Ne için bekliyorsun? (Mahjong çözücü)


14

@ MartinBüttner'e sohbet tartışması sayesinde fikir

Mahjong , Asya'da son derece popüler olan bir çini oyunudur. Genellikle dört oyuncu ile oynanır ve oyunun amacı fayansları kullanarak geçerli bir eli tamamlayan ilk kişi olmaktır. Bu meydan okuma için, oyunun basitleştirilmiş bir versiyonunu ele alacağız - PPCG mahjong.

- PPCG mahjongda üç takım elbise vardır m, pve s- ve fayans numaralandirilmistir 1için 9. Orada her karo dört kopyası aynen vardır ve fayans onun takım tarafından takip onun numarası (örn ile gösterilir 3m, 9s).

Tamamlanmış bir PPCG mahjong eli, toplam 14 karo için üç set ve bir çiftten oluşur.

Üçlü bir dizi şunlardan biri olabilir:

  • Aynı döşemeden üçü (örneğin 4s 4s 4s, ancak değil 4m 4p 4s) veya
  • Aynı türden üç ardışık döşemeden oluşan bir dizi (örneğin, 1s 2s 3sya da 6p 7p 8pdeğil 3s 4m 5mveya 3p 5p 7p). Diziler sarılmaz ( 9m 1m 2mgeçersizdir).

Bir çift basitçe iki özdeş döşemedir (örneğin 5s 5s).

Meydan okuma

Programınız her biri dört kereden fazla görünmeyecek şekilde, 13 döşemeden oluşan bir boşluk elde eder. Tam bir program veya bir dize alan bir işlev yazabilirsiniz.

Senin görevin, el eklendiğinde tamamlanmış bir PPCG mahjong eli oluşturacak olası tüm 14 karoları ("bekler") bulmaktır. Çıkarılan döşemeler boşlukla ayrılmalıdır, ancak herhangi bir sırada olabilir. Öncü veya sondaki boşluklara izin verilir.

Programınız bir dakikadan fazla olmamak üzere makul bir sürede çalışmalıdır.

Örnekler

Input: 1m 1m 1m 4s 4s 4s 7p 7p 7p 3m 3m 3m 9s
Output: 9s

Input: 1m 1m 1m 3m 3m 3m 5m 5m 5m 2s 3s 7p 8p
Output:

Input: 1m 2m 2m 3m 3m 3m 3m 4m 1s 1s 9s 9s 9s
Output: 1s

Input: 1m 1m 1m 2m 3m 4m 5m 6m 7m 8m 9m 9m 9m
Output: 1m 2m 3m 4m 5m 6m 7m 8m 9m

Input: 1m 1m 1m 5p 2m 3m 5p 7s 8s 5p 9s 9s 9s
Output: 1m 4m 6s 9s 

İlk örnekte, 1m 4s 7p 3mhepsi mevcut üçlüleri oluşturur ve yalnız 9sbir çift oluşturur.

İkinci örnekte, 2s 3sve 7p 8pyalnızca diziler oluşturabilir ve geri kalan döşemeler yalnızca üçüz oluşturabilir. Dolayısıyla hiçbir çift oluşturulamaz ve çıktı yoktur.

Üçüncü örnekte, el bölünür 1m2m3m 2m3m4m 3m3m 1s1s 9s9s9s. Normalde bu bir bekleme olur 3m 1s, ancak dördünün 3mhepsi kullanıldığından, mevcut tek bekleme 1s.

Dördüncü örnekte, tüm mkarolar eli tamamlar. Örneğin 1m, biri 1m1m1m 1m2m3m 4m5m6m 7m8m9m 9m9mtamamlanmış bir ele sahip olabilir .

Dördüncü örneğin beşinci örneğini anlamaya çalışın :)

puanlama

Bu , bu yüzden en az bayt içindeki çözüm kazanır. Standart boşluklar geçerlidir.


9
Batılıların "Mahjong" kelimesini duyduklarında düşünecekleri karoları kullanarak (IMO sinir bozucu) solitaire yerine aslında Mahjong yaptığınız için teşekkür ederiz.
Justin

@Quincunx Eğlenceli gerçek: Bu zorluk, Mahjong solitaire'in ASCII temsili ile bir meydan okuma yapmak istediğim için ortaya çıktı (ki hala bir noktada yapabilirim ...). Ben buna "Mahjong solitaire" diyorum. ;)
Martin Ender

2
@Quincunx: Bunun onların hatası olduğunu sanmıyorum. Oyun geliştiricilerinin "Mahjong solitaire" oyunlarını "Mahjong" ve başka bir şey olarak adlandırmama hatası.
Joe Z.20

Yedi çift ne olacak? on üç yetim mi? onurlarla daha da karmaşık bir şey yapabilirsiniz :) Bir elin shantını ( tenpai - kazanmaya hazır olmadan önce gereken minimum karo sayısı) hesaplamasını isteyen bir codegolf oluşturmamın amaç dışı olduğunu düşünüyor musunuz ?
V. Courtois

@VCourtois Bir süre oldu, ama özellikle yedi çift, on üç yetim, onur ve özel olarak, oyuna yeni gelen insanlar için zorluğu aşırı karmaşıklaştırmamak için çağrılar yapmayı hatırlıyorum. Sanırım bundan sonra shanten bir meydan okuma yapmayı düşündüm ama sonunda hiç yapmadım - eğer bir tane göndermek istersen iyi bir meydan okuma olacağını düşünüyorum.
Sp3000

Yanıtlar:


4

Python, 312 281 bayt

