Apa yang kamu tunggu? (Seorang pemecah mahjong)

14

Ide terima kasih kepada @ MartinBüttner dari diskusi dalam obrolan

Mahjong adalah gim ubin yang sangat populer di Asia. Biasanya dimainkan dengan empat pemain, dan tujuan permainan ini adalah menjadi orang pertama yang menyelesaikan kartu yang sah menggunakan ubin. Untuk tantangan ini, kami akan mempertimbangkan versi gim yang disederhanakan - PPCG mahjong.

Di PPCG mahjong, ada tiga setelan - m, pdan s- dan ubin dinomori dari 1ke 9. Tepatnya ada empat salinan dari setiap ubin, dan ubin ditandai dengan nomornya diikuti dengan setelannya (misalnya 3m, 9s).

Tangan mahjong PPCG yang lengkap terdiri dari empat set tiga dan sepasang, dengan total 14 ubin.

Seperangkat tiga dapat berupa:

  • Tiga ubin yang sama (misalnya 4s 4s 4s, tetapi tidak 4m 4p 4s), atau
  • Urutan tiga ubin berturut-turut dalam setelan yang sama (misalnya 1s 2s 3satau 6p 7p 8ptetapi tidak 3s 4m 5matau 3p 5p 7p). Urutan tidak terbungkus (jadi 9m 1m 2mtidak valid).

Sepasang hanyalah dua ubin yang identik (misalnya 5s 5s).

Tantangan

Program Anda akan menerima 13 ubin yang dipisahkan oleh ruang, dengan setiap ubin muncul tidak lebih dari empat kali. Anda dapat menulis program lengkap atau fungsi yang mengambil string.

Tugas Anda adalah menemukan semua ubin ke-14 yang mungkin ("menunggu") yang, ketika ditambahkan ke tangan, akan membentuk tangan mahjong PPCG yang lengkap. Ubin yang dikeluarkan harus dipisahkan dengan ruang, tetapi dapat dalam urutan apa pun. Ruang putih terkemuka atau tertinggal diizinkan.

Program Anda harus berjalan dalam jumlah waktu yang wajar, tidak lebih dari satu menit.

Contohnya

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 

Pada contoh pertama, 1m 4s 7p 3msemua membentuk kembar tiga yang ada, meninggalkan satu-satunya 9suntuk membentuk pasangan.

Pada contoh kedua, 2s 3sdan 7p 8phanya dapat membentuk urutan, dan ubin yang tersisa hanya dapat membentuk kembar tiga. Karenanya tidak ada pasangan yang dapat dibentuk, dan tidak ada output.

Pada contoh ketiga, tangan terbagi menjadi 1m2m3m 2m3m4m 3m3m 1s1s 9s9s9s. Biasanya ini menunggu 3m 1s, tetapi karena keempat 3mtelah digunakan, satu-satunya menunggu yang tersedia 1s.

Pada contoh keempat, semua mubin melengkapi tangan. Misalnya, untuk 1m, seseorang dapat memiliki tangan 1m1m1m 1m2m3m 4m5m6m 7m8m9m 9m9myang sudah selesai.

Cobalah untuk mengerjakan sisa contoh keempat dan contoh kelima :)

Mencetak gol

Ini adalah , sehingga solusi dalam byte paling sedikit menang. Celah standar berlaku.

Sp3000
sumber
9
Terima kasih telah benar-benar melakukan Mahjong, daripada solitaire (mengganggu IMO) menggunakan ubin yang tampaknya dipikirkan orang Barat setiap kali mereka mendengar kata "Mahjong".
Justin
@Quincunx Fakta menyenangkan: Tantangan ini muncul karena saya ingin melakukan tantangan dengan representasi ASCII dari Mahjong solitaire (yang mungkin masih saya lakukan di beberapa titik ...). Saya memang menyebutnya "Mahjong solitaire". ;)
Martin Ender
2
@ Quincunx: Saya tidak berpikir itu salah mereka. Ini kesalahan pengembang game karena menyebut game "Mahjong solitaire" mereka "Mahjong" dan tidak ada yang lain.
Joe Z.
Bagaimana dengan tujuh pasang? tiga belas anak yatim? Anda bisa melakukan sesuatu yang lebih kompleks dengan pujian :) Apakah Anda pikir itu tidak sengaja jika saya membuat codegolf yang meminta untuk menghitung shanten (jumlah minimal ubin yang diperlukan sebelum mendapatkan tenpai - siap untuk menang) dari sebuah tangan?
V. Courtois
@ PVCourtois Sudah lama, tapi saya ingat secara khusus mengecualikan tujuh pasangan, tiga belas anak yatim, penghargaan dan sudah menelepon agar tidak terlalu rumit tantangan bagi orang-orang yang baru dalam permainan. Saya pikir saya mempertimbangkan untuk membuat tantangan shanten nanti setelah itu tetapi tidak pernah melakukannya pada akhirnya - jika Anda ingin mempostingnya saya pikir itu akan membuat tantangan yang bagus.
Sp3000

Jawaban:

4

Python, 312 281 byte

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 mengambil string sebagai input dan mengembalikan string sebagai output.

Sejumlah kecil ubin (27) membuatnya cukup cepat untuk menguji apakah masing-masing menyelesaikan tangan. Masalahnya menjadi untuk memeriksa apakah sebuah tangan valid. Fungsi ini menggunakan algoritma backtracking sederhana yang mempertimbangkan semua pilihan set yang mungkin dan memeriksa apakah ada di antara mereka yang menambahkan ke tangan yang lengkap.

Tangan direpresentasikan sebagai histogram ubin, yaitu daftar jumlah ubin (untuk semua ubin, tidak hanya yang ada di tangan.) Ini memudahkan untuk memeriksa apakah kita memiliki jumlah tertentu ubin tertentu, dan jika kita memiliki urutan ubin yang berdekatan (bantalan di antara ubin setelan yang berbeda mencegah urutan multi-setelan.)

Elo
sumber
Ah, Anda mengalahkan saya: P Ngomong-ngomong, sepertinya Anda dapat menggunakannya mapdi beberapa tempat, seperti:H(map((S+t).count,T))
FryAmTheEggman
@FryAmTheEggman melewatkannya. Terima kasih!
Ell
@ Sp3000 Ini Python 2. Itu aneh; itu berfungsi dengan baik untuk saya di 2.7.8.
Ell
@Ell Bekerja di 2.7.8 - 2.7.5 tidak menyukai 5else: 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
)

Dijelaskan

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 
)

Uji di konsol FireFox / FireBug

;["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)))

Keluaran

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
edc65
sumber