คุณกำลังรออะไรอยู่? (แก้ปัญหาไพ่นกกระจอก)


14

ขอบคุณไอเดียที่ @ MartinBüttnerจากการสนทนาในแชท

Mahjongเป็นเกมไพ่ที่ได้รับความนิยมอย่างมากในเอเชีย โดยทั่วไปจะเล่นกับผู้เล่นสี่คนและเป้าหมายของเกมคือการเป็นคนแรกที่เล่นไพ่ที่ถูกต้องโดยใช้มือ สำหรับความท้าทายนี้เราจะพิจารณาเกมที่เรียบง่าย - PPCG ไพ่นกกระจอก

ใน PPCG ไพ่นกกระจอก, มีสามชุด - m, pและs- และกระเบื้องที่มีเลขจากไป1 9มีสี่สำเนาของไพ่แต่ละใบและไพ่จะถูกแทนด้วยหมายเลขตามด้วยชุดไพ่ (เช่น3m, 9s)

ไพ่นกกระจอก PPCG ที่เสร็จสมบูรณ์แล้วประกอบด้วยสี่ชุดสามชุดและคู่รวมเป็น 14 แผ่น

ชุดของสามสามารถเป็นได้ทั้ง:

  • ไพ่สามใบเดียวกัน (เช่น4s 4s 4sแต่ไม่ใช่4m 4p 4s) หรือ
  • ลำดับของไพ่สามติดต่อกันในชุดเดียวกัน (เช่น1s 2s 3sหรือ6p 7p 8pแต่ไม่3s 4m 5mหรือ3p 5p 7p) ลำดับไม่ห่อ (ดังนั้นจึง9m 1m 2mไม่ถูกต้อง)

คู่คือไพ่สองใบที่เหมือนกัน (เช่น5s 5s)

ความท้าทาย

โปรแกรมของคุณจะได้รับไพ่ 13 ใบแยกด้วยกันโดยที่แต่ละแผ่นมีไม่เกินสี่ครั้ง คุณสามารถเขียนโปรแกรมเต็มหรือฟังก์ชั่นที่ใช้ในสตริง

งานของคุณคือการหาไพ่ที่ 14 ที่เป็นไปได้ทั้งหมด ("รอ") ซึ่งเมื่อเพิ่มลงในมือจะกลายเป็นไพ่นกกระจอก PPCG ที่เสร็จสมบูรณ์ ไทล์เอาท์พุทควรคั่นด้วยช่องว่าง แต่สามารถอยู่ในลำดับใดก็ได้ อนุญาตช่องว่างนำหน้าหรือต่อท้าย

โปรแกรมของคุณควรทำงานในเวลาที่เหมาะสมไม่เกินหนึ่งนาที

ตัวอย่าง

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 

ในตัวอย่างแรก1m 4s 7p 3mรูปแบบทั้งหมดที่มีอยู่สามเท่าปล่อยให้อยู่คนเดียว9sในรูปแบบคู่

ในตัวอย่างที่สอง, 2s 3sและ7p 8pสามารถสร้างได้เฉพาะซีเควนซ์และไทล์ที่เหลือสามารถสร้างแบบสามส่วนได้เท่านั้น ดังนั้นจึงไม่มีคู่ใดสามารถเกิดขึ้นได้และไม่มีผลลัพธ์

1m2m3m 2m3m4m 3m3m 1s1s 9s9s9sในตัวอย่างที่สามมือแยกออกเป็น ปกตินี้จะรอ3m 1sแต่เป็นทั้งสี่ได้ถูกนำมาใช้ในการรอคอยที่มีอยู่เพียงอย่างเดียวคือ3m1s

ในตัวอย่างที่สี่mไพ่ทั้งหมดทำมือให้เสร็จ ตัวอย่างเช่นสำหรับ1mหนึ่งอาจมี1m1m1m 1m2m3m 4m5m6m 7m8m9m 9m9mซึ่งเป็นมือที่สมบูรณ์

ลองหาตัวอย่างที่เหลือจากตัวอย่างที่สี่และตัวอย่างที่ห้า :)

เกณฑ์การให้คะแนน

นี่คือดังนั้นวิธีการแก้ปัญหาในไบต์ที่น้อยที่สุดชนะ ช่องโหว่มาตรฐานใช้


