Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download
Path: chomp.py
Views: 87
1
import pickle
2
3
class ChompBoard():
4
def __init__(self, _rows = []):
5
6
#make sure sequence is non-increasing, then initialize new board
7
if all(_rows[i]>=_rows[i+1] for i in range(len(_rows)-1)):
8
self._rows = _rows
9
10
#clean up extra zeros at beginning of 1st row.
11
while self._rows != [] and self._rows[len(self._rows)-1] == 0:
12
self._rows.pop()
13
else:
14
raise TypeError("list elements must be non-increasing")
15
16
#an equality test, that is used when deciding if a P-board is new or one seen alread
17
def __eq__(self, other):
18
return self._rows == other._rows
19
20
#repr = "representation", used when printing some representation of a board
21
def __repr__(self):
22
return str(self._rows)
23
24
#a user-accessible way to get a name for a board
25
def name(self):
26
return str(self._rows)
27
28
#a non-hidden, user-accessible way to get the list of cookies per row
29
def rows(self):
30
return copy(self._rows)
31
32
#a non-hidden, user-accessible way to get the list of cookies per column
33
def columns(self):
34
M = self.matrix()
35
return [sum(x) for x in M.columns()]
36
37
#should be the number of rows that have at least one cookie
38
def number_of_rows(self):
39
return len(self._rows)
40
41
#a non-hidden, user-accessible way to get the list of cookies per column
42
def columns(self):
43
M = self.matrix()
44
return [sum(x) for x in M.columns()]
45
46
#should be the number of cookies in the first row
47
def number_of_columns(self):
48
if self.number_of_rows() == 0:
49
return 0
50
else:
51
return self._rows[0]
52
53
#counts number of cookies
54
def number_of_cookies(self):
55
return sum(self._rows)
56
57
#counts full board size
58
def full_rectangle(self):
59
return self.number_of_columns() * self.number_of_rows()
60
61
#counts empty spaces
62
def empty_space(self):
63
return self.full_rectangle() - self.number_of_cookies()
64
65
#counts full square
66
def full_square(self):
67
return max(self.number_of_rows()**2,self.number_of_columns()**2)
68
69
def rows_of_different_length(self):
70
M = self.matrix()
71
return M.rank()
72
73
# column rank of matrix = row rank
74
def columns_of_different_length(self):
75
return self.rows_of_different_length()
76
77
# number of duplicate rows
78
def duplicate_rows(self):
79
return abs(self.number_of_rows() - self.rows_of_different_length())
80
81
# number of duplicate columns
82
def duplicate_columns(self):
83
return abs(self.number_of_columns() - self.columns_of_different_length())
84
85
# full square matrix
86
def squared_matrix(self):
87
M = self.matrix()
88
M = self.matrix()
89
if self._rows == []:
90
return matrix(0,0,[])
91
#ws[0],len(self._rows))
92
M = matrix(m,m,[0]*(m*m))
93
for i in range(len(self._rows)):
94
for j in range(self._rows[i]):
95
M[i,j] = 1
96
return M
97
98
# determinant
99
def determinant(self):
100
M = self.squared_matrix()
101
return det(M)
102
103
# trace
104
def trace_square(self):
105
M = self.squared_matrix()
106
return M.trace()
107
108
# rows-columns difference
109
def squareness(self):
110
return abs(self.number_of_rows()-self.number_of_columns())
111
112
#gives a "picture" of the board as a 0-1 matrix
113
def matrix(self):
114
if self._rows == []:
115
return matrix(0,0,[])
116
m = len(self._rows)
117
n = self._rows[0]
118
M = matrix(m,n,[0]*(m*n))
119
for i in range(m):
120
for j in range(self._rows[i]):
121
M[i,j] = 1
122
return M
123
124
#column rank of matrix = row rank
125
def columns_of_different_length(self):
126
return self.rows_of_different_length()
127
128
# number of duplicate rows
129
def duplicate_rows(self):
130
return self.number_of_rows() - self.rows_of_different_length()
131
132
# number of duplicate columns
133
#uses fact that row rank = column rank
134
def duplicate_columns(self):
135
return self.number_of_columns() - self.rows_of_different_length()
136
137
138
#DON'T USE, has uninitialized Lreal M[i,j] = 1
139
140
141
#column rank of matrix = row rank
142
def columns_of_different_length(self):
143
def max_eigenvalue(self):
144
if self._rows == []:
145
return 0
146
M = self.squared_matrix()
147
L = M.eigenvalues()
148
return max([real_part(x) for x in L])
149
150
def min_eigenvalue(self):
151
if self._rows == []:
152
return 0
153
M = self.squared_matrix()
154
L = M.eigenvalues()
155
return min([real_part(x) for x in L])
156
157
158
def max_eigenvalue(self):
159
if self._rows == []:
160
return 0
161
M = self.squared_matrix()
162
def max_eigenvalue(self):
163
if self._rows == []:
164
return 0
165
M = self.squared_matrix()
166
L = M.eigenvalues()
167
return max([real_part(x) for x in L])
168
169
170
171
def min_eigenvalue(self):
172
if self._rows == []:
173
return 0
174
M = self.squared_matrix()
175
L = M.eigenvalues()
176
return min([real_part(x) for x in L])
177
178
179
# number of duplicate rows
180
def duplicate_rows(self):
181
def max_eigenvalue(self):
182
if self._rows == []:
183
return 0
184
M = self.squared_matrix()
185
L = M.eigenvalues()
186
return max([real_part(x) for x in L])
187
188
def min_eigenvalue(self):
189
if self._rows == []:
190
return 0
191
def max_eigenvalue(self):
192
if self._rows == []:
193
return 0
194
M = self.squared_matrix()
195
L = M.eigenvalues()
196
return max([real_part(x) for x in L])
197
198
def min_eigenvalue(self):
199
if self._rows == []:
200
return 0
201
M = self.squared_matrix()
202
L = M.eigenvalues()
203
return min([real_part(x) for x in L])
204
205
206
# number of duplicate rows
207
def duplicate_rows(self):
208
def max_eigenvalue(self):
209
if self._rows == []:
210
return 0
211
M = self.squared_matrix()
212
L = M.eigenvalues()
213
return max([real_part(x) for x in L])
214
215
def min_eigenvalue(self):
216
if self._rows == []:
217
return 0
218
M = self.squared_matrix()
219
L = M.eigenvalues()
220
return min([real_part(x) for x in L])
221
222
223
# number of duplicate columns
224
def duplicate_columns(self):
225
n = self._rows[0]
226
M = matrix(m,n,[0]*(m*n))
227
for i in range(m):
228
for j in range(self._rows[i]):
229
M[i,j] = 1
230
return M
231
232
#gives min positive eigenvalue
233
#DON'T USE, has uninitialized Lreal
234
def eigen_max_positive(self):
235
M = self.squared_matrix()
236
L = M.eigenvalues()
237
if Lreal != []:
238
return max(Lreal)
239
else:
240
return 0
241
242
def squared_damage_matrix(self):
243
M_columns = self.number_of_columns()
244
M_rows = self.number_of_rows()
245
M_max = max(self.number_of_columns(),self.number_of_rows())
246
M = matrix(M_max,M_max,[0]*(M_max**2))
247
oldcookies = self.number_of_cookies()
248
for i in range(M_rows):
249
for j in range(M_columns):
250
newboard= chomp_board_after_eating_cookie(self,i,j)
251
newcookies = newboard.number_of_cookies()
252
damage = oldcookies - newcookies
253
M[i,j] = damage
254
return M
255
256
#returns a squared damage matrix
257
def squared_damage_matrix(self):
258
M_columns = self.number_of_columns()
259
M_rows = self.number_of_rows()
260
M_max = max(self.number_of_columns(),self.number_of_rows())
261
M = matrix(M_max,M_max,[0]*(M_max**2))
262
oldcookies = self.number_of_cookies()
263
for i in range(M_rows):
264
for j in range(M_columns):
265
newboard= chomp_board_after_eating_cookie(self,i,j)
266
newcookies = newboard.number_of_cookies()
267
damage = oldcookies - newcookies
268
M[i,j] = damage
269
return M
270
271
272
#returns a squared damage matrix
273
def squared_damage_matrix(self):
274
M_columns = self.number_of_columns()
275
M_rows = self.number_of_rows()
276
M_max = max(self.number_of_columns(),self.number_of_rows())
277
M = matrix(M_max,M_max,[0]*(M_max**2))
278
oldcookies = self.number_of_cookies()
279
for i in range(M_rows):
280
for j in range(M_columns):
281
M_columns = self.number_of_columns()
282
M_rows = self.number_of_rows()
283
number = 0
284
M= self.damage_matrix()
285
for i in range(M_rows):
286
for j in range(M_columns):
287
number = number + M[i,j]
288
return number
289
290
#returns the gcd of of row lengths
291
def row_gcd(self):
292
return gcd([sum(x) for x in self.rows()])
293
294
295
296
#returns the product of the row lengths
297
def row_product(self):
298
if self.rows() == []:
299
return 0
300
return prod(self.rows())
301
302
#returns the product of the column lengths
303
def column_product(self):
304
if self.name() == "[]":
305
return 0
306
return prod(self.columns()) newboard= chomp_board_after_eating_cookie(self,i,j)
307
newcookies = newboard.number_of_cookies()
308
damage = oldcookies - newcookies
309
M[i,j] = damage
310
return M
311
312
#returns a squared damage matrix
313
def squared_damage_matrix(self):
314
M_columns = self.number_of_columns()
315
M_rows = self.number_of_rows()
316
M_max = max(self.number_of_columns(),self.number_of_rows())
317
M = matrix(M_max,M_max,[0]*(M_max**2))
318
oldcookies = self.number_of_cookies()
319
for i in range(M_rows):
320
for j in range(M_columns):
321
newboard= chomp_board_after_eating_cookie(self,i,j)
322
newcookies = newboard.number_of_cookies()
323
damage = oldcookies - newcookies
324
M[i,j] = damage
325
return M
326
327
#returns a squared damage matrix
328
def squared_damage_matrix(self):
329
M_columns = self.number_of_columns()
330
M_rows = self.number_of_rows()
331
M_max = max(self.number_of_columns(),self.number_of_rows())
332
M = matrix(M_max,M_max,[0]*(M_max**2))
333
oldcookies = self.number_of_cookies()
334
for i in range(M_rows):
335
for j in range(M_columns):
336
newboard= chomp_board_after_eating_cookie(self,i,j)
337
newcookies = newboard.number_of_cookies()
338
damage = oldcookies - newcookies
339
M[i,j] = damage
340
return M
341
342
return M
343
344
return M
345
346
#returns a squared damage matrix
347
def squared_damage_matrix(self):
348
M_columns = self.number_of_columns()
349
M_rows = self.number_of_rows()
350
M_max = max(self.number_of_columns(),self.number_of_rows())
351
M = matrix(M_max,M_max,[0]*(M_max**2))
352
oldcookies = self.number_of_cookies()
353
for i in range(M_rows):
354
for j in range(M_columns):
355
newboard= chomp_board_after_eating_cookie(self,i,j)
356
newcookies = newboard.number_of_cookies()
357
damage = oldcookies - newcookies
358
M[i,j] = damage
359
return M
360
361
#returns a squared damage matrix
362
def squared_damage_matrix(self):
363
M_columns = self.number_of_columns()
364
M_rows = self.number_of_rows()
365
M_max = max(self.number_of_columns(),self.number_of_rows())
366
M = matrix(M_max,M_max,[0]*(M_max**2))
367
oldcookies = self.number_of_cookies()
368
for i in range(M_rows):
369
for j in range(M_columns):
370
newboard= chomp_board_after_eating_cookie(self,i,j)
371
newcookies = newboard.number_of_cookies()
372
damage = oldcookies - newcookies
373
M[i,j] = damage
374
return M
375
376
377
#returns a squared damage matrix
378
def squared_damage_matrix(self):
379
M_columns = self.number_of_columns()
380
M_rows = self.number_of_rows()
381
M_max = max(self.number_of_columns(),self.number_of_rows())
382
M = matrix(M_max,M_max,[0]*(M_max**2))
383
oldcookies = self.number_of_cookies()
384
for i in range(M_rows):
385
for j in range(M_columns):
386
newboard= chomp_board_after_eating_cookie(self,i,j)
387
newcookies = newboard.number_of_cookies()
388
damage = oldcookies - newcookies
389
M[i,j] = damage
390
return M
391
392
#returns a squared damage matrix
393
def squared_damage_matrix(self):
394
M_columns = self.number_of_columns()
395
M_rows = self.number_of_rows()
396
M_max = max(self.number_of_columns(),self.number_of_rows())
397
M = matrix(M_max,M_max,[0]*(M_max**2))
398
oldcookies = self.number_of_cookies()
399
for i in range(M_rows):
400
for j in range(M_columns):
401
newboard= chomp_board_after_eating_cookie(self,i,j)
402
newcookies = newboard.number_of_cookies()
403
damage = oldcookies - newcookies
404
M[i,j] = damage
405
return M
406
407
408
409
#returns real eigenvalues
410
def eigen(self):
411
M = self.squared_matrix()
412
L = M.eigenvalues()
413
return [x for x in L if x.is_real()]
414
415
#returns a matrix of damage values
416
def damage_matrix(self):
417
M_columns = self.number_of_columns()
418
M_rows = self.number_of_rows()
419
number = 0
420
M= self.damage_matrix()
421
for i in range(M_rows):
422
for j in range(M_columns):
423
number = number + M[i,j]
424
return number
425
426
#returns the gcd of of row lengths
427
def row_gcd(self):
428
return gcd(self.rows())
429
430
#returns the lcm of of row lengths
431
def row_lcm(self):
432
return lcm(self.rows())
433
434
M = self.squared_matrix()
435
L = M.eigenvalues()
436
return min([real_part(x) for x in L])
437
return self.number_of_rows() - self.rows_of_different_length()
438
439
# number of duplicate columns
440
def duplicate_columns(self):
441
n = self._rows[0]
442
M = matrix(m,n,[0]*(m*n))
443
for i in range(m):
444
for j in range(self._rows[i]):
445
M[i,j] = 1
446
return M
447
448
#gives min positive eigenvalue
449
#DON'T USE, has uninitialized Lreal
450
def eigen_max_positive(self):
451
M = self.squared_matrix()
452
L = M.eigenvalues()
453
if Lreal != []:
454
return max(Lreal)
455
else:
456
return 0s a squared damage matrix
457
def squared_damage_matrix(self):
458
M_columns = self.number_of_columns()
459
M_rows = self.number_of_rows()
460
M_max = max(self.number_of_columns(),self.number_of_rows())
461
M = matrix(M_max,M_max,[0]*(M_max**2))
462
oldcookies = self.number_of_cookies()
463
for i in range(M_rows):
464
for j in range(M_columns):
465
newboard= chomp_board_after_eating_cookie(self,i,j)
466
newcookies = newboard.number_of_cookies()
467
damage = oldcookies - newcookies
468
M[i,j] = damage
469
return M
470
471
#returns a squared damage matrix
472
def squared_damage_matrix(self):
473
M_columns = self.number_of_columns()
474
M_rows = self.number_of_rows()
475
M_max = max(self.number_of_columns(),self.number_of_rows())
476
M = matrix(M_max,M_max,[0]*(M_max**2))
477
oldcookies = self.number_of_cookies()
478
for i in range(M_rows):
479
for j in range(M_columns):
480
newboard= chomp_board_after_eating_cookie(self,i,j)
481
newcookies = newboard.number_of_cookies()
482
damage = oldcookies - newcookies
483
M[i,j] = damage
484
return M
485
486
487
#returns a squared damage matrix
488
def squared_damage_matrix(self):
489
M_columns = self.number_of_columns()
490
M_rows = self.number_of_rows()
491
M_max = max(self.number_of_columns(),self.number_of_rows())
492
M = matrix(M_max,M_max,[0]*(M_max**2))
493
oldcookies = self.number_of_cookies()
494
for i in range(M_rows):
495
for j in range(M_columns):
496
M_columns = self.number_of_columns()
497
M_rows = self.number_of_rows()
498
number = 0
499
M= self.damage_matrix()
500
for i in range(M_rows):
501
for j in range(M_columns):
502
number = number + M[i,j]
503
return number
504
505
#returns the gcd of of row lengths
506
def row_gcd(self):
507
return gcd([sum(x) for x in self.rows()])
508
509
510
511
#returns the product of the row lengths
512
def row_product(self):
513
if self.rows() == []:
514
return 0
515
return prod(self.rows())
516
517
#returns the product of the column lengths
518
def column_product(self):
519
if self.name() == "[]":
520
return 0
521
return prod(self.columns()) newboard= chomp_board_after_eating_cookie(self,i,j)
522
newcookies = newboard.number_of_cookies()
523
damage = oldcookies - newcookies
524
M[i,j] = damage
525
return M
526
527
#returns a squared damage matrix
528
def squared_damage_matrix(self):
529
M_columns = self.number_of_columns()
530
M_rows = self.number_of_rows()
531
M_max = max(self.number_of_columns(),self.number_of_rows())
532
M = matrix(M_max,M_max,[0]*(M_max**2))
533
oldcookies = self.number_of_cookies()
534
for i in range(M_rows):
535
for j in range(M_columns):
536
newboard= chomp_board_after_eating_cookie(self,i,j)
537
newcookies = newboard.number_of_cookies()
538
damage = oldcookies - newcookies
539
M[i,j] = damage
540
return M
541
542
#returns a squared damage matrix
543
def squared_damage_matrix(self):
544
M_columns = self.number_of_columns()
545
M_rows = self.number_of_rows()
546
M_max = max(self.number_of_columns(),self.number_of_rows())
547
M = matrix(M_max,M_max,[0]*(M_max**2))
548
oldcookies = self.number_of_cookies()
549
for i in range(M_rows):
550
for j in range(M_columns):
551
newboard= chomp_board_after_eating_cookie(self,i,j)
552
newcookies = newboard.number_of_cookies()
553
damage = oldcookies - newcookies
554
M[i,j] = damage
555
return M
556
557
return M
558
559
return M
560
561
#returns a squared damage matrix
562
def squared_damage_matrix(self):
563
M_columns = self.number_of_columns()
564
M_rows = self.number_of_rows()
565
M_max = max(self.number_of_columns(),self.number_of_rows())
566
M = matrix(M_max,M_max,[0]*(M_max**2))
567
oldcookies = self.number_of_cookies()
568
for i in range(M_rows):
569
for j in range(M_columns):
570
newboard= chomp_board_after_eating_cookie(self,i,j)
571
newcookies = newboard.number_of_cookies()
572
damage = oldcookies - newcookies
573
M[i,j] = damage
574
return M
575
576
#returns a squared damage matrix
577
def squared_damage_matrix(self):
578
M_columns = self.number_of_columns()
579
M_rows = self.number_of_rows()
580
M_max = max(self.number_of_columns(),self.number_of_rows())
581
M = matrix(M_max,M_max,[0]*(M_max**2))
582
oldcookies = self.number_of_cookies()
583
for i in range(M_rows):
584
for j in range(M_columns):
585
newboard= chomp_board_after_eating_cookie(self,i,j)
586
newcookies = newboard.number_of_cookies()
587
damage = oldcookies - newcookies
588
M[i,j] = damage
589
return M
590
591
592
#returns a squared damage matrix
593
def squared_damage_matrix(self):
594
M_columns = self.number_of_columns()
595
M_rows = self.number_of_rows()
596
M_max = max(self.number_of_columns(),self.number_of_rows())
597
M = matrix(M_max,M_max,[0]*(M_max**2))
598
oldcookies = self.number_of_cookies()
599
for i in range(M_rows):
600
for j in range(M_columns):
601
newboard= chomp_board_after_eating_cookie(self,i,j)
602
newcookies = newboard.number_of_cookies()
603
damage = oldcookies - newcookies
604
M[i,j] = damage
605
return M
606
607
#returns a squared damage matrix
608
def squared_damage_matrix(self):
609
M_columns = self.number_of_columns()
610
M_rows = self.number_of_rows()
611
M_max = max(self.number_of_columns(),self.number_of_rows())
612
M = matrix(M_max,M_max,[0]*(M_max**2))
613
oldcookies = self.number_of_cookies()
614
for i in range(M_rows):
615
for j in range(M_columns):
616
newboard= chomp_board_after_eating_cookie(self,i,j)
617
newcookies = newboard.number_of_cookies()
618
damage = oldcookies - newcookies
619
M[i,j] = damage
620
return M
621
622
623
624
#returns real eigenvalues
625
def eigen(self):
626
M = self.squared_matrix()
627
L = M.eigenvalues()
628
return [x for x in L if x.is_real()]
629
630
#returns a matrix of damage values
631
def damage_matrix(self):
632
M_columns = self.number_of_columns()
633
M_rows = self.number_of_rows()
634
number = 0
635
M= self.damage_matrix()
636
for i in range(M_rows):
637
for j in range(M_columns):
638
number = number + M[i,j]
639
return number
640
641
#returns the gcd of of row lengths
642
def row_gcd(self):
643
return gcd(self.rows())
644
645
#returns the lcm of of row lengths
646
def row_lcm(self):
647
return lcm(self.rows())
648
649
L = M.eigenvalues()
650
return max([real_part(x) for x in L])
651
652
def min_eigenvalue(self):
653
if self._rows == []:
654
return 0
655
def max_eigenvalue(self):
656
if self._rows == []:
657
return 0
658
M = self.squared_matrix()
659
L = M.eigenvalues()
660
return max([real_part(x) for x in L])
661
662
def min_eigenvalue(self):
663
if self._rows == []:
664
return 0
665
M = self.squared_matrix()
666
L = M.eigenvalues()
667
return min([real_part(x) for x in L])
668
return self.rows_of_different_length()
669
670
# number of duplicate rows
671
def duplicate_rows(self):
672
def max_eigenvalue(self):
673
if self._rows == []:
674
return 0
675
M = self.squared_matrix()
676
L = M.eigenvalues()
677
return max([real_part(x) for x in L])
678
679
def min_eigenvalue(self):
680
if self._rows == []:
681
return 0
682
M = self.squared_matrix()
683
L = M.eigenvalues()
684
return min([real_part(x) for x in L])
685
return self.number_of_rows() - self.rows_of_different_length()
686
687
# number of duplicate columns
688
def duplicate_columns(self):
689
n = self._rows[0]
690
M = matrix(m,n,[0]*(m*n))
691
for i in range(m):
692
for j in range(self._rows[i]):
693
M[i,j] = 1
694
return M
695
696
#gives min positive eigenvalue
697
#DON'T USE, has uninitialized Lreal
698
def eigen_max_positive(self):
699
M = self.squared_matrix()
700
L = M.eigenvalues()
701
if Lreal != []:
702
return max(Lreal)
703
else:
704
return 0s a squared damage matrix
705
def squared_damage_matrix(self):
706
M_columns = self.number_of_columns()
707
M_rows = self.number_of_rows()
708
M_max = max(self.number_of_columns(),self.number_of_rows())
709
M = matrix(M_max,M_max,[0]*(M_max**2))
710
oldcookies = self.number_of_cookies()
711
for i in range(M_rows):
712
for j in range(M_columns):
713
newboard= chomp_board_after_eating_cookie(self,i,j)
714
newcookies = newboard.number_of_cookies()
715
damage = oldcookies - newcookies
716
M[i,j] = damage
717
return M
718
719
#returns a squared damage matrix
720
def squared_damage_matrix(self):
721
M_columns = self.number_of_columns()
722
M_rows = self.number_of_rows()
723
M_max = max(self.number_of_columns(),self.number_of_rows())
724
M = matrix(M_max,M_max,[0]*(M_max**2))
725
oldcookies = self.number_of_cookies()
726
for i in range(M_rows):
727
for j in range(M_columns):
728
newboard= chomp_board_after_eating_cookie(self,i,j)
729
newcookies = newboard.number_of_cookies()
730
damage = oldcookies - newcookies
731
M[i,j] = damage
732
return M
733
734
735
#returns a squared damage matrix
736
def squared_damage_matrix(self):
737
M_columns = self.number_of_columns()
738
M_rows = self.number_of_rows()
739
M_max = max(self.number_of_columns(),self.number_of_rows())
740
M = matrix(M_max,M_max,[0]*(M_max**2))
741
oldcookies = self.number_of_cookies()
742
for i in range(M_rows):
743
for j in range(M_columns):
744
M_columns = self.number_of_columns()
745
M_rows = self.number_of_rows()
746
number = 0
747
M= self.damage_matrix()
748
for i in range(M_rows):
749
for j in range(M_columns):
750
number = number + M[i,j]
751
return number
752
753
#returns the gcd of of row lengths
754
def row_gcd(self):
755
return gcd([sum(x) for x in self.rows()])
756
757
758
759
#returns the product of the row lengths
760
def row_product(self):
761
if self.rows() == []:
762
return 0
763
return prod(self.rows())
764
765
#returns the product of the column lengths
766
def column_product(self):
767
if self.name() == "[]":
768
return 0
769
return prod(self.columns()) newboard= chomp_board_after_eating_cookie(self,i,j)
770
newcookies = newboard.number_of_cookies()
771
damage = oldcookies - newcookies
772
M[i,j] = damage
773
return M
774
775
#returns a squared damage matrix
776
def squared_damage_matrix(self):
777
M_columns = self.number_of_columns()
778
M_rows = self.number_of_rows()
779
M_max = max(self.number_of_columns(),self.number_of_rows())
780
M = matrix(M_max,M_max,[0]*(M_max**2))
781
oldcookies = self.number_of_cookies()
782
for i in range(M_rows):
783
for j in range(M_columns):
784
newboard= chomp_board_after_eating_cookie(self,i,j)
785
newcookies = newboard.number_of_cookies()
786
damage = oldcookies - newcookies
787
M[i,j] = damage
788
return M
789
790
#returns a squared damage matrix
791
def squared_damage_matrix(self):
792
M_columns = self.number_of_columns()
793
M_rows = self.number_of_rows()
794
M_max = max(self.number_of_columns(),self.number_of_rows())
795
M = matrix(M_max,M_max,[0]*(M_max**2))
796
oldcookies = self.number_of_cookies()
797
for i in range(M_rows):
798
for j in range(M_columns):
799
newboard= chomp_board_after_eating_cookie(self,i,j)
800
newcookies = newboard.number_of_cookies()
801
damage = oldcookies - newcookies
802
M[i,j] = damage
803
return M
804
805
return M
806
807
return M
808
809
#returns a squared damage matrix
810
def squared_damage_matrix(self):
811
M_columns = self.number_of_columns()
812
M_rows = self.number_of_rows()
813
M_max = max(self.number_of_columns(),self.number_of_rows())
814
M = matrix(M_max,M_max,[0]*(M_max**2))
815
oldcookies = self.number_of_cookies()
816
for i in range(M_rows):
817
for j in range(M_columns):
818
newboard= chomp_board_after_eating_cookie(self,i,j)
819
newcookies = newboard.number_of_cookies()
820
damage = oldcookies - newcookies
821
M[i,j] = damage
822
return M
823
824
#returns a squared damage matrix
825
def squared_damage_matrix(self):
826
M_columns = self.number_of_columns()
827
M_rows = self.number_of_rows()
828
M_max = max(self.number_of_columns(),self.number_of_rows())
829
M = matrix(M_max,M_max,[0]*(M_max**2))
830
oldcookies = self.number_of_cookies()
831
for i in range(M_rows):
832
for j in range(M_columns):
833
newboard= chomp_board_after_eating_cookie(self,i,j)
834
newcookies = newboard.number_of_cookies()
835
damage = oldcookies - newcookies
836
M[i,j] = damage
837
return M
838
839
840
#returns a squared damage matrix
841
def squared_damage_matrix(self):
842
M_columns = self.number_of_columns()
843
M_rows = self.number_of_rows()
844
M_max = max(self.number_of_columns(),self.number_of_rows())
845
M = matrix(M_max,M_max,[0]*(M_max**2))
846
oldcookies = self.number_of_cookies()
847
for i in range(M_rows):
848
for j in range(M_columns):
849
newboard= chomp_board_after_eating_cookie(self,i,j)
850
newcookies = newboard.number_of_cookies()
851
damage = oldcookies - newcookies
852
M[i,j] = damage
853
return M
854
855
#returns a squared damage matrix
856
def squared_damage_matrix(self):
857
M_columns = self.number_of_columns()
858
M_rows = self.number_of_rows()
859
M_max = max(self.number_of_columns(),self.number_of_rows())
860
M = matrix(M_max,M_max,[0]*(M_max**2))
861
oldcookies = self.number_of_cookies()
862
for i in range(M_rows):
863
for j in range(M_columns):
864
newboard= chomp_board_after_eating_cookie(self,i,j)
865
newcookies = newboard.number_of_cookies()
866
damage = oldcookies - newcookies
867
M[i,j] = damage
868
return M
869
870
871
872
#returns real eigenvalues
873
def eigen(self):
874
M = self.squared_matrix()
875
L = M.eigenvalues()
876
return [x for x in L if x.is_real()]
877
878
#returns a matrix of damage values
879
def damage_matrix(self):
880
M_columns = self.number_of_columns()
881
M_rows = self.number_of_rows()
882
number = 0
883
M= self.damage_matrix()
884
for i in range(M_rows):
885
for j in range(M_columns):
886
number = number + M[i,j]
887
return number
888
889
#returns the gcd of of row lengths
890
def row_gcd(self):
891
return gcd(self.rows())
892
893
#returns the lcm of of row lengths
894
def row_lcm(self):
895
return lcm(self.rows())
896
897
M = self.squared_matrix()
898
L = M.eigenvalues()
899
return min([real_part(x) for x in L])
900
return self.number_of_rows() - self.rows_of_different_length()
901
902
# number of duplicate columns
903
def duplicate_columns(self):
904
n = self._rows[0]
905
M = matrix(m,n,[0]*(m*n))
906
for i in range(m):
907
for j in range(self._rows[i]):
908
M[i,j] = 1
909
return M
910
911
#gives min positive eigenvalue
912
#DON'T USE, has uninitialized Lreal
913
def eigen_max_positive(self):
914
M = self.squared_matrix()
915
L = M.eigenvalues()
916
if Lreal != []:
917
return max(Lreal)
918
else:
919
return 0s a squared damage matrix
920
def squared_damage_matrix(self):
921
M_columns = self.number_of_columns()
922
try:
923
value = conj.evaluate(board)
924
if value == False:
925
Pcounterexamples.append(board.name())
926
print "{} is a counterexample to: {}".format(board.name(),conj)
927
return board
928
except:
929
print "error with evaluating: {} for {}".format(conj,board.name())
930
931
L = find_reachable_P_positions(ChompBoard([column_limit]*row_limit))
932
933
for board in L:
934
try:
935
value = conj.evaluate(board)
936
if value == False:
937
Pcounterexamples.append(board.name())
938
print "{} is a counterexample to: {}".format(board.name(),conj)
939
return board
940
except:
941
print "error with evaluating: {} for {}".format(conj,board.name()) M_rows = self.number_of_rows()
942
M_max = max(self.number_of_columns(),self.number_of_rows())
943
M = matrix(M_max,M_max,[0]*(M_max**2))
944
oldcookies = self.number_of_cookies()
945
for i in range(M_rows):
946
for j in range(M_columns):
947
newboard= chomp_board_after_eating_cookie(self,i,j)
948
newcookies = newboard.number_of_cookies()
949
damage = oldcookies - newcookies
950
M[i,j] = damage
951
return M
952
953
#returns a squared damage matrix
954
def squared_damage_matrix(self):
955
M_columns = self.number_of_columns()
956
M_rows = self.number_of_rows()
957
M_max = max(self.number_of_columns(),self.number_of_rows())
958
M = matrix(M_max,M_max,[0]*(M_max**2))
959
oldcookies = self.number_of_cookies()
960
for i in range(M_rows):
961
for j in range(M_columns):
962
newboard= chomp_board_after_eating_cookie(self,i,j)
963
newcookies = newboard.number_of_cookies()
964
damage = oldcookies - newcookies
965
M[i,j] = damage
966
return M
967
968
969
#returns a squared damage matrix
970
def squared_damage_matrix(self):
971
M_columns = self.number_of_columns()
972
M_rows = self.number_of_rows()
973
M_max = max(self.number_of_columns(),self.number_of_rows())
974
M = matrix(M_max,M_max,[0]*(M_max**2))
975
oldcookies = self.number_of_cookies()
976
for i in range(M_rows):
977
for j in range(M_columns):
978
M_columns = self.number_of_columns()
979
M_rows = self.number_of_rows()
980
number = 0
981
M= self.damage_matrix()
982
for i in range(M_rows):
983
for j in range(M_columns):
984
number = number + M[i,j]
985
return number
986
987
#returns the gcd of of row lengths
988
def row_gcd(self):
989
return gcd([sum(x) for x in self.rows()])
990
991
992
993
#returns the product of the row lengths
994
def row_product(self):
995
if self.rows() == []:
996
return 0
997
return prod(self.rows())
998
999
#returns the product of the column lengths
1000
def column_product(self):
1001
if self.name() == "[]":
1002
return 0
1003
return prod(self.columns()) newboard= chomp_board_after_eating_cookie(self,i,j)
1004
newcookies = newboard.number_of_cookies()
1005
damage = oldcookies - newcookies
1006
M[i,j] = damage
1007
return M
1008
1009
#returns a squared damage matrix
1010
def squared_damage_matrix(self):
1011
M_columns = self.number_of_columns()
1012
M_rows = self.number_of_rows()
1013
M_max = max(self.number_of_columns(),self.number_of_rows())
1014
M = matrix(M_max,M_max,[0]*(M_max**2))
1015
oldcookies = self.number_of_cookies()
1016
for i in range(M_rows):
1017
for j in range(M_columns):
1018
newboard= chomp_board_after_eating_cookie(self,i,j)
1019
newcookies = newboard.number_of_cookies()
1020
damage = oldcookies - newcookies
1021
M[i,j] = damage
1022
return M
1023
1024
#returns a squared damage matrix
1025
def squared_damage_matrix(self):
1026
M_columns = self.number_of_columns()
1027
M_rows = self.number_of_rows()
1028
M_max = max(self.number_of_columns(),self.number_of_rows())
1029
M = matrix(M_max,M_max,[0]*(M_max**2))
1030
oldcookies = self.number_of_cookies()
1031
for i in range(M_rows):
1032
for j in range(M_columns):
1033
newboard= chomp_board_after_eating_cookie(self,i,j)
1034
newcookies = newboard.number_of_cookies()
1035
damage = oldcookies - newcookies
1036
M[i,j] = damage
1037
return M
1038
1039
return M
1040
1041
return M
1042
1043
#returns a squared damage matrix
1044
def squared_damage_matrix(self):
1045
M_columns = self.number_of_columns()
1046
M_rows = self.number_of_rows()
1047
M_max = max(self.number_of_columns(),self.number_of_rows())
1048
M = matrix(M_max,M_max,[0]*(M_max**2))
1049
oldcookies = self.number_of_cookies()
1050
for i in range(M_rows):
1051
for j in range(M_columns):
1052
newboard= chomp_board_after_eating_cookie(self,i,j)
1053
newcookies = newboard.number_of_cookies()
1054
damage = oldcookies - newcookies
1055
M[i,j] = damage
1056
return M
1057
1058
#returns a squared damage matrix
1059
def squared_damage_matrix(self):
1060
M_columns = self.number_of_columns()
1061
M_rows = self.number_of_rows()
1062
M_max = max(self.number_of_columns(),self.number_of_rows())
1063
M = matrix(M_max,M_max,[0]*(M_max**2))
1064
oldcookies = self.number_of_cookies()
1065
for i in range(M_rows):
1066
for j in range(M_columns):
1067
newboard= chomp_board_after_eating_cookie(self,i,j)
1068
newcookies = newboard.number_of_cookies()
1069
damage = oldcookies - newcookies
1070
M[i,j] = damage
1071
return M
1072
1073
1074
#returns a squared damage matrix
1075
def squared_damage_matrix(self):
1076
M_columns = self.number_of_columns()
1077
M_rows = self.number_of_rows()
1078
M_max = max(self.number_of_columns(),self.number_of_rows())
1079
M = matrix(M_max,M_max,[0]*(M_max**2))
1080
oldcookies = self.number_of_cookies()
1081
for i in range(M_rows):
1082
for j in range(M_columns):
1083
newboard= chomp_board_after_eating_cookie(self,i,j)
1084
newcookies = newboard.number_of_cookies()
1085
damage = oldcookies - newcookies
1086
M[i,j] = damage
1087
return M
1088
1089
#returns a squared damage matrix
1090
def squared_damage_matrix(self):
1091
M_columns = self.number_of_columns()
1092
M_rows = self.number_of_rows()
1093
M_max = max(self.number_of_columns(),self.number_of_rows())
1094
M = matrix(M_max,M_max,[0]*(M_max**2))
1095
oldcookies = self.number_of_cookies()
1096
for i in range(M_rows):
1097
for j in range(M_columns):
1098
newboard= chomp_board_after_eating_cookie(self,i,j)
1099
newcookies = newboard.number_of_cookies()
1100
damage = oldcookies - newcookies
1101
M[i,j] = damage
1102
return M
1103
1104
1105
1106
#returns real eigenvalues
1107
def eigen(self):
1108
M = self.squared_matrix()
1109
L = M.eigenvalues()
1110
return [x for x in L if x.is_real()]
1111
1112
#returns a matrix of damage values
1113
def damage_matrix(self):
1114
M_columns = self.number_of_columns()
1115
M_rows = self.number_of_rows()
1116
number = 0
1117
M= self.damage_matrix()
1118
for i in range(M_rows):
1119
for j in range(M_columns):
1120
number = number + M[i,j]
1121
return number
1122
1123
#returns the gcd of of row lengths
1124
def row_gcd(self):
1125
return gcd(self.rows())
1126
1127
#returns the lcm of of row lengths
1128
def row_lcm(self):
1129
return lcm(self.rows())
1130
1131
1132
1133
def eigen_min_positive(self):
1134
M = self.squared_matrix()
1135
L = M.eigenvalues()
1136
Lreal = [real_part(x) for x in L if real_part(x) > 0]
1137
if Lreal != []:
1138
return max(Lreal)
1139
else:
1140
return 0
1141
1142
#returns a matrix of damage values
1143
def damage_matrix(self):
1144
M_columns = self.number_of_columns()
1145
M_rows = self.number_of_rows()
1146
M_max = max(self.number_of_columns(),self.number_of_rows())
1147
M_max = max(self.number_of_columns(),self.number_of_rows())
1148
M_max = max(self.number_of_columns(),self.number_of_rows())
1149
M_max = max(self.number_of_columns(),self.number_of_rows())
1150
M_max = max(self.number_of_columns(),self.number_of_rows())
1151
M = matrix(M_rows,M_columns,[0]*(M_rows*M_columns))
1152
oldcookies = self.number_of_cookies()
1153
for i in range(M_rows):
1154
for j in range(M_columns):
1155
newboard= chomp_board_after_eating_cookie(self,i,j)
1156
newcookies = newboard.number_of_cookies()
1157
damage = oldcookies - newcookies
1158
M[i,j] = damage
1159
return M
1160
1161
#returns a squared damage matrix
1162
def squared_damage_matrix(self):
1163
M_columns = self.number_of_columns()
1164
M_rows = self.number_of_rows()
1165
M_max = max(self.number_of_columns(),self.number_of_rows())
1166
M = matrix(M_max,M_max,[0]*(M_max**2))
1167
oldcookies = self.number_of_cookies()
1168
for i in range(M_rows):
1169
for j in range(M_columns):
1170
newboard= chomp_board_after_eating_cookie(self,i,j)
1171
newcookies = newboard.number_of_cookies()
1172
damage = oldcookies - newcookies
1173
M[i,j] = damage
1174
return M
1175
1176
#returns real eigenvalues
1177
def eigen(self):
1178
M = self.squared_matrix()
1179
L = M.eigenvalues()
1180
return [x for x in L if x.is_real()]
1181
1182
#returns a matrix of damage values
1183
def damage_matrix(self):
1184
M_columns = self.number_of_columns()
1185
M_rows = self.number_of_rows()
1186
number = 0
1187
M= self.damage_matrix()
1188
for i in range(M_rows):
1189
for j in range(M_columns):
1190
M_columns = self.number_of_columns()
1191
M_rows = self.number_of_rows()
1192
number = 0
1193
M= self.damage_matrix()
1194
for i in range(M_rows):
1195
for j in range(M_columns):
1196
number = number + M[i,j]
1197
return number
1198
1199
#returns the gcd of of row lengths
1200
def row_gcd(self):
1201
return gcd([sum(x) for x in self.rows()])
1202
1203
1204
1205
#returns the product of the row lengths
1206
def row_product(self):
1207
if self.rows() == []:
1208
return 0
1209
return prod(self.rows())
1210
1211
#returns the product of the column lengths
1212
def column_product(self):
1213
if self.name() == "[]":
1214
return 0
1215
return prod(self.columns()) number = number + M[i,j]
1216
return number
1217
1218
#returns the gcd of of row lengths
1219
def row_gcd(self):
1220
return gcd(self.rows())
1221
1222
#returns the lcm of of row lengths
1223
def row_lcm(self):
1224
return lcm(self.rows())
1225
1226
#Sum of orthogonal neighbors of each cookie
1227
def laura_number_sum(self):
1228
#Trivial cases
1229
if self._rows == []:
1230
return 0
1231
if self.number_of_rows() == 1:
1232
return 2*self._rows[0] - 2
1233
1234
#Non-trivial cases
1235
row1_laura_number = 2*self._rows[0] - 2 + self._rows[1]
1236
other_row_laura_number = 0
1237
1238
for i in range(1, self.number_of_rows() - 1):
1239
other_row_laura_number += 3*self._rows[i] + self._rows[i+1] - 2
1240
other_row_laura_number += 3*self._rows[-1] - 2
1241
1242
return row1_laura_number + other_row_laura_number
1243
1244
#Damage of a cookie is defined as the number of cookies removed from the board if this cookie were to be eaten next move.
1245
#This is the sum of the damage of each of the cookies on the board.
1246
def damage_sum(self):
1247
M_columns = self.number_of_columns()
1248
M_rows = self.number_of_rows()
1249
number = 0
1250
M= self.damage_matrix()
1251
for i in range(M_rows):
1252
for j in range(M_columns):
1253
number = number + M[i,j]
1254
return number
1255
1256
#returns the product of the row lengths
1257
def row_product(self):
1258
if self.rows() == []:
1259
return 0
1260
return prod(self.rows())
1261
1262
#returns the product of the column lengths
1263
def column_product(self):
1264
if self.name() == "[]":
1265
return 0
1266
return prod(self.columns())
1267
1268
#returns the gcd of of column lengths
1269
def column_gcd(self):
1270
output = self.column_product()
1271
for column in self.columns():
1272
output = gcd(output,column)
1273
return output
1274
1275
#returns the lcm of of column lengths
1276
def column_lcm(self):
1277
return lcm([sum(x) for x in self.columns()])
1278
1279
1280
#returns the lcm of of row lengths
1281
def row_lcm(self):
1282
return lcm([sum(x) for x in self.rows()])
1283
1284
1285
# trace of damage matrix
1286
def trace_damage(self):
1287
M = self.squared_damage_matrix()
1288
return M.trace()
1289
1290
def average_damage(self):
1291
damage_sum = self.damage_sum()
1292
cookies = self.number_of_cookies()
1293
average = damage_sum/cookies
1294
return average
1295
1296
def rank_ratio(self):
1297
rank = self.rows_of_different_length()
1298
rows = self.number_of_rows()
1299
return n(rank/rows)
1300
1301
1302
1303
# gives average number of cookies per row
1304
def average_cookies_per_row(self):
1305
count = 0
1306
rows = self.number_of_rows()
1307
for cookies in self.rows():
1308
count = count + cookies
1309
return n(count/rows)
1310
1311
# gives average number of cookies per column
1312
def average_cookies_per_column(self):
1313
count = 0
1314
columns = self.number_of_columns()
1315
for cookies in self.columns():
1316
count = count + cookies
1317
return n(count/columns)
1318
1319
#Steepness of a Chomp Board
1320
def bevel(self):
1321
total = 0
1322
row_diff = 0
1323
i=0
1324
while i <= self.number_of_rows()-2:
1325
if self.rows()[i] - self.rows()[i+1] == 0:
1326
total = total + row_diff
1327
else:
1328
row_diff = self.rows()[i] - self.rows()[i+1]
1329
total = total + row_diff
1330
i=i+1
1331
return total
1332
1333
#Smallest row size
1334
def smallest_row_size(self):
1335
return min(self.rows())
1336
1337
#Smallest column size
1338
def smallest_column_size(self):
1339
M = self.matrix()
1340
return min(M.columns())
1341
1342
#number of cookies not in the first row or first column
1343
def cookies_inside(self):
1344
cookies = self.number_of_cookies()
1345
M = self.number_of_rows()
1346
N = self.number_of_columns()
1347
if M == 1 or N == 1:
1348
inside = 0
1349
else:
1350
inside = cookies - (M+N-1)
1351
return inside
1352
1353
#ratio of cookies not in the first row or first column and total cookies
1354
def cookies_inside_ratio(self):
1355
cookies = self.number_of_cookies()
1356
inside = self.cookies_inside()
1357
ratio = n(inside/cookies)
1358
return ratio
1359
1360
# remainder when cookies is divided by rows
1361
def row_remainder(self):
1362
M = self.number_of_rows()
1363
cookies = self.number_of_cookies()
1364
remainder = mod(cookies,M)
1365
return remainder
1366
1367
# remainder when cookies is divided by columns
1368
def column_remainder(self):
1369
N = self.number_of_columns()
1370
cookies = self.number_of_cookies()
1371
remainder = mod(cookies,N)
1372
return remainder
1373
1374
#For test_completes_self
1375
def row_difference(board):
1376
M = []
1377
for x in range(len(board)):
1378
if x < len(board)-1:
1379
M.append(board[x]-board[x+1])
1380
M.append(board[len(board)-1])
1381
return M
1382
1383
#For test_completes_self
1384
def column_difference(board):
1385
M = []
1386
N = []
1387
T = ChompBoard([5,4,2,1]).matrix().transpose()
1388
for x in range(board[0]):
1389
M.append(sum(T[x]))
1390
return filter(lambda x: x != 0, row_difference(M))
1391
1392
#For test_completes_self
1393
def step_list(board):
1394
A = row_difference(board)
1395
B = column_difference(board)
1396
C = []
1397
for x in range(len(A)):
1398
C.append(B[x])
1399
C.append(A[x])
1400
return C
1401
1402
###### PROPERTIES
1403
1404
#true if odd number of cookies false if even
1405
def is_P_board(self):
1406
if is_P_position(self):
1407
return True
1408
else:
1409
return False
1410
1411
def is_N_board(self):
1412
if is_N_position(self):
1413
return True
1414
else:
1415
return False
1416
1417
def odd_cookies(self):
1418
number = self.number_of_cookies()
1419
if is_even(number):
1420
return False
1421
else:
1422
return True
1423
1424
#true if even number of cookies false if odd
1425
def even_cookies(self):
1426
number = self.number_of_cookies()
1427
if is_even(number):
1428
return True
1429
else:
1430
return False
1431
1432
#tests if the board is a full square board
1433
def is_square(self):
1434
M = self.number_of_rows()
1435
N = self.number_of_columns()
1436
C = self.number_of_cookies()
1437
if M != N:
1438
return False
1439
elif C != M*N:
1440
return False
1441
else:
1442
return True
1443
def is_rectangle(self):
1444
M = self.number_of_rows()
1445
N = self.number_of_columns()
1446
C = self.number_of_cookies()
1447
if C != M*N:
1448
return False
1449
else:
1450
return True
1451
1452
1453
#test if our key conjecture is true (number_of_cookes >= 2*number_of_columns - 1)
1454
1455
def test_theorem1(self):
1456
C = self.number_of_cookies()
1457
col = self.number_of_columns()
1458
if C >= 2*col - 1:
1459
return True
1460
else:
1461
return False
1462
1463
# tests if the squareness == 0 (rows == columns)
1464
def squareness_is_zero(self):
1465
M = self.number_of_rows()
1466
N = self.number_of_columns()
1467
if M == N:
1468
return True
1469
else:
1470
return False
1471
1472
# checks if the trace is even
1473
def even_trace(self):
1474
T = self.trace_square()
1475
if is_even(T):
1476
return True
1477
else:
1478
return False
1479
1480
# checks if the trace if odd
1481
def odd_trace(self):
1482
T = self.trace_square()
1483
if is_odd(T):
1484
return True
1485
else:
1486
return False
1487
1488
1489
1490
1491
# tests if the board is a balanced L
1492
def is_balanced_L(self):
1493
M = self.number_of_rows()
1494
N = self.number_of_columns()
1495
C = self.number_of_cookies()
1496
if M == N and C == M + N - 1:
1497
return True
1498
else:
1499
return False
1500
1501
# tests if the board is an unbalanced L
1502
def is_unbalanced_L(self):
1503
M = self.number_of_rows()
1504
N = self.number_of_columns()
1505
C = self.number_of_cookies()
1506
if C > M+N-1:
1507
return False
1508
elif M == N:
1509
return False
1510
elif M == 1 or N == 1:
1511
return False
1512
else:
1513
return True
1514
1515
#the two column/row solution
1516
def is_two_row_solution(self):
1517
M = self.number_of_rows()
1518
N = self.number_of_columns()
1519
C = self.number_of_cookies()
1520
if M != 2 and N != 2:
1521
return False
1522
elif C != (2*M)-1 and C != (2*N)-1:
1523
return False
1524
else:
1525
return True
1526
1527
# tests if there are not rows of different
1528
def rank_one_property(self):
1529
R = self.rows_of_different_length()
1530
if R > 1:
1531
return False
1532
else:
1533
return True
1534
1535
# tests if there are rows of different length
1536
def rank_non_one_property(self):
1537
R = self.rows_of_different_length()
1538
if R > 1:
1539
return True
1540
else:
1541
return False
1542
1543
#test if our key conjecture is true (number_of_cookes >= 2*number_of_columns - 1)
1544
1545
def test_theorem1(self):
1546
C = self.number_of_cookies()
1547
col = self.number_of_columns()
1548
if C >= 2*col - 1:
1549
return True
1550
else:
1551
return False
1552
1553
# tests if a balanced L is reachable
1554
def reachable_balanced_L(self):
1555
reachable = find_reachable_boards(self)
1556
for board in reachable:
1557
if board.balanced_L() == True:
1558
return True
1559
return False
1560
1561
# if the two row solution is reachable
1562
# tests if a unbalanced L is reachable
1563
def reachable_unbalanced_L(self):
1564
reachable = find_reachable_boards(self)
1565
for board in reachable:
1566
if board.unbalanced_L() == True:
1567
return True
1568
return False
1569
1570
1571
# property of p position
1572
# if the two row solution is reachable
1573
def reachable_two_row_solution(self):
1574
reachable = find_reachable_boards(self)
1575
for board in reachable:
1576
if board.two_row_solution() == True:
1577
return True
1578
return False
1579
1580
# property of p position
1581
def test_P_position(self):
1582
if is_P_position(self)== True:
1583
return True
1584
else:
1585
return False
1586
1587
#zeilberger paper theorem 1 about 3 row chomp
1588
def three_row_one_cookie(self):
1589
M_rows = self.number_of_rows()
1590
if M_rows == 3:
1591
if self._rows[2]==1:
1592
if self.rows[0] == 2 and self.rows[1]==2:
1593
return True
1594
elif self.rows[1] == 1 and self.rows[0]==3:
1595
return True
1596
else:
1597
return False
1598
else:
1599
return False
1600
else:
1601
return False
1602
1603
def is_almost_L(self):
1604
M_rows = self.number_of_rows()
1605
M_col = self.number_of_columns()
1606
cookies = self.number_of_cookies()
1607
if abs(M_rows-M_col) != 1:
1608
return False
1609
elif cookies != M_rows + M_col:
1610
return True
1611
else:
1612
return False
1613
1614
def test_prime_cookies(self):
1615
1616
1617
def test_row_theorem(self):
1618
M = self.number_of_rows()
1619
cookies = self.number_of_cookies()
1620
if cookies >= 2*M - 1:
1621
return False
1622
elif is_even(M_rows) and M_rows < M_col:
1623
return True
1624
elif is_even(M_col) and M_col < M_rows:
1625
return True
1626
else:
1627
return False
1628
1629
1630
#zeilberger paper theorem 2 about 3 row chomp
1631
def three_row_two_cookie(self):
1632
M_rows = self.number_of_rows()
1633
if M_rows == 3:
1634
if self._rows[2]==2 and (self.rows[0]-self.rows[1])==2:
1635
return True
1636
else:
1637
return False
1638
else:
1639
return False
1640
1641
#needs explanation
1642
def is_almost_L(self):
1643
M_rows = self.number_of_rows()
1644
M_col = self.number_of_columns()
1645
cookies = self.number_of_cookies()
1646
if abs(M_rows-M_col) != 1:
1647
return False
1648
elif cookies != M_rows + M_col:
1649
return True
1650
else:
1651
return False
1652
1653
def test_prime_cookies(self):
1654
N = self.number_of_columns()
1655
cookies = self.number_of_cookies()
1656
if M == 1 or N == 1:
1657
return True
1658
elif cookies-(M+N-1) < M+N-1:
1659
return True
1660
else:
1661
return False
1662
1663
def cookies_divisible_by_rows(self):
1664
M = self.number_of_rows()
1665
cookies = self.number_of_cookies()
1666
if mod(cookies,M) == 0:
1667
return True
1668
else:
1669
return False
1670
1671
def cookies_divisible_by_columns(self):
1672
N = self.number_of_columns()
1673
cookies = self.number_of_cookies()
1674
if mod(cookies,N) == 0:
1675
return True
1676
else:
1677
return False
1678
1679
1680
1681
def test_row_theorem(self):
1682
M = self.number_of_rows()
1683
cookies = self.number_of_cookies()
1684
if cookies >= 2*M - 1:
1685
return False
1686
elif is_even(M_rows) and M_rows < M_col:
1687
return True
1688
elif is_even(M_col) and M_col < M_rows:
1689
return True
1690
else:
1691
return False
1692
1693
1694
def test_Theorem2(self):
1695
M_rows = self.number_of_rows()
1696
M_col = self.number_of_columns()
1697
cookies = self.number_of_cookies
1698
if M_col == M_rows + 1 and cookies == M_rows + M_col:
1699
return True
1700
else:
1701
return False
1702
1703
def test_prime_cookies(self):
1704
cookies = self.number_of_cookies()
1705
if is_prime(cookies):
1706
return True
1707
else:
1708
False
1709
1710
def test_row_theorem(self):
1711
M = self.number_of_rows()
1712
cookies = self.number_of_cookies()
1713
if cookies >= 2*M - 1:
1714
return True
1715
else:
1716
return False
1717
def composite_odd_cookies(self):
1718
cookies = self.number_of_cookies()
1719
if is_even(cookies):
1720
return False
1721
elif is_prime(cookies):
1722
return False
1723
else:
1724
return True
1725
1726
def rows_greater_than_columns(self):
1727
M = self.number_of_rows()
1728
N = self.number_of_columns()
1729
if M > N :
1730
return True
1731
else:
1732
return False
1733
1734
def columns_greater_than_rows(self):
1735
M = self.number_of_rows()
1736
N = self.number_of_columns()
1737
if M < N :
1738
return True
1739
else:
1740
return False
1741
1742
def is_symmetric(self):
1743
board = self.rows()
1744
transpose = self.columns()
1745
if board == transpose:
1746
return True
1747
else:
1748
return False
1749
1750
def cookies_in_greater_than_cookies_out(self):
1751
M = self.number_of_rows()
1752
N = self.number_of_columns()
1753
cookies = self.number_of_cookies()
1754
if M == 1 or N == 1:
1755
return False
1756
elif cookies-(M+N-1) > M+N-1:
1757
return True
1758
else:
1759
return False
1760
def cookies_out_greater_than_cookies_in(self):
1761
M = self.number_of_rows()
1762
N = self.number_of_columns()
1763
cookies = self.number_of_cookies()
1764
if M == 1 or N == 1:
1765
return True
1766
elif cookies-(M+N-1) < M+N-1:
1767
return True
1768
else:
1769
return False
1770
1771
def cookies_divisible_by_rows(self):
1772
M = self.number_of_rows()
1773
cookies = self.number_of_cookies()
1774
if mod(cookies,M) == 0:
1775
return True
1776
else:
1777
return False
1778
1779
def cookies_divisible_by_columns(self):
1780
N = self.number_of_columns()
1781
cookies = self.number_of_cookies()
1782
if mod(cookies,N) == 0:
1783
return True
1784
else:
1785
return False
1786
1787
1788
1789
#If rotated, does chomp board fit nicely with itself?
1790
def test_completes_self(board):
1791
A = step_list(board)[0:(len(step_list(board))-1)]
1792
B = step_list(board)[1:len(step_list(board))]
1793
if A == A[::-1] or B == B[::-1]:
1794
return True
1795
else:
1796
return False
1797
1798
1799
####FUNCTIONS
1800
1801
def string_to_list(string):
1802
L = []
1803
for x in str(string[1:(len(string)-1):3]):
1804
L.append(int(x))
1805
return L
1806
1807
#eat cookie in i,j th spot on board and return updated board
1808
def chomp_board_after_eating_cookie(board,i,j):
1809
board_rows = board.rows()
1810
1811
m = board.number_of_rows()
1812
n = board.number_of_columns()
1813
1814
new = board.rows()
1815
1816
for k in range(i,m):
1817
new[k] = min(board_rows[k],j)
1818
1819
return ChompBoard(new)
1820
1821
1822
1823
#find all the boards that are possible after the current player's move
1824
def find_reachable_boards(board):
1825
1826
reachable = []
1827
1828
if board.rows() == []:
1829
return reachable
1830
1831
m = board.number_of_rows()
1832
n = board.number_of_columns()
1833
1834
for i in range(m):
1835
for j in range(n):
1836
new = chomp_board_after_eating_cookie(board,i,j)
1837
if new.rows() != board.rows():
1838
if new.number_of_rows() >= 1:
1839
reachable.append(new)
1840
1841
return reachable
1842
1843
#finds the move i,j that was made to go from oldboard to newboard
1844
def find_move(oldboard, newboard):
1845
row = -1
1846
column = -1
1847
if oldboard.number_of_columns() != newboard.number_of_columns():
1848
return (0, newboard.rows()[0])
1849
1850
elif oldboard.number_of_rows() != newboard.number_of_rows():
1851
return (newboard.number_of_rows(), 0)
1852
1853
else:
1854
old= oldboard.matrix()
1855
newmatrix = newboard.matrix()
1856
for row in range(oldboard.number_of_rows()):
1857
for cookie in range(oldboard.rows()[row]):
1858
if oldmatrix[row][cookie] != newmatrix[row][cookie]:
1859
return (row, cookie)
1860
1861
# a position B is an P-position iff every reachable position is an N-position
1862
#equivalently, B is an N-position iff not (every reachable position is an N-position)
1863
#equivalently, B is an N-position iff there is a reachable position which is an P-position
1864
# base case: no cookies left is an N-position (and the sum of the rows = 0)
1865
1866
#stores "N" for postions which are N-positions and "P" for positions which are P-positions
1867
#loads "position_values.sobj" if it exists otherwise initializes a new one
1868
try:
1869
temp = load("position_values.sobj")
1870
position_values = temp
1871
except:
1872
position_values = {str([]):"N"}
1873
1874
#tests if a position is a N-position
1875
def is_N_position(B):
1876
1877
if B.name() in position_values:
1878
if position_values[B.name()] == "N":
1879
return True
1880
else:
1881
return False
1882
1883
else:
1884
value = any(is_P_position(A) for A in find_reachable_boards(B))
1885
if value == True:
1886
position_values[B.name()] = "N"
1887
return True
1888
else:
1889
position_values[B.name()] = "P"
1890
return False
1891
1892
#tests if a position is a P-position
1893
def is_P_position(B):
1894
1895
if B.name() in position_values:
1896
if position_values[B.name()] == "P":
1897
return True
1898
else:
1899
return False
1900
else:
1901
value = is_N_position(B)
1902
if value == True:
1903
position_values[B.name()] = "N"
1904
return False
1905
else:
1906
position_values[B.name()] = "P"
1907
return True
1908
1909
#finds all the positions that the current player can choose for her next move that are winners
1910
#includes a "save" function - so that position_values is saved occsionally
1911
1912
def find_reachable_P_positions(B):
1913
reachable = find_reachable_boards(B)
1914
reachable_P = []
1915
1916
for x in reachable:
1917
if is_P_position(x):
1918
reachable_P.append(x)
1919
1920
#can be removed
1921
save(position_values, "position_values.sobj")
1922
1923
return reachable_P
1924
1925
#finds all the positions that the current player can choose for her next move that are losers
1926
def find_reachable_N_positions(B):
1927
reachable = find_reachable_boards(B)
1928
reachable_N = []
1929
1930
for x in reachable:
1931
if not is_P_position(x):
1932
reachable_N.append(x)
1933
1934
return reachable_N
1935
1936
1937
#saves the current position_values dictionary into a file "known_positions.p" in the main chomp directory.
1938
#It will overwrite whatever is currently in the "known_positions.p" file.
1939
def save_position_values():
1940
output = open('known_positions.p', 'wb')
1941
pickle.dump(position_values, output)
1942
output.close()
1943
1944
#stores the contents of "known_position.p" file in the position_values dictionary.
1945
def load_position_values():
1946
global position_values
1947
input = open('known_positions.p', 'rb')
1948
position_values = pickle.load(input)
1949
1950
1951
#Prints out the positions in position_values dictionary in the following format:
1952
#P Positions:
1953
#ChompBoard([r1,r2,...,rn]), ChompBoard([r1,r2,...,rn]),...
1954
#
1955
#
1956
#N Positions:
1957
#ChompBoard([r1,r2,...,rn]), ChompBoard([r1,r2,...,rn]),...
1958
#
1959
#
1960
#A word of caution: sage seems to cut off strings that are too long, so when dealing with a lot of board positions, it may end the string with "[...]". Just remove this and any partial ChompBoard declaration and you should be good.
1961
#Also: the conjecturing program has a maximum object limit so you may need to cut out some of the objects when trying to conjecture with them.
1962
def print_position_values_formatted():
1963
p_out = "P-Positions:\n"
1964
n_out = "N-Positions:\n"
1965
for k, v in position_values.iteritems():
1966
if v == 'P':
1967
p_out += "ChompBoard({}), ".format(k)
1968
elif v == 'N':
1969
n_out += "ChompBoard({}), ".format(k)
1970
print p_out,'\n\n', n_out
1971
1972
#Print P-positions only
1973
def print_P_position_values_formatted():
1974
p_out = "P-Positions:\n"
1975
n_out = "N-Positions:\n"
1976
for k, v in position_values.iteritems():
1977
if v == 'P':
1978
p_out += "ChompBoard({}), ".format(k)
1979
elif v == 'N':
1980
n_out += "ChompBoard({}), ".format(k)
1981
print p_out
1982
1983
#Print N-positions only
1984
def print_N_position_values_formatted():
1985
p_out = "P-Positions:\n"
1986
n_out = "N-Positions:\n"
1987
for k, v in position_values.iteritems():
1988
if v == 'P':
1989
p_out += "ChompBoard({}), ".format(k)
1990
elif v == 'N':
1991
n_out += "ChompBoard({}), ".format(k)
1992
print n_out
1993
1994
import ast
1995
def convert_board_name_to_board(name_of_board):
1996
L = ast.literal_eval(name_of_board)
1997
return ChompBoard(L)
1998
1999
#Pexamples is a list of names of previously computed P positions
2000
Pexamples = [board_name for board_name in position_values if position_values[board_name]=="P"]
2001
2002
#Nexamples is a list of names of previously computed N positions
2003
Nexamples = [board_name for board_name in position_values if position_values[board_name]=="N"]
2004
2005
2006
#Pcounterexamples is a list of names of P-boards that have been counterexamples to conjectures
2007
#initializes to list with only poison-cookie board if load fails
2008
2009
try:
2010
temp = load("Pcounterexamples.sobj")
2011
Pcounterexamples = temp
2012
except:
2013
Pcounterexamples = ["[1]"]
2014
2015
try:
2016
temp = load("Ncounterexamples.sobj")
2017
Ncounterexamples = temp
2018
except:
2019
Ncounterexamples = ["[2]"]
2020
2021
#find a counterexample P-board to a *single* conjecture if one exists among all boards of size no more than
2022
#row_limit x column_limit
2023
#first it checks if any example in Pcounterexamples is already known
2024
#should *not* add duplicates into Pcounterexamples list
2025
2026
def find_Pcounterexample(conj, row_limit, column_limit):
2027
2028
#tests existing P-counterexamples first
2029
for s in Pcounterexamples:
2030
board = convert_board_name_to_board(s)
2031
try:
2032
value = conj.evaluate(board)
2033
if value == False:
2034
#Pcounterexamples.append(board.name())
2035
print "{} is a counterexample to: {}".format(board.name(),conj)
2036
return board
2037
except:
2038
print "error with evaluating: {} for {}".format(conj,board.name())
2039
2040
L = find_reachable_P_positions(ChompBoard([column_limit]*row_limit))
2041
2042
for board in L:
2043
try:
2044
value = conj.evaluate(board)
2045
if value == False and board.name() not in Pcounterexamples:
2046
Pcounterexamples.append(board.name())
2047
print "{} is a counterexample to: {}".format(board.name(),conj)
2048
return board
2049
except:
2050
print "error with evaluating: {} for {}".format(conj,board.name())
2051
2052
print "{}: No counterexamples found".format(conj)
2053
2054
2055
def find_Ncounterexample(conj, row_limit, column_limit):
2056
2057
#tests existing N-counterexamples first
2058
for s in Ncounterexamples:
2059
board = convert_board_name_to_board(s)
2060
try:
2061
value = conj.evaluate(board)
2062
if value == False:
2063
print "{} is a counterexample to: {}".format(board.name(),conj)
2064
return board
2065
except:
2066
print "error with evaluating: {} for {}".format(conj,board.name())
2067
2068
L = find_reachable_N_positions(ChompBoard([column_limit]*row_limit))
2069
2070
for board in L:
2071
try:
2072
value = conj.evaluate(board)
2073
if value == False and board.name() not in Ncounterexamples:
2074
Ncounterexamples.append(board.name())
2075
print "{} is a counterexample to: {}".format(board.name(),conj)
2076
return board
2077
except:
2078
print "error with evaluating: {} for {}".format(conj,board.name())
2079
2080
print "{}: No counterexamples found".format(conj)
2081
2082
#finds Pcounterexamples to a *list* of P-board conjectures
2083
#saves Pcounterexample file
2084
# inefficient: scans position_values and filters Ppositions multiple times - could be written to do this once
2085
2086
def find_Pcounterexamples(conjs, row_limit, column_limit):
2087
2088
for conj in conjs:
2089
find_Pcounterexample(conj, row_limit, column_limit)
2090
2091
save(Pcounterexamples, "Pcounterexamples.sobj")
2092
2093
def find_Ncounterexamples(conjs, row_limit, column_limit):
2094
2095
for conj in conjs:
2096
find_Ncounterexample(conj, row_limit, column_limit)
2097
2098
save(Ncounterexamples, "Ncounterexamples.sobj")
2099
2100
2101
# appends conjectures with n counterexample to new list
2102
def find_p_unique_conjs(conjs, row_limit, column_limit):
2103
pconjs= []
2104
for i in range(len(conjs)): ##Bryan changed this line at 1:13 AM on 5/23/15. Previously it was "for i in [0..len(conjs)-1]:" if I missed some nuance when I changed it, please correct it, but the previous was not compiling.
2105
if find_Ncounterexample(conjs[i],row_limit,column_limit) != []:
2106
pconjs.append(conjs[i])
2107
return pconjs
2108
2109
2110
## SPECIAL OBJECTS
2111
2112
#UCLA's board
2113
ucla = ChompBoard([7,7,7,7])
2114
2115
Nspecial = ["[2]", "[10]", "[3,2,1]", "[4,2]", "[7,2]", "[7,7,7,7]", "[3,2,1,1]", "[3,3,3,3,3,3,3,3,3,3,2]", "[24,13,13,13,13,6]", "[28,25,15]", "[15,15,9,6]", "[2,2,2,2,2,2,2,2,2,2,2,2]"] + Ncounterexamples
2116
2117
Pspecial = ["[2,1]", "[1]", "[5,1,1,1,1]", "[3,2]", "[7,6]", "[100,45,45,45]", "[3,3,3,3,3,3,1,1,1,1,1]", "[24,13,7,7,7,6]", "[28,17,15]", "[15,13,9,6]", "[2,2,2,2,2,2,2,2,2,2,2,1]", "[11,11,10,9,8,8,5,5]"] + Pcounterexamples
2118
2119
2120
2121