ฉันสามารถกวาดทุ่นระเบิดได้ไหม?


29

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

1110
2*31
3*??
2*4?
112?

ในรูปแบบนี้ตัวเลขหมายถึงจำนวนเหมืองที่อยู่ติดกันและเป็น*ตัวแทนของเหมืองที่รู้จักและ "?" แสดงถึงเหมืองที่มีศักยภาพ อัปมงคลเกี่ยวกับปริศนานี้โดยเฉพาะอย่างยิ่งก็คือว่ามีสี่ที่แตกต่างและถูกต้องแก้ปัญหาที่อาจเกิดขึ้น:

1110    1110    1110    1110    
2*31    2*31    2*31    2*31
3*4*    3*5*    3**2    3**1
2*42    2*4*    2*4*    2*42
112*    1121    1121    112*

หมายความว่าบอร์ดไม่สามารถแก้ไขได้ นี่คือตัวอย่างของบอร์ดที่แก้ไขได้ :

1121
1??*
12?*
0122

บอร์ดนี้แก้ไขได้เนื่องจากมีวิธีแก้ปัญหาที่ใช้ได้เพียงวิธีเดียวเท่านั้น

1121
1*4*
12**
0122

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

อินพุตของคุณอาจเป็นอาร์เรย์ของอักขระอาร์เรย์ของสตริงสตริงที่มีการขึ้นบรรทัดใหม่ ฯลฯ ผลลัพธ์จะต้องเป็นค่าจริงหากมีการแก้ไขและค่าเท็จถ้าไม่ ผมไม่ได้กังวลอย่างมากเกี่ยวกับผลการดำเนินงาน แต่วิธีการแก้ปัญหาของคุณจะต้องในทางทฤษฎีการทำงานสำหรับการป้อนข้อมูลที่มีขนาดใด

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

ตัวอย่าง:

ตัวอย่างต่อไปนี้สามารถแก้ไขได้ทั้งหมด:

1121
1??*
12?*
0122

1110
1???
1110
0000

1110
3???
??20
*310

****
****
****
****

0000
0000
0000
0000

1100
*100
2321
??*2
13*2
1221
1*10
1110

1121
2*??
2*31
2220
1*10

ตัวอย่างต่อไปนี้ไม่สามารถแก้ไขได้ทั้งหมด:

1110
2*31
3*??
2*4?
112?

01??11*211
12??2323*1
1*33*2*210
12?2122321
13?3101**1
1***101221

1***
3*52
2*31
12??
02??
01??

00000111
000012*1
00001*21
22101110
**100111
?31123*1
?311**31
**113*20

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

2
ไม่มีอะไรที่คุ้มค่าที่ใน MineSweeper คุณมีข้อมูลเพิ่มเติมที่นี่หายไป: จำนวนเหมือง
edc65

@Mathmandan ใช่อินพุตจะเป็นรูปสี่เหลี่ยมผืนผ้าที่มีเซลล์อย่างน้อยหนึ่งเซลล์และโซลูชันที่ถูกต้องอย่างน้อยหนึ่งรายการเสมอ
DJMcMayhem

คำตอบ:


20

GNU Prolog ขนาด 493 ไบต์

z(_,[_,_]).
z(F,[A,B,C|T]):-call(F,A,B,C),z(F,[B,C|T]).
i([],[],[],[]).
i([H|A],[I|B],[J|C],[H-I-J|T]):-i(A,B,C,T).
c(A/_-B/_-C/_,D/_-_/T-E/_,F/_-G/_-H/_):-T#=A+B+C+D+E+F+G+H.
r(A,B,C):-i(A,B,C,L),z(c,L).
q(63,V):-var(V).
q(42,1/_).
q(X,0/Y):-Y#=X-48.
l([],[0/_]).
l([H|T],[E|U]):-q(H,E),l(T,U).
p([],[[0/_,0/_]],0).
p([],[[0/_|T]],N):-M#=N-1,p([],[T],M).
p([H|T],[[0/_|E]|U],N):-p(T,U,N),l(H,E).
m([H|A],B):-length(H,N),p([],[R],N),p([H|A],M,N),z(r,[R|M]),p(B,M,N).
s(A):-setof(B,m(A,B),[_]).