9
ขอขอบคุณที่ทำเกมไพ่นกกระจอกแทนที่จะเล่นไพ่คนเดียว (น่ารำคาญ IMO) โดยใช้แผ่นกระเบื้องที่ชาวตะวันตกดูเหมือนจะนึกถึงเมื่อใดก็ตามที่พวกเขาได้ยินคำว่า "ไพ่นกกระจอก"
Justin

@Quincunx ความจริงเรื่องสนุก: ความท้าทายนี้เกิดขึ้นเพราะฉันต้องการทำสิ่งท้าทายด้วยการเป็นตัวแทน ASCII ของเกมไพ่นกกระจอก (ซึ่งฉันอาจยังคงทำในบางจุด ... ) ฉันเรียกมันว่า "ไพ่นกกระจอก" ;)
Martin Ender

2
@Quincunx: ฉันไม่คิดว่ามันเป็นความผิดของพวกเขา มันเป็นความผิดของผู้พัฒนาเกมในการเรียก "ไพ่นกกระจอก" เกม "ไพ่นกกระจอก" ของพวกเขาและไม่มีอะไรอื่น
Joe Z.

ประมาณเจ็ดคู่ล่ะ เด็กกำพร้าสิบสามคน? คุณสามารถทำอะไรที่ซับซ้อนยิ่งขึ้นด้วยเกียรตินิยม :) คุณคิดว่ามันผิดวัตถุประสงค์หรือไม่ถ้าฉันสร้าง codegolf ที่ขอให้คำนวณshanten (จำนวนไพ่น้อยที่สุดที่จำเป็นก่อนที่จะรับtenpai - พร้อมที่จะชนะ) ของมือหรือไม่?
V. Courtois

@VCourtois นานแล้ว แต่ฉันจำได้ดีว่าไม่รวมเจ็ดคู่เด็กกำพร้าสิบสามคนเกียรติและได้รับโทรศัพท์แล้วเพื่อที่จะไม่เน้นความท้าทายสำหรับผู้ที่เพิ่งเริ่มเล่นเกม ฉันคิดว่าฉันคิดว่าจะทำการท้าทายแบบ shanten ในภายหลังหลังจากนั้น แต่ก็ไม่เคยทำในท้ายที่สุด - หากคุณต้องการโพสต์สิ่งที่ฉันคิดว่ามันเป็นการท้าทายที่ดี
Sp3000

คำตอบ:


4

งูหลาม 312 281 ไบต์

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 รับสตริงเป็นอินพุตและส่งคืนสตริงเป็นเอาต์พุต

จำนวนไพ่น้อย ๆ (27) ทำให้เร็วพอที่จะทดสอบว่าไพ่แต่ละไพ่นั้นเสร็จสมบูรณ์หรือไม่ ปัญหาจะเกิดขึ้นเพื่อตรวจสอบว่ามือถูกต้องหรือไม่ ฟังก์ชั่นนี้ใช้อัลกอริทึมการย้อนรอยง่าย ๆ ซึ่งพิจารณาตัวเลือกที่เป็นไปได้ทั้งหมดของชุดและตรวจสอบว่ามีสิ่งใดที่เพิ่มเข้ามาในมือ

มือแสดงเป็นไพ่ฮิสโทแกรมเช่นรายการของจำนวนไพ่ (สำหรับไพ่ทั้งหมดไม่ใช่เฉพาะไพ่ที่มีอยู่ในมือ) สิ่งนี้ทำให้ง่ายต่อการตรวจสอบว่าเรามีไพ่จำนวนหนึ่งหรือไม่และถ้าเรา มีลำดับของไพ่ที่อยู่ติดกัน (padding ระหว่างไพ่ของชุดที่แตกต่างกันป้องกันลำดับที่มีหลายชุด)


อ่าคุณชนะฉัน: P อย่างไรก็ตามดูเหมือนว่าคุณสามารถใช้mapในสองสถานที่เช่น:H(map((S+t).count,T))
FryAmTheEggman

@FryAmTheEggman พลาดไปแล้ว ขอบคุณ!
Ell

@ Sp3000 มันคือ Python 2 มันแปลกนะ มันใช้งานได้ดีสำหรับฉันใน 2.7.8
Ell

@Ell ทำงานใน 2.7.8 - 2.7.5 ไม่ชอบ 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
)

อธิบาย

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

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

เอาท์พุต

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.