-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathJigsawInferenceGizmo.py
191 lines (153 loc) · 5.98 KB
/
JigsawInferenceGizmo.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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# JIG code from Stand-up Maths video "Why don't Jigsaw Puzzles have the correct number of pieces?"
def low_factors(n):
# all the factors which are the lower half of each factor pair
lf = []
for i in range(1, int(n**0.5)+1):
if n % i == 0:
lf.append(i)
return lf
def jig(w,h,n,b=0):
# percentage we'll check in either direction
threshold = 0.1
# the extra badness per piece
penalty = 1.005
ratio = max(w,h)/min(w,h) # switched to be greater than 1
print("")
print(f"{w} by {h} is picture ratio {round(ratio,4)}")
print("")
max_cap = int((1+threshold)*n)
min_cap = int((1-threshold)*n)
up_range = [i for i in range(n,max_cap+1)]
down_range = [i for i in range(min_cap,n)] # do not want n included again
down_range.reverse()
# start at 100 which is silly high and then move down.
up_best = 100
up_best_deets = []
down_best = 100
down_best_deets = []
# I am using the run marker so I know if looking above or below n
run = 0
for dis_range in [up_range,down_range]:
best_n = 0
best_n_ratio = 0
best_n_sides = []
if run == 0:
print(f"Looking for >= {n} solutions:")
print("")
else:
print("")
print("Just out of interest, here are smaller options:")
print("")
for i in dis_range:
this_best = 0
for j in low_factors(i):
j2 = int(i/j) # must be a whole number anyway
this_ratio = j2/j
if this_best == 0:
this_best = this_ratio
best_sides = [j,j2]
else:
if abs(this_ratio/ratio - 1) < abs(this_best/ratio - 1):
this_best = this_ratio
best_sides = [j,j2]
yes = 0
if best_n == 0:
yes = 1
else:
if abs(this_best/ratio - 1) < abs(best_n_ratio/ratio - 1):
yes = 1
if yes == 1:
best_n = i
best_n_ratio = this_best
best_n_sides = best_sides
piece_ratio = max(ratio,this_best)/min(ratio,this_best)
badness_score = (penalty**(abs(i-n)))*piece_ratio
if run == 0:
if badness_score < up_best:
up_best = badness_score
up_best_deets = [best_n,best_n_sides,best_n_ratio]
else:
if badness_score < down_best:
down_best = badness_score
down_best_deets = [best_n,best_n_sides,best_n_ratio]
print(f"{best_n} pieces in {best_n_sides} (grid ratio {round(best_n_ratio,4)}) needs piece ratio {round(piece_ratio,4)}")
if b==1:
print(f"[badness = {round(badness_score,5)}]")
print(f"for {n} the best is {best_n} pieces with size {best_n_sides}")
run += 1
print("")
print(f"If I had to guess: I think it's {up_best_deets[0]} pieces.")
if down_best < up_best:
print("")
print(f"BUT, fun fact, {down_best_deets[0]} would be even better.")
print("")
return 'DONE'
# I duplicated jig_v0 to make is easier to show in the video
def jig_v0(w,h,n,b=0):
# percentage we'll check in either direction
threshold = 0.1
penalty = 1.005
ratio = max(w,h)/min(w,h) # switched to be greater than 1
print("")
print(f"{w} by {h} is picture ratio {round(ratio,4)}")
print("")
max_cap = int((1+threshold)*n)
min_cap = int((1-threshold)*n)
up_range = [i for i in range(n,max_cap+1)]
down_range = [i for i in range(min_cap,n)] # do not want n included again
down_range.reverse()
# start at 100 which is silly high and then move down.
up_best = 100
up_best_deets = []
down_best = 100
down_best_deets = []
run = 0
for dis_range in [up_range,down_range]:
best_n = 0
best_n_ratio = 0
best_n_sides = []
if run == 0:
print(f"Looking for >= {n} solutions:")
print("")
else:
print("")
print("Just out of interest, here are smaller options:")
print("")
for i in dis_range:
this_best = 0
for j in low_factors(i):
j2 = int(i/j) # must be a whole number anyway
this_ratio = j2/j
if this_best == 0:
this_best = this_ratio
best_sides = [j,j2]
else:
if abs(this_ratio/ratio - 1) < abs(this_best/ratio - 1):
this_best = this_ratio
best_sides = [j,j2]
yes = 0
if best_n == 0:
yes = 1
else:
if abs(this_best/ratio - 1) < abs(best_n_ratio/ratio - 1):
yes = 1
if yes == 1:
best_n = i
best_n_ratio = this_best
best_n_sides = best_sides
piece_ratio = max(ratio,this_best)/min(ratio,this_best)
badness_score = (penalty**(abs(i-n)))*piece_ratio
if run == 0:
if badness_score < up_best:
up_best = badness_score
up_best_deets = [best_n,best_n_sides,best_n_ratio]
else:
if badness_score < down_best:
down_best = badness_score
down_best_deets = [best_n,best_n_sides,best_n_ratio]
print(f"{best_n} pieces in {best_n_sides} (grid ratio {round(best_n_ratio,4)}) needs piece ratio {round(piece_ratio,4)}")
if b==1:
print(f"[badness = {round(badness_score,5)}]")
run += 1
print("")
return 'DONE'