เพรดิเคตพิเศษที่อาจเป็นประโยชน์สำหรับการทดสอบ (ไม่ใช่ส่วนหนึ่งของการส่ง):

d([]).
d([H|T]):-format("~s~n",[H]),d(T).

ภาษาโปรล็อกเป็นภาษาที่เหมาะสมสำหรับการแก้ไขงานนี้จากมุมมองของภาคปฏิบัติ โปรแกรมนี้บอกกฎของเรือกวาดทุ่นระเบิดและช่วยให้นักแก้ไขข้อ จำกัด ของ GNU Prolog แก้ปัญหาจากตรงนั้น

zและiเป็นฟังก์ชั่นยูทิลิตี้ ( zจะเรียงลำดับของการดำเนินการเหมือนพับ แต่ในชุดของสามองค์ประกอบที่อยู่ติดกันมากกว่า 2; itransposes 3 รายการขององค์ประกอบnเข้าไปในรายการของn -3 tuples) เราเก็บเซลล์ไว้ภายในโดยที่xคือ 1 สำหรับเหมืองและ 0 สำหรับ nonmine และyคือจำนวนเหมืองที่อยู่ติดกัน เป็นการแสดงออกถึงข้อ จำกัด นี้บนกระดาน ใช้ได้กับทุกแถวของกระดาน และตรวจสอบเพื่อดูว่าเป็นคณะกรรมการที่ถูกต้องx/ycrcz(r,M)M

น่าเสียดายที่รูปแบบการป้อนข้อมูลที่จำเป็นในการทำให้งานนี้โดยตรงไม่มีเหตุผลดังนั้นฉันจึงต้องรวมตัวแยกวิเคราะห์ (ซึ่งอาจเป็นรหัสสำหรับรหัสมากกว่าเครื่องมือกฎจริงและใช้เวลาในการดีบั๊กส่วนใหญ่) เครื่องมือกฎของเรือกวาดทุ่นระเบิดทำงานค่อนข้างมาก ครั้งแรก แต่ตัวแยกวิเคราะห์เต็มไปด้วย thinkos) qแปลงเซลล์เดียวระหว่างรหัสอักขระและรูปแบบของเรา แปลงหนึ่งบรรทัดของบอร์ด (ปล่อยให้เซลล์หนึ่งที่รู้ว่าไม่ใช่ของฉัน แต่มีจำนวนเหมืองใกล้เคียงที่ไม่รู้จักที่ขอบแต่ละบรรทัดเป็นขอบ);x/ylpแปลงบอร์ดทั้งหมด (รวมถึงขอบด้านล่าง แต่ไม่รวมบอร์ดด้านบน) ฟังก์ชั่นเหล่านี้ทั้งหมดสามารถเรียกใช้ไปข้างหน้าหรือข้างหลังดังนั้นจึงสามารถแยกวิเคราะห์และพิมพ์บอร์ดสวยได้ (มีการแกว่งไปมาที่น่ารำคาญกับอาร์กิวเมนต์ที่สามไปpซึ่งระบุความกว้างของบอร์ดนั่นเป็นเพราะ Prolog ไม่มีประเภทเมทริกซ์และถ้าฉันไม่ จำกัด บอร์ดให้เป็นสี่เหลี่ยมโปรแกรมจะเข้าสู่ การวนซ้ำไม่สิ้นสุดที่พยายามทำให้เส้นขอบที่กว้างขึ้นรอบ ๆ กระดานมีความก้าวหน้า)

