ขยายการท่องเที่ยวของ Sudoku King ให้สูงสุด


16

พื้นหลัง

ซูโดกุเป็นปริศนาจำนวนที่รับn×nตารางแบ่งออกเป็นกล่องขนาดnจำนวนของแต่ละ1เพื่อnควรปรากฏว่าครั้งเดียวในแต่ละแถวคอลัมน์และกล่อง

ในเกมหมากรุกราชาสามารถเลื่อนไปยังเซลล์ใด ๆ (อย่างมาก) 8 เซลล์ที่อยู่ติดกันในคราวเดียว "ที่อยู่ติดกัน" ที่นี่หมายถึงที่อยู่ติดกันในแนวนอนแนวตั้งหรือแนวทแยงมุม

The King's tourเป็นการเปรียบเทียบของทัวร์ของอัศวิน มันเป็นเส้นทาง (อาจเปิด) ที่เข้าเยี่ยมชมทุกเซลล์อย่างแน่นอนหนึ่งครั้งบนกระดานที่กำหนดโดยมีการเคลื่อนไหวของ Chess King

งาน

พิจารณาตารางซูโดกุแบบ 6 ต่อ 6:

654 | 321
123 | 654
----+----
462 | 135
315 | 246
----+----
536 | 412
241 | 563

และทัวร์ของกษัตริย์ (จาก01ถึง36):

01 02 03 | 34 35 36
31 32 33 | 04 05 06
---------+---------
30 23 28 | 27 26 07
22 29 24 | 25 09 08
---------+---------
21 19 16 | 10 14 13
20 17 18 | 15 11 12

654654564463215641325365231214123321ทัวร์รูปแบบจำนวน 36 หลัก

การทัวร์ต่างประเทศของกษัตริย์ให้ตัวเลขที่มากขึ้น ตัวอย่างเช่นฉันสามารถหาเส้นทางที่ขึ้นต้นด้วย65<6>56446556...ซึ่งแน่นอนกว่าข้างต้น คุณสามารถเปลี่ยนกระดาน Sudoku เพื่อให้ได้ตัวเลขที่สูงขึ้น:

... | ...
.6. | ...
----+----
..6 | ...
.5. | 6..
----+----
.45 | .6.
6.. | 5..

บอร์ดที่ไม่สมบูรณ์นี้ให้ลำดับการเริ่มต้น666655546...ซึ่งเป็นลำดับที่ดีที่สุดของตัวเลขเริ่มต้น 9 หลัก

งานของคุณคือการหาหมายเลขดังกล่าวที่ใหญ่ที่สุดสำหรับซูโดกุแบบมาตรฐาน 9 ถึง 9 พร้อมกล่อง 3 ต่อ 3เช่น

... | ... | ...
... | ... | ...
... | ... | ...
----+-----+----
... | ... | ...
... | ... | ...
... | ... | ...
----+-----+----
... | ... | ...
... | ... | ...
... | ... | ...

โปรดทราบว่าความท้าทายนี้ไม่ได้เป็น ; มุ่งเน้นคือการหาวิธีแก้ปัญหามากกว่าที่จะเขียนโปรแกรมขนาดเล็กที่ใช้งานได้ในทางทฤษฎี

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

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

โปรแกรมของคุณอาจแสดงผลลัพธ์หลายรายการ คะแนนของคุณเป็นคะแนนสูงสุด

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


2
ในการเสนอชื่อของคุณเองสำหรับความท้าทายที่ดีที่สุดของ PPCG คุณพูดถึงว่า "นี่อาจจะเป็นครั้งแรกที่ [code-challenge] ถามถึงวิธีการแก้ปัญหาที่ได้รับการปรับปรุงโดยตรงไม่ใช่คะแนนรวมกับความยาวโค้ด ฉันแค่อยากจะบอกให้คุณรู้ว่ามันไม่เป็นความจริง - มีUniversal Maze Exit Stringที่สั้นที่สุดซึ่งถูกโพสต์ในปี 2015
ผลไม้ที่ละลายได้ใน

คำตอบ:


19

Python + Z3 , 999899898789789787876789658767666545355432471632124566352413452143214321432143231 ที่ดีที่สุด

ทำงานในประมาณครึ่งชั่วโมงผลิต