def W(S):H=lambda C,n=0,t=1:sum([m<C[0]and H([c-s for c in C][:l]+C[l:],n+1,u)for m,s,l,u in(2,3,1,t),(t,2,1,4),(4-5*all(C[:3]),1,3,t)])|H(C[1:],n,t)if C[2:]and max(C)<5else n>4;T=[i+s for s in"mps"for i in"12345678900"];return" ".join(t for t in T if("1"<t)*H(map((S+t).count,T)))

W bir dizeyi girdi olarak alır ve bir dizeyi çıktı olarak döndürür.

Az sayıda karo (27), her birinin eli tamamlayıp tamamlamadığını test etmek için yeterince hızlı hale getirir. Sorun, bir elin geçerli olup olmadığını kontrol etmek olur. İşlev, tüm olası set seçeneklerini dikkate alan basit bir geri izleme algoritması kullanır ve bunlardan herhangi birinin tam bir ele eklenip eklenmediğini kontrol eder.

Eller karo histogramları olarak temsil edilir, yani karo sayımlarının bir listesi (sadece eldeki mevcut karolar için değil, tüm karolar için.) Bu, her ikisinin belirli bir karonun olup olmadığını kontrol etmeyi kolaylaştırır ve bitişik karoların bir sırasına sahip olmak (farklı takımların karoları arasında dolgu çok takımlı dizileri önler.)


Ah, beni mapH(map((S+t).count,T))
dövüyorsun

@FryAmTheEggman Bunu kaçırdı. Teşekkürler!
Ell

@ Sp3000 Python 2. Bu çok garip; 2.7.8 benim için iyi çalışıyor.
Ell

@ 2.7.8 - 2.7.5'teki tüm işler 5seğeni beğenmedi: P
Sp3000

2

JavaScript (E6) 306

F=h=>(
  R=(a,p,n=1)=>(a=[...a]).splice(p,n)&&a,
  K=(t,d=3)=>
    !t[0]
    |t.some(
      (v,p)=>
        v==t[p+1]&v==t[p+d-1]&&
        K(R(t,p,d))
      ||
        ~((r=t.indexOf((x=-~v[0])+v[1]))|(s=t.indexOf(-~x+v[1])))&&
        K(R(R(R(t,s),r),p))
    ),
  o=[],
  [for(s of'mps')for(i of'123456789')h.replace(t=i+s,s,'g')[34]
  &&K([t,...h.split(' ')].sort(),2)&&o.push(t)
  ],o
)

Açıklaması

F=hand=>(
  Remove=(a,p,n=1)=>                // function to remove 1 or more element from an array, returning a new shorter array
    ((a=[...a]).splice(p,n), a),    // using array.splice on a new created array 

  Check=(ckHand, dim)=>  // recursive function to check hand. 
                         // removing pairs (at iteration 0) or sequence of three, if at last the hand remain empty then success
                         // parameter dim is 2 or 3 indicating how many equal elements are to be removed
    !ckHand[0]           // check if empty (element 0 does not exist)
    |ckHand.some(        // else traverse all array checking what can be removed
      (value, position)=> 
        value == ckHand[position + 1] 
        & value == ckHand[position + dim-1] &&   // look for 3 (or 2) equal elements
        Check(Remove(ckHand, position, dim), 3)   // if found, then remove elements and check again
      ||
        ~((r = ckHand.indexOf((x=-~value[0]) + value[1]))     // value[0] is number, value[1] is suit 
        |(s = ckHand.indexOf(-~x + value[1]))) &&              // look for an ascending sequence in following elements (the array is sorted)
        Check(Remove(Remove(Remove(ckHand, s), r), position),3) // if sequence found, remove elements and check again
    ),
  output=[], // start with an empty solution list
  [ // using array comprehension to implement a double loop
    for(s of'mps')        // loop for all suits
    for(i of'123456789')  // loop for all numbers
    (
       tile=i+s, // current tile 
       (hand.replace(tile,' ','g').length > 34)      // if tile is present 4 times in hand, the replaced length is 38-4 == 34
       && (                                       // else proceed with check
         ckHand = hand.split(' '), 
         ckHand.push(tile),    // in ckHand (as an array) the hand to be checked, that is base hand + current tile
         ckHand.sort(),        // sorting the array simplfy the checks
         Check(ckHand, 2)      // start checks looking for a pair
       )
       && 
         output.push(tile)   // if check ok, add tile to the solution list
    )   
  ],
  output // last expression in list is the function return value 
)

FireFox / FireBug konsolunda test

;["1m 1m 1m 4s 4s 4s 7p 7p 7p 3m 3m 3m 9s", "1m 1m 1m 3m 3m 3m 5m 5m 5m 2s 3s 7p 8p",
 "1m 2m 2m 3m 3m 3m 3m 4m 1s 1s 9s 9s 9s", "1m 1m 1m 2m 3m 4m 5m 6m 7m 8m 9m 9m 9m",
 "1m 1m 1m 5p 2m 3m 5p 7s 8s 5p 9s 9s 9s"].forEach(s=>console.log(s+' => '+F(s)))

Çıktı

1m 1m 1m 4s 4s 4s 7p 7p 7p 3m 3m 3m 9s => 9s
1m 1m 1m 3m 3m 3m 5m 5m 5m 2s 3s 7p 8p =>
1m 2m 2m 3m 3m 3m 3m 4m 1s 1s 9s 9s 9s => 1s
1m 1m 1m 2m 3m 4m 5m 6m 7m 8m 9m 9m 9m => 1m,2m,3m,4m,5m,6m,7m,8m,9m
1m 1m 1m 5p 2m 3m 5p 7s 8s 5p 9s 9s 9s => 1m,4m,6s,9s
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.