-
Notifications
You must be signed in to change notification settings - Fork 0
/
npuzzle-gen.py
98 lines (81 loc) · 2.22 KB
/
npuzzle-gen.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python
import sys
import argparse
import random
def make_puzzle(s, solvable, iterations):
def swap_empty(p):
idx = p.index(0)
poss = []
if idx % s > 0:
poss.append(idx - 1)
if idx % s < s - 1:
poss.append(idx + 1)
if idx / s > 0 and idx - s >= 0:
poss.append(idx - s)
if idx / s < s - 1:
poss.append(idx + s)
swi = random.choice(poss)
p[idx] = p[swi]
p[swi] = 0
p = make_goal(s)
for i in range(iterations):
swap_empty(p)
if not solvable:
if p[0] == 0 or p[1] == 0:
p[-1], p[-2] = p[-2], p[-1]
else:
p[0], p[1] = p[1], p[0]
return p
def make_goal(s):
ts = s*s
puzzle = [-1 for i in range(ts)]
cur = 1
x = 0
ix = 1
y = 0
iy = 0
while True:
puzzle[x + y*s] = cur
if cur == 0:
break
cur += 1
if x + ix == s or x + ix < 0 or (ix != 0 and puzzle[x + ix + y*s] != -1):
iy = ix
ix = 0
elif y + iy == s or y + iy < 0 or (iy != 0 and puzzle[x + (y+iy)*s] != -1):
ix = -iy
iy = 0
x += ix
y += iy
if cur == s*s:
cur = 0
return puzzle
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("size", type=int, help="Size of the puzzle's side. Must be >3.")
parser.add_argument("-s", "--solvable", action="store_true", default=False, help="Forces generation of a solvable puzzle. Overrides -u.")
parser.add_argument("-u", "--unsolvable", action="store_true", default=False, help="Forces generation of an unsolvable puzzle")
parser.add_argument("-i", "--iterations", type=int, default=10000, help="Number of passes")
args = parser.parse_args()
random.seed()
if args.solvable and args.unsolvable:
print "Can't be both solvable AND unsolvable, dummy !"
sys.exit(1)
if args.size < 3:
print "Can't generate a puzzle with size lower than 2. It says so in the help. Dummy."
sys.exit(1)
if not args.solvable and not args.unsolvable:
solv = random.choice([True, False])
elif args.solvable:
solv = True
elif args.unsolvable:
solv = False
s = args.size
puzzle = make_puzzle(s, solvable=solv, iterations=args.iterations)
w = len(str(s*s))
print "# This puzzle is %s" % ("solvable" if solv else "unsolvable")
print "%d" % s
for y in range(s):
for x in range(s):
print "%s" % (str(puzzle[x + y*s]).rjust(w)),
print