mเป็นฟังก์ชั่นการแก้ปัญหาเรือกวาดทุ่นระเบิดหลัก มันแยกวิเคราะห์สตริงอินพุตสร้างบอร์ดที่มีเส้นขอบที่ถูกต้อง (ผ่านการใช้เคสซ้ำของpการแปลงบอร์ดส่วนใหญ่จากนั้นเรียกเคสฐานโดยตรงเพื่อสร้างเส้นขอบด้านบนซึ่งมีโครงสร้างเดียวกันกับขอบด้านล่าง) จากนั้นจะโทรz(r,[R|M])เพื่อรันเครื่องมือกฎ Minesweeper ซึ่ง (ด้วยรูปแบบการโทรนี้) กลายเป็นเครื่องกำเนิดไฟฟ้าที่สร้างบอร์ดที่ถูกต้องเท่านั้น ณ จุดนี้บอร์ดยังคงแสดงถึงข้อ จำกัด ซึ่งอาจทำให้เราอึดอัดใจ บางทีเราอาจมีข้อ จำกัด เพียงชุดเดียวซึ่งอาจเป็นตัวแทนของคณะกรรมการมากกว่าหนึ่งคณะ นอกจากนี้เรายังไม่ได้ระบุที่ใดก็ได้ที่แต่ละช่องมีไม่เกินหนึ่งเหมือง ด้วยเหตุนี้เราต้อง "ยุบรูปคลื่น" ของแต่ละช่องอย่างชัดเจนโดยกำหนดให้เป็นเฉพาะ (เหมือง) หรือเหมืองแร่และวิธีที่ง่ายที่สุดในการทำเช่นนี้คือเรียกใช้ผ่านตัวแยกวิเคราะห์ย้อนกลับ ( var(V)บนq(63,V)เคสได้รับการออกแบบมาเพื่อป้องกันไม่ให้?เคสวิ่งถอยหลัง ในที่สุดเราก็ส่งคืนกระดานแยกวิเคราะห์จากm; mจึงกลายเป็นตัวกำเนิดซึ่งใช้บอร์ดที่ไม่รู้จักบางส่วนและสร้างบอร์ดที่รู้จักทั้งหมดที่สอดคล้องกับมัน

มันเพียงพอที่จะแก้ปัญหาเรือกวาดทุ่นระเบิด แต่คำถามที่ถามอย่างชัดเจนเพื่อตรวจสอบว่ามีวิธีการแก้ปัญหาอย่างใดอย่างหนึ่งมากกว่าที่จะหาทางออกทั้งหมด เช่นนี้ฉันเขียนภาคแสดงพิเศษsซึ่งเพียงแปลงตัวกำเนิดmเป็นชุดจากนั้นยืนยันว่าชุดนั้นมีองค์ประกอบเดียว ซึ่งหมายความว่าsจะส่งคืนความจริง ( yes) หากมีวิธีแก้ปัญหาอย่างแน่นอนหรือเท็จ ( no) หากมีมากกว่าหนึ่งหรือน้อยกว่าหนึ่ง

dไม่ได้เป็นส่วนหนึ่งของโซลูชันและไม่รวมอยู่ใน bytecount มันเป็นฟังก์ชั่นสำหรับการพิมพ์รายการของสตริงราวกับว่ามันเป็นเมทริกซ์ซึ่งทำให้สามารถตรวจสอบบอร์ดที่สร้างโดยm(ตามค่าเริ่มต้น GNU Prolog พิมพ์สตริงเป็นรายการของรหัส ASCII เพราะปฏิบัติกับทั้งสองเหมือนกันรูปแบบนี้ อ่านยาก) มันมีประโยชน์ในระหว่างการทดสอบหรือถ้าคุณต้องการใช้mเป็นนักแก้ปัญหาเรือกวาดทุ่นระเบิดในทางปฏิบัติ (เพราะใช้ตัวแก้ข้อ จำกัด มันมีประสิทธิภาพสูง)


11

Haskell, 193 169 168 ไบต์

c '?'="*!"
c x=[x]
g x|t<-x>>" ",w<-length(words x!!0)+1=1==sum[1|p<-mapM c$t++x++t,and[sum[1|m<-[-1..1],n<-[j-w,j,j+w],p!!(m+n)=='*']==read[d]|(j,d)<-zip[0..]p,d>'/']]

ตัวอย่างการใช้งาน: ->g "1121 1??* 12?* 0122"True

มันทำงานอย่างไร: ทำรายการของบอร์ดที่เป็นไปได้ทั้งหมด?โดยแทนที่ด้วย*หรือ!( !หมายถึงไม่สนใจในภายหลัง) สิ่งนี้ทำผ่านmapM cแต่ก่อนที่เราจะเพิ่มและผนวกช่องว่างเข้ากับสตริงอินพุตเพื่อให้การจัดทำดัชนีของเราไม่อยู่ในช่วงที่กำหนด สำหรับการตรวจสอบแต่ละคณะกรรมการดังกล่าวว่าจะเป็นคณะกรรมการที่ถูกต้องโดยการวนลูปกับองค์ประกอบทั้งหมด (ดัชนีj) และถ้าหากมันเป็นตัวเลข ( d>'/') นอกจากนี้ยังมากกว่าประเทศเพื่อนบ้าน (ดัชนีn, m) นับ*และเปรียบเทียบกับจำนวน ในที่สุดตรวจสอบความยาวของรายการของบอร์ดที่ถูกต้อง


7

Mathematica, 214 192 190 180 176 174 168 165 ไบต์

0&/@Cases[b="*";If[!FreeQ[#,q="?"],(x#0@MapAt[x&,#,#&@@#~Position~q])/@{b,0},BlockMap[If[#[[2,2]]==b,b,Count[#,b,2]]&,#~ArrayPad~1,{3,3},1]]&@#,#/.q->_,All]=={0}&

มี U + F4A1 (ใช้ส่วนตัว) ฟังก์ชันที่ไม่มีชื่อนี้จะค้นหาชุดค่าผสมที่เป็นไปได้ทั้งหมดสำหรับ"?"(เช่นแทนที่ค่าทั้งหมด"?"ด้วย"*"หรือ0) และตรวจสอบว่ามีโซลูชันที่ถูกต้องเพียงโซลูชันเดียวเท่านั้นหรือไม่

คำอธิบาย

b="*";

ตั้งค่าการb"*"

!FreeQ[#,q="?"]

ตั้งสตริงq "?"ตรวจสอบว่ามีอยู่"?"ในอินพุต

If[ ..., (x#0 ... ,0}, BlockMap[ ... ]]

ถ้าTrue...

(x#0@MapAt[x&,#,#&@@#~Position~q])/@{b,0}

แทนที่การเกิดขึ้นครั้งแรกของq(= "?") ด้วยb(= "*") หรือ0(เช่นสองเอาต์พุต) และใช้ฟังก์ชันทั้งหมดอีกครั้ง


ถ้าFalse...

#~ArrayPad~1

Pad 0การป้อนข้อมูลด้วยชั้นหนึ่ง

BlockMap[If[#[[2,2]]==b,b,Count[#,b,2]]&, ... ,{3,3},1]

แบ่งพาร์ติชันอินพุตเป็นเมทริกซ์ 3 x 3 ที่มีออฟเซ็ต 1 สำหรับแต่ละพาร์ติชันให้ใช้ฟังก์ชันเช่นถ้าค่ากลางคือb(= "*") เอาต์พุตคือb(= "*") และหากค่ากลางไม่b(= "*") output คือจำนวนb(= "*") ในอินพุต ขั้นตอนนี้จะประเมินเซลล์ตัวเลขทั้งหมดอีกครั้ง


Cases[ ... ,#/.q->_,All]

จากผลลัพธ์ทั้งหมดค้นหารายการที่ตรงกับอินพุต

0&/@ ... =={0}

ตรวจสอบว่าอินพุตมีความยาว 1


7

Perl, 215 ไบต์

รหัส + -p0ธง213 ไบต์(2 ไบต์)

/.*/;$c="@+";$_=A x$c."
$_".A x$c;s/^|$/A/mg;sub t{my($_)=@_;if(/\?/){for$i(0..8,"*"){t(s/\?/$i/r)}}else{$r=1;for$i(/\d/g){$r&=!/(...)[^V]{$c}(.$i.)[^V]{$c}(...)(??{"$1$2$3"=~y%*%%!=$i?"":R})/}$e+=$r}}t$_;$_=$e==1

แนวคิดของรหัสคือการทดสอบทุกความเป็นไปได้และดูว่ามีเพียงหนึ่งเดียวเท่านั้นที่นำไปสู่คณะกรรมการที่เต็มไปอย่างสมบูรณ์ที่ถูกต้อง

อ่านเพิ่มเติมรหัสดูเหมือนว่า:

/.*/;$c="@+ "; # นับขนาดของบรรทัด; $ c = "@ +" ; # นับขนาดของบรรทัด           
$ _ = A x $ c "\ n $ _" A x $ c; # เพิ่มบรรทัด "A" ที่จุดเริ่มต้นและอีกบรรทัดในตอนท้าย= เครื่องหมาย x $ "\ n $ _" A $ x ; # เพิ่มบรรทัด "A" ที่จุดเริ่มต้นและอีกบรรทัดในตอนท้าย  
s / ^ | $ / A / มิลลิกรัม # เพิ่ม "A" ที่จุดเริ่มต้นและจุดสิ้นสุดของแต่ละบรรทัด/ ^ | $ / A / mg ; # เพิ่ม "A" ที่จุดเริ่มต้นและจุดสิ้นสุดของแต่ละบรรทัด        

# funcion ที่แก้ปัญหาได้จริง# funcion ที่แก้ปัญหาได้จริง
ย่อย t { ย่อยt { 
    $ _ = ป๊อปอัปของฉัน # รับพารามิเตอร์เก็บไว้ใน $ _ (อาร์กิวเมนต์เริ่มต้นเพื่อ regex)ฉัน$ _ = pop ; # รับพารามิเตอร์เก็บไว้ใน $ _ (อาร์กิวเมนต์เริ่มต้นเพื่อ regex) 
    if (/ \? /) {# ถ้ามีตัวอักษรอื่นที่ไม่รู้จักif ( / \? / ) { # ถ้ามีตัวอักษรอื่นที่ไม่รู้จัก    
        สำหรับ $ i (0..8, "*") {# ลองทุกความเป็นไปได้สำหรับ$ i ( 0. . 8 , "*" ) { # ลองทุกความเป็นไปได้  
            t (s / \? / $ i / r) # reccursive call ที่แทนที่ char ที่ไม่รู้จักแรกถูกแทนที่( s / \? / $ i / r ) # การเรียกซ้ำที่แทนที่ char แรกที่ไม่รู้จัก  
        }}
    } else {# ไม่มีอักขระที่ไม่รู้จักอีกแล้วดังนั้นที่นี่เราตรวจสอบว่าบอร์ดถูกต้องหรือไม่} else { # ไม่มีอักขระที่ไม่รู้จักอีกแล้วดังนั้นที่นี่เราตรวจสอบว่าบอร์ดถูกต้องหรือไม่ 
        $ r = 1; # if r == 1 ในตอนท้ายบอร์ดจะใช้ได้ไม่เช่นนั้น= 1 ; # if r == 1 ในตอนท้ายบอร์ดจะใช้ได้ไม่เช่นนั้น  
        สำหรับ $ i (/ \ d / g) {# สำหรับแต่ละหมายเลขที่มีในกระดานสำหรับ$ i ( / \ d / g ) { # สำหรับแต่ละหมายเลขที่มีในกระดาน  
            # regex ต่อไปนี้ตรวจสอบว่ามีตัวเลขล้อมรอบด้วยหรือไม่ # regex ต่อไปนี้ตรวจสอบว่ามีตัวเลขล้อมรอบด้วยหรือไม่ 
            # เหมืองมากเกินไปหรือน้อยเกินไป# เหมืองมากเกินไปหรือน้อยเกินไป
            # (มันทำงานอย่างไร: มายากล!)# (มันทำงานอย่างไร: มายากล!)
         $ R & =! / ( ... ) [^ V] {$ C} (. $ i.) [^ V] {$ C} ( ... ) (?? { "$ 1 $ 2 $ 3" ​​= ~ Y% * %% = $ i "": R}) / และ =! /(...)[^V]{$c}(.$i.)[^V]{$c}(...)(??{"$1$2$3"=~y%*%%! = $ i "": R}) / 
        }}
        $ e + = $ r # เพิ่มจำนวนบอร์ดที่ถูกต้อง+ = $ r # เพิ่มจำนวนบอร์ดที่ถูกต้อง
    }}
}}
T $ _; # เรียกใช้ฟังก์ชันก่อนหน้า; # เรียกใช้ฟังก์ชันก่อนหน้า 
$ _ = $ e == 1 # ตรวจสอบว่ามีบอร์ดที่ใช้ได้เพียงบอร์ดเดียวเท่านั้น ($ _ ถูกพิมพ์โดยปริยายด้วยแฟล็ก -p)= $ e == 1 # ตรวจสอบว่ามีบอร์ดที่ใช้ได้เพียงบอร์ดเดียวเท่านั้น ($ _ ถูกพิมพ์โดยปริยายด้วยแฟล็ก -p) 

เกี่ยวกับ regex ที่อยู่ตรงกลาง:

/(...)[^V]{$c}(.$i.)[^V]{$c}(...)(??{"$1$2$3"=~y%*%%!=$i?"":R})/

โปรดทราบว่า[^V]ย่อมาจาก "อักขระใด ๆ รวมถึง \ n"
ดังนั้นความคิดคือ: 3 อักขระบนบรรทัดจากนั้น 3 ในหน้าถัดไป ( $iตรงกลาง) จากนั้น 3 ในหน้าถัดไป ทั้งสามกลุ่มของ 3 หมายเลขนั้นอยู่ในแนวเดียวกันขอบคุณ[^V]{$c}และตัวเลขที่เราสนใจนั้นอยู่ตรงกลาง
จากนั้น"$1$2$3"=~y%*%%นับจำนวน*(ระเบิด) ในบรรดาอักขระ 9 ตัว: ถ้ามันแตกต่างจาก$iเราเพิ่มสตริงว่างเพื่อจับคู่ ( ""=> การจับคู่ทันที regex ส่งคืนจริง) มิฉะนั้นเราบังคับให้ล้มเหลวโดยพยายามจับคู่R( ซึ่งไม่สามารถอยู่ในสตริงได้)
หากตรงกับ regex แล้วคณะกรรมการจะไม่ถูกต้องดังนั้นเราตั้ง$rไปด้วย0 และนั่นคือเหตุผลที่เราเพิ่มบางส่วน$r&=!/.../
Aทุกที่รอบ ๆ แต่ละบรรทัด: ดังนั้นเราไม่ต้องกังวลเกี่ยวกับกรณีขอบของตัวเลขที่อยู่ใกล้กับขอบกระดาน: พวกเขาจะมีAเหมือนเพื่อนบ้านซึ่งไม่ใช่เหมือง (แน่นอนแน่นอนว่าคนทำงานคนไหนจะทำงานได้ ฉันเลือกA)

คุณสามารถรันโปรแกรมจากบรรทัดคำสั่งเช่นนั้น:

perl -p0E '/.*/;$c="@+";$_=A x$c."\n$_".A x$c;s/^|$/A/mg;sub t{my($_)=@_;if(/\?/){for$i(0..8,"*"){t(s/\?/$i/r)}}else{$r=1;for$i(/\d/g){$r&=!/(...)[^V]{$c}(.$i.)[^V]{$c}(...)(??{"$1$2$3"=~y%*%%!=$i?"":R})/}$e+=$r}}t$_;$_=$e==1' <<< "1121
1??*
12?*
0122"

ความซับซ้อนไม่อาจจะเลวร้ายที่สุด: มันO(m*9^n)ที่nเป็นจำนวนของ?บนกระดานและmเป็นจำนวนของเซลล์บนกระดาน (โดยไม่นับความซับซ้อนของ regex ที่อยู่ตรงกลางซึ่งอาจเป็นที่ไม่ดีงาม) บนเครื่องของฉันมันใช้งานได้เร็วมากถึง 4 ?และเริ่มช้าลง 5 ใช้เวลาไม่กี่นาทีสำหรับ 6 และฉันก็ไม่ได้ลองตัวเลขที่ใหญ่กว่า


3

JavaScript (ES6), 221 229

g=>(a=>{for(s=i=1;~i;g.replace(x,c=>a[j++],z=j=0).replace(/\d/g,(c,p,g)=>([o=g.search`
`,-o,++o,-o,++o,-o,1,-1].map(d=>c-=g[p+d]=='*'),z|=c)),s-=!z)for(i=a.length;a[--i]='*?'[+(c=a[i]<'?')],c;);})(g.match(x=/\?/g)||[])|!s

หากการป้อนข้อมูลทั้งหมดคาดว่าจะถูกต้อง - นั่นคือการแก้ปัญหาอย่างน้อย 1 - จากนั้นฉันสามารถบันทึกการเปลี่ยนแปลงไบต์s==1ด้วยs<2

น้อย golfed

g=>{
  a = g.match(/\?/g) || []; // array of '?' in a
  s = 1; // counter of solutions
  for(i=0; ~i;) // loop to find all configurations of ? and *
  {
    // get next configuration
    for(i = a.length; a[--i] = '*?'[+( c = a[i] < '?')], c; );
    z = 0; // init at 0, must stay 0 if all cells count is ok
    g
    .replace(/\?/g,c=>a[j++],j=0) // put ? and * at right places
    .replace(/\d/g,(c,p,g)=>(
       // look for mines in all 8 directions
       // for each mine decrease c
       // if c ends at 0, then the count is ok
       [o=g.search`\n`,-o,++o,-o,++o,-o,1,-1].map(d=>c-=g[p+d]=='*'),
       z|=c // z stays at 0 if count is ok
    )) // check neighbour count
    s-=!z // if count ok for all cells, decrement number of solutions
  }
  return s==0 // true if exactly one solution found
}

ทดสอบ

F=
g=>(a=>{for(s=i=1;~i;g.replace(x,c=>a[j++],z=j=0).replace(/\d/g,(c,p,g)=>([o=g.search`
`,-o,++o,-o,++o,-o,1,-1].map(d=>c-=g[p+d]=='*'),z|=c)),s-=!z)for(i=a.length;a[--i]='*?'[+(c=a[i]<'?')],c;);})(g.match(x=/\?/g)||[])|!s

out=x=>O.textContent+=x+'\n'

Solvable=['1121\n1??*\n12?*\n0122'
,'1110\n1???\n1110\n0000'
,'1110\n3???\n??20\n*310'
,'****\n****\n****\n****'
,'0000\n0000\n0000\n0000'
,'1100\n*100\n2321\n??*2\n13*2\n1221\n1*10\n1110'
,'1121\n2*??\n2*31\n2220\n1*10']
Unsolvable=['1110\n2*31\n3*??\n2*4?\n112?'
,'01??11*211\n12??2323*1\n1*33*2*210\n12?2122321\n13?3101**1\n1***101221'
,'1***\n3*52\n2*31\n12??\n02??\n01??'
,'00000111\n000012*1\n00001*21\n22101110\n**100111\n?31123*1\n?311**31\n**113*20']
out('Solvable')
Solvable.forEach(t=>out(t+'\n'+F(t)+'\n'))
out('Unsolvable')
Unsolvable.forEach(t=>out(t+'\n'+F(t)+'\n'))
<pre id=O></pre>


แย้มยิ้มคุณสามารถเล่นกอล์ฟแบบไบท์ได้
เลมอนที่ทำลายได้

@DestructibleWatermelon ขอบคุณผมแก้ไขและประหยัดมากขึ้นบางไบต์แน่นอน
edc65

0

JavaScript (Node.js) , 167 ไบต์

s=>g=(r=c='',[p,...q]=s,w)=>w?0:p?(g(r+0,q,p=='*')+g(r+1,q,1/p),c==1):c-=-![...s].some((p,i)=>p>' '&&[-1,1,-q,-1-q,-2-q,q,q+1,q+2].map(j=>p-=~~r[i+j])|p,q=s.search`
`)

ลองออนไลน์!

แม้ว่า op บอกว่า "อินพุตจะเป็นรูปสี่เหลี่ยมผืนผ้าเสมอมีโซลูชันอย่างน้อยหนึ่งรายการ" แต่ตัวอย่างที่ผิดพลาด 3 ไม่ตรงกันดังนั้นฉันยังต้องการโซลูชัน 1 โซลูชันไม่ใช่โซลูชัน <2

s=>(        // p.s. Here "block" can also mean \n
  c=0,          // possible mine count
  g=(           // recursive
    r='',       // mine states
    [p,...q]=s, // known info to check possible state for a block
    w           // invert condition, stop if true
  )=>
    w?0:
      p?(       // for each block
        g(r+0,q,p=='*')+   // possibly not bomb if doesn't say so
        g(r+1,q,1/p),      // number/newline can't be bomb
        c==1               // only one bomb
      ):
        c-=-![...s].some(  // no block doesn't satisfy
          (p,i)=>
            p>' '&& // \n don't mean number
                    // other symbols turn into NaN when counting
            [-1,1,-q,-1-q,-2-q,q,q+1,q+2].map(j=>p-=~~r[i+j])
                    // subtract each neighbor, OOB = 0
            |p,     // difference between intended and actual
            q=s.search('\n') // how many blocks in a line
        )
)

ดูเหมือนว่า "ไม่ตรงกัน" เป็นตัวพิมพ์ผิดการแก้ไขมันทำให้โซลูชัน 4 อย่าง
l4m2
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.