1 3 4 8 9 7 6 2 5
2 9 7 1 5 6 8 3 4
5 6 8 4 2 3 7 9 1
4 7 6 2 1 5 9 8 3
8 5 1 6 3 9 2 4 7
9 2 3 7 8 4 1 5 6
3 8 5 9 6 1 4 7 2
6 4 9 5 7 2 3 1 8
7 1 2 3 4 8 5 6 9
81 79 78 14 15 16 54 57 56
80 12 13 77 52 53 17 55 58
34 33 11 51 76 75 18  1 59
35 10 32 50 74 72  2 19 60
 9 36 49 31 73  3 71 61 20
 8 48 37 30  4 69 70 62 21
47  7 38  5 29 68 65 22 63
46 43  6 39 28 67 66 64 23
44 45 42 41 40 27 26 25 24
999899898789789787876789658767666545355432471632124566352413452143214125313214321

รหัส

import z3


def adj(a):
    x, y = a
    for x1 in range(max(0, x - 1), min(9, x + 2)):
        for y1 in range(max(0, y - 1), min(9, y + 2)):
            if (x1, y1) != a:
                yield x1, y1


solver = z3.SolverFor("QF_FD")

squares = list((x, y) for x in range(9) for y in range(9))
num = {(x, y): z3.Int(f"num{x}_{y}") for x, y in squares}
for a in squares:
    solver += 1 <= num[a], num[a] <= 9
for cells in (
    [[(x, y) for y in range(9)] for x in range(9)]
    + [[(x, y) for x in range(9)] for y in range(9)]
    + [
        [(x, y) for x in range(i, i + 3) for y in range(j, j + 3)]
        for i in range(0, 9, 3)
        for j in range(0, 9, 3)
    ]
):
    solver += z3.Distinct([num[x, y] for x, y in cells])
    for k in range(1, 10):
        solver += z3.Or([num[x, y] == k for x, y in cells])

move = {
    ((x0, y0), (x1, y1)): z3.Bool(f"move{x0}_{y0}_{x1}_{y1}")
    for x0, y0 in squares
    for x1, y1 in adj((x0, y0))
}
tour = {(x, y): z3.Int(f"tour{x}_{y}") for x, y in squares}
for a in squares:
    solver += 0 <= tour[a], tour[a] < 81
for a in squares:
    solver += z3.PbEq([(move[a, b], 1) for b in adj(a)] + [(tour[a] == 80, 1)], 1)
for b in squares:
    solver += z3.PbEq([(move[a, b], 1) for a in adj(b)] + [(tour[b] == 0, 1)], 1)
solver += z3.Distinct([tour[a] for a in squares])
for t in range(81):
    solver += z3.Or([tour[a] == t for a in squares])
for a in squares:
    for b in adj(a):
        solver += move[a, b] == (tour[a] + 1 == tour[b])

value = [z3.Int(f"value{t}") for t in range(81)]
for t in range(81):
    solver += 1 <= value[t], value[t] <= 9
for a in squares:
    for t in range(81):
        solver += z3.Implies(tour[a] == t, num[a] == value[t])

assert solver.check() != z3.unsat
opt = 0
while opt < 81:
    model = solver.model()
    for y in range(9):
        print(*(model[num[x, y]] for x in range(9)))
    for y in range(9):
        print(*(f"{model[tour[x, y]].as_long() + 1:2}" for x in range(9)))
    best = [model[value[t]].as_long() for t in range(81)]
    print(*best, sep="")
    print()
    while opt < 81:
        improve = z3.Bool(f"improve{opt}_{best[opt]}")
        solver += improve == (value[opt] > best[opt])
        if solver.check(improve) != z3.unsat:
            break
        solver += value[opt] == best[opt]
        opt += 1

แน่นอนฉันประเมินค่าสูงเกินไปปัญหามากเกินไป และฉันสมบูรณ์ลืมมายากลมืดของ Z3 ...
Bubbler

@Bubler มั่นใจว่าทางออกที่ดีที่สุดนั้นยาก ฉันทำผิดพลาดเหมือนกัน - และฉันใช้เวลาน้อยลงก่อนที่จะมีคนโพสต์คำตอบที่ดีที่สุด ... codegolf.stackexchange.com/a/51974/20283
trichoplax

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