Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/games/hexad.py
4057 views
1
r"""
2
Hexads in S(5,6,12)
3
4
This module completes a 5-element subset of as 12-set X
5
into a hexad in a Steiner system S(5,6,12) using Curtis and
6
Conway's "kitten method". The labeling is either the
7
"modulo 11" labeling or the "shuffle" labeling.
8
9
The main functions implemented in this file are
10
blackjack_move and find_hexad. Enter "blackjack_move?"
11
for help to play blackjack (i.e., the rules of the game), or
12
"find_hexad?" for help finding hexads of S(5,6,12) in the
13
shuffle labeling.
14
15
This picture is the kitten in the "shuffle" labeling:
16
17
18
6
19
20
9
21
22
10 8
23
24
7 2 5
25
26
9 4 11 9
27
28
10 8 3 10 8
29
30
1 0
31
32
33
The corresponding MINIMOG is
34
35
_________________
36
| 6 | 3 | 0 | 9 |
37
|---|---|---|---|
38
| 5 | 2 | 7 | 10 |
39
|---|---|---|---|
40
| 4 | 1 | 8 | 11 |
41
|___|____|___|____|
42
43
which is specified by the global variable "minimog_shuffle".
44
See the docstrings for find_hexad and blackjack_move for
45
further details and examples.
46
47
AUTHOR::
48
David Joyner (2006-05)
49
50
REFERENCES::
51
R. Curtis, ``The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$,
52
and the kitten,'' in {\bf Computational group theory}, ed. M. Atkinson,
53
Academic Press, 1984.
54
J. Conway, ``Hexacode and tetracode - MINIMOG and MOG,'' in {\bf Computational
55
group theory}, ed. M. Atkinson, Academic Press, 1984.
56
J. Conway and N. Sloane, ``Lexicographic codes: error-correcting codes from
57
game theory,'' IEEE Trans. Infor. Theory32(1986)337-348.
58
J. Kahane and A. Ryba, ``The hexad game,'' Electronic Journal of Combinatorics, 8 (2001)
59
http://www.combinatorics.org/Volume_8/Abstracts/v8i2r11.html
60
61
Some details are also online at: http://www.permutationpuzzles.org/hexad/
62
63
"""
64
#*****************************************************************************
65
# Copyright (C) 2005 David Joyner <[email protected]>
66
#
67
# Distributed under the terms of the GNU General Public License (GPL),
68
# version 2 or later (at your choice)
69
#
70
# http://www.gnu.org/licenses/
71
#*****************************************************************************
72
73
from sage.rings.infinity import Infinity
74
from sage.matrix.matrix_space import MatrixSpace
75
from sage.rings.rational_field import RationalField
76
QQ = RationalField()
77
infinity = Infinity
78
from sage.rings.finite_rings.constructor import FiniteField
79
GF = FiniteField
80
from sage.calculus.calculus import SR
81
#SR = SymbolicRing()
82
83
def view_list(L):
84
"""
85
This provides a printout of the lines, crosses and squares of the MINIMOG,
86
as in Curtis' paper.
87
88
EXAMPLES::
89
sage: from sage.games.hexad import *
90
sage: M = Minimog(type="shuffle")
91
sage: view_list(M.line[1])
92
<BLANKLINE>
93
[0 0 0]
94
[1 1 1]
95
[0 0 0]
96
sage: view_list(M.cross[1])
97
<BLANKLINE>
98
[1 1 1]
99
[0 0 1]
100
[0 0 1]
101
sage: view_list(M.square[1])
102
<BLANKLINE>
103
[0 0 0]
104
[1 1 0]
105
[1 1 0]
106
107
"""
108
MS = MatrixSpace(QQ,3,3)
109
box = [(0,0),(0,1),(0,2),(1,0),(1,1),(1,2),(2,0),(2,1),(2,2)]
110
A = MS([[0 for i in range(3)] for i in range(3)])
111
for x in box:
112
if x in L:
113
A[x] = 1
114
return A
115
116
def picture_set(A,L):
117
"""
118
This is needed in the find_hexad function below.
119
120
EXAMPLES::
121
sage: from sage.games.hexad import *
122
sage: M = Minimog(type="shuffle")
123
sage: picture_set(M.picture00, M.cross[2])
124
set([8, 9, 10, 5, 7])
125
sage: picture_set(M.picture02, M.square[7])
126
set([8, 2, 3, 5])
127
128
"""
129
return set([A[x] for x in L])
130
131
class Minimog():
132
"""
133
This implements the Conway/Curtis minimog idea for describing the Steiner
134
triple system S(5,6,12).
135
136
EXAMPLES::
137
sage: from sage.games.hexad import *
138
sage: Minimog(type="shuffle")
139
Minimog of type shuffle
140
sage: M = Minimog(type = "modulo11")
141
sage: M.minimog
142
[ 0 3 +Infinity 2]
143
[ 5 9 8 10]
144
[ 4 1 6 7]
145
146
"""
147
def __init__(self, type="shuffle"):
148
self.type = type
149
MS34 = MatrixSpace(SR,3,4)
150
minimog_modulo11 = MS34([[0,3,infinity,2],[5,9,8,10],[4,1,6,7]])
151
minimog_shuffle = MS34([[6,3,0,9],[5,2,7,10],[4,1,8,11]])
152
if type == "shuffle":
153
self.minimog = minimog_shuffle
154
elif type == "modulo11":
155
self.minimog = minimog_modulo11
156
else:
157
raise ValueError, "That Minimog type is not implemented."
158
# This initializes the variables in the game.
159
MS34 = MatrixSpace(SR,3,4)
160
A = self.minimog
161
MS33 = MatrixSpace(SR,3,3)
162
self.picture00 = MS33([[A[(1,0)],A[(2,3)],A[(0,1)]],[A[(2,2)],A[(1,1)],A[(2,0)]],[A[(0,3)],A[(1,3)],A[(1,2)]]])
163
####### self.picture00 is the "picture at 6"
164
self.picture02 = MS33([[A[(1,0)],A[(2,3)],A[(0,1)]],[A[(1,1)],A[(2,0)],A[(2,2)]],[A[(1,2)],A[(0,3)],A[(1,3)]]])
165
####### self.picture02 is the "picture at 1"
166
self.picture21 = MS33([[A[(2,2)],A[(1,3)],A[(0,1)]],[A[(0,3)],A[(2,3)],A[(2,0)]],[A[(1,0)],A[(1,1)],A[(1,2)]]])
167
####### self.picture21 is the "picture at 0"
168
169
self.line = [set([]) for i in range(12)]
170
self.line[0] = set([(0,0),(0,1),(0,2)])
171
self.line[1] = set([(1,0),(1,1),(1,2)])
172
self.line[2] = set([(2,0),(2,1),(2,2)])
173
self.line[3] = set([(0,2),(1,2),(2,2)])
174
self.line[4] = set([(0,1),(1,1),(2,1)])
175
self.line[5] = set([(0,0),(1,0),(2,0)])
176
self.line[6] = set([(0,0),(1,1),(2,2)])
177
self.line[7] = set([(2,0),(0,1),(1,2)])
178
self.line[8] = set([(0,2),(1,0),(2,1)])
179
self.line[9] = set([(2,0),(1,1),(0,2)])
180
self.line[10] = set([(0,0),(1,2),(2,1)])
181
self.line[11] = set([(1,0),(0,1),(2,2)])
182
183
self.cross = [set([]) for i in range(18)]
184
self.cross[0] = set([(0,0),(0,1),(0,2),(1,0),(2,0)])
185
self.cross[1] = set([(0,0),(0,1),(0,2),(1,2),(2,2)])
186
self.cross[2] = set([(0,0),(1,0),(2,0),(2,1),(2,2)])
187
self.cross[3] = set([(2,0),(2,1),(2,2),(0,2),(1,2)])
188
self.cross[4] = set([(0,0),(0,1),(0,2),(1,1),(2,1)])
189
self.cross[5] = set([(0,0),(1,0),(2,0),(1,1),(1,2)])
190
self.cross[6] = set([(1,0),(1,1),(1,2),(0,2),(2,2)])
191
self.cross[7] = set([(0,1),(1,1),(2,1),(2,0),(2,2)])
192
self.cross[8] = set([(0,0),(0,1),(1,0),(1,1),(2,2)])
193
self.cross[9] = set([(0,0),(1,1),(1,2),(2,1),(2,2)])
194
self.cross[10] = set([(2,0),(2,1),(1,0),(1,1),(0,2)])
195
self.cross[11] = set([(0,1),(0,2),(1,1),(1,2),(2,0)])
196
self.cross[12] = set([(0,0),(1,0),(0,2),(1,2),(2,1)])
197
self.cross[13] = set([(1,0),(0,1),(0,2),(2,1),(2,2)])
198
self.cross[14] = set([(0,1),(1,0),(1,2),(2,0),(2,2)])
199
self.cross[15] = set([(0,0),(0,1),(1,2),(2,0),(2,1)])
200
self.cross[16] = set([(1,0),(1,1),(1,2),(0,1),(2,1)])
201
self.cross[17] = set([(0,0),(0,2),(1,1),(2,0),(2,2)])
202
self.box = set([(i,j) for i in range(3) for j in range(3)])
203
self.square = [set([]) for i in range(18)]
204
for i in range(18):
205
self.square[i] = self.box - self.cross[i]
206
207
MS34_GF3 = MatrixSpace(GF(3),3,4)
208
self.col1 = MS34_GF3([[1,0,0,0],[1,0,0,0],[1,0,0,0]])
209
self.col2 = MS34_GF3([[0,1,0,0],[0,1,0,0],[0,1,0,0]])
210
self.col3 = MS34_GF3([[0,0,1,0],[0,0,1,0],[0,0,1,0]])
211
self.col4 = MS34_GF3([[0,0,0,1],[0,0,0,1],[0,0,0,1]])
212
213
self.tet1 = MS34_GF3([[1,1,1,1],[0,0,0,0],[0,0,0,0]])
214
self.tet2 = MS34_GF3([[1,0,0,0],[0,1,1,1],[0,0,0,0]])
215
self.tet3 = MS34_GF3([[1,0,0,0],[0,0,0,0],[0,1,1,1]])
216
self.tet4 = MS34_GF3([[0,1,0,0],[1,0,1,0],[0,0,0,1]])
217
self.tet5 = MS34_GF3([[0,0,0,1],[1,1,0,0],[0,0,1,0]])
218
self.tet6 = MS34_GF3([[0,0,1,0],[1,0,0,1],[0,1,0,0]])
219
self.tet7 = MS34_GF3([[0,1,0,0],[0,0,0,1],[1,0,1,0]])
220
self.tet8 = MS34_GF3([[0,0,1,0],[0,1,0,0],[1,0,0,1]])
221
self.tet9 = MS34_GF3([[0,0,0,1],[0,0,1,0],[1,1,0,0]])
222
self.col = [ self.col1, self.col2, self.col3, self.col4]
223
self.tet = [ self.tet1, self.tet2, self.tet3, self.tet4, self.tet5, self.tet6, self.tet7, self.tet8, self.tet9]
224
# return picture00,picture02,picture21,line,cross,square,col,tet
225
226
def __repr__(self):
227
return "Minimog of type %s"%self.type
228
229
def __str__(self):
230
"""
231
232
EXAMPLES::
233
sage: M = Minimog(type="modulo11")
234
sage: print M
235
Minimog of type modulo11 associated to
236
[ 0 3 +Infinity 2]
237
[ 5 9 8 10]
238
[ 4 1 6 7]
239
240
"""
241
return "Minimog of type %s associated to\n %s"%(self.type,self.minimog)
242
243
def _latex_(self):
244
"""
245
Prints latex code.
246
247
EXAMPLES::
248
sage: M = Minimog(type="modulo11")
249
sage: latex(M)
250
Minimog of type modulo11 associated to
251
$\left(\begin{array}{rrrr}
252
0 & 3 & +\infty & 2 \\
253
5 & 9 & 8 & 10 \\
254
4 & 1 & 6 & 7
255
\end{array}\right)$
256
"""
257
from sage.misc.latex import latex
258
return "Minimog of type %s associated to\n $%s$"%(self.type, latex(self.minimog))
259
260
def print_kitten(self):
261
"""
262
This simply prints the "kitten" (expressed as a triangular diagram
263
of symbols).
264
265
EXAMPLES::
266
sage: from sage.games.hexad import *
267
sage: M = Minimog("shuffle")
268
sage: M.print_kitten()
269
0
270
<BLANKLINE>
271
8
272
9 10
273
5 11 3
274
8 2 4 8
275
9 10 7 9 10
276
<BLANKLINE>
277
6 1
278
sage: M = Minimog("modulo11")
279
sage: M.print_kitten()
280
+Infinity
281
<BLANKLINE>
282
6
283
2 10
284
5 7 3
285
6 9 4 6
286
2 10 8 2 10
287
<BLANKLINE>
288
0 1
289
290
"""
291
MINIMOG = self.minimog
292
Kitten1 = [' ',' ',' ',' ',' ',' ',' ',' ',' ',str(MINIMOG[0][2]),' ',' ',' ',' ',' ']
293
Kitten2 = [' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ']
294
Kitten3 = [' ',' ',' ',' ',' ',' ',' ',' ',' ',str(MINIMOG[2][2]),' ',' ',' ',' ',' ']
295
Kitten4 = [' ',' ',' ',' ',' ',' ',' ',str(MINIMOG[0][3]),' ',' ',str(MINIMOG[1][3]),' ',' ',' ',' ']
296
Kitten5 = [' ',' ',' ',' ',' ',' ',str(MINIMOG[1][0]),' ',' ',str(MINIMOG[2][3]),' ',' ',str(MINIMOG[0][1]),' ',' ',' ']
297
Kitten6 = [' ',' ',' ',' ',' ',str(MINIMOG[2][2]),' ',' ',str(MINIMOG[1][1]),' ',' ',str(MINIMOG[2][0]),' ',' ',str(MINIMOG[2][2]),' ',' ']
298
Kitten7 = [' ',' ',' ',str(MINIMOG[0][3]),' ',' ',str(MINIMOG[1][3]),' ',' ',str(MINIMOG[1][2]),' ',' ',str(MINIMOG[0][3]),' ',' ',str(MINIMOG[1][3]),' ']
299
Kitten8 = [' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ']
300
Kitten9 = [str(MINIMOG[0][0]),' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',str(MINIMOG[2][1])]
301
Kitten = [Kitten1, Kitten2, Kitten3, Kitten4, Kitten5, Kitten6, Kitten7, Kitten8, Kitten9]
302
kitten = "".join(Kitten1)+"\n"+"".join(Kitten2)+"\n"+"".join(Kitten3)+"\n"+"".join(Kitten4)+"\n"+"".join(Kitten5)+"\n"+"".join(Kitten6)+"\n"+"".join(Kitten7)+"\n"+"".join(Kitten8)+"\n"+"".join(Kitten9)
303
print kitten
304
305
def find_hexad0(self, pts):
306
"""
307
INPUT::
308
pts -- a set of 2 distinct elements of MINIMOG, but not
309
including the "points at infinity"
310
OUTPUT::
311
hexad containing pts and of type 0 (the 3 points "at infinity" union a line)
312
313
NOTE:: 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]}
314
315
EXAMPLES::
316
sage: from sage.games.hexad import *
317
sage: M = Minimog(type="shuffle")
318
sage: M.find_hexad0(set([2,4]))
319
([0, 1, 2, 4, 6, 8], ['line 1', 'picture 1'])
320
321
"""
322
MINIMOG = self.minimog
323
L = set(pts)
324
H = set([MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]])
325
for i in range(12):
326
if L <= picture_set(self.picture02,self.line[i]):
327
WHAT = ["line "+str(i),"picture "+str(1)]
328
H = H | picture_set(self.picture02,self.line[i])
329
return list(H),WHAT
330
if L <= picture_set(self.picture21,self.line[i]):
331
WHAT = ["line "+str(i),"picture "+str(0)]
332
H = H | picture_set(self.picture21,self.line[i])
333
return list(H),WHAT
334
if L <= picture_set(self.picture00,self.line[i]):
335
WHAT = ["line "+str(i),"picture "+str(6)]
336
H = H | picture_set(self.picture00,self.line[i])
337
return list(H),WHAT
338
return [],[]
339
340
def find_hexad1(self, pts):
341
"""
342
INPUT::
343
pts -- a set pts of 5 distinct elements of MINIMOG
344
OUTPUT::
345
hexad containing pts and of type 1 (union of 2 parallel lines -- *no*
346
points "at infinity")
347
348
NOTE:: 3 points "at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]}
349
350
EXAMPLES::
351
sage: from sage.games.hexad import *
352
sage: M = Minimog(type="shuffle")
353
sage: M.find_hexad1(set([2,3,4,5,8]))
354
([2, 3, 4, 5, 8, 11], ['lines (1, 2)', 'picture 1'])
355
356
"""
357
H = set(pts)
358
L = set(pts)
359
linez = [(1,2),(1,3),(2,3),(4,5),(4,6),(5,6),(7,8),(7,9),(8,9),(10,11),(10,12),(11,12)]
360
for x in linez:
361
x1 = int(x[0]-1)
362
x2 = int(x[1]-1) ## (recall | is union)
363
if L <= (picture_set(self.picture02,self.line[x1]) | picture_set(self.picture02,self.line[x2])):
364
WHAT = ["lines "+str(x),"picture "+str(1)]
365
H = picture_set(self.picture02,self.line[x1]) | picture_set(self.picture02,self.line[x2])
366
return list(H),WHAT
367
if L <= (picture_set(self.picture21,self.line[x1]) | picture_set(self.picture21,self.line[x2])):
368
WHAT = ["lines "+str(x),"picture "+str(0)]
369
H = picture_set(self.picture21,self.line[x1]) | picture_set(self.picture21,self.line[x2])
370
return list(H),WHAT
371
if L <= (picture_set(self.picture00,self.line[x1]) | picture_set(self.picture00,self.line[x2])):
372
WHAT = ["lines "+str(x),"picture "+str(6)]
373
H = picture_set(self.picture00,self.line[x1]) | picture_set(self.picture00,self.line[x2])
374
return list(H),WHAT
375
return [],[]
376
377
def find_hexad2(self, pts, x0):
378
"""
379
INPUT::
380
pts -- a list S of 4 elements of MINIMOG, not including
381
any "points at infinity"
382
x0 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]}
383
384
OUTPUT::
385
hexad containing S \union \{x0\} of type 2
386
387
EXAMPLES::
388
sage: from sage.games.hexad import *
389
sage: M = Minimog(type="shuffle")
390
sage: M.find_hexad2([2,3,4,5],1)
391
([], [])
392
393
The above output indicates that there is no hexad of type 2
394
containing {2,3,4,5}. However, there is one containing {2,3,4,8}:
395
396
sage: M.find_hexad2([2,3,4,8],0)
397
([0, 2, 3, 4, 8, 9], ['cross 12', 'picture 0'])
398
399
"""
400
MINIMOG = self.minimog
401
L = set(pts)
402
H = set([x0])
403
for i in range(18):
404
if (x0 == MINIMOG[2][1] and L <= picture_set(self.picture02,self.cross[i])):
405
WHAT = ["cross "+str(i),"picture "+str(1)]
406
H = H | picture_set(self.picture02,self.cross[i])
407
return list(H),WHAT
408
if (x0 == MINIMOG[0][2] and L <= picture_set(self.picture21,self.cross[i])):
409
WHAT = ["cross "+str(i),"picture "+str(MINIMOG[0][2])]
410
H = H | picture_set(self.picture21,self.cross[i])
411
return list(H),WHAT
412
if (x0 == MINIMOG[0][0] and L <= picture_set(self.picture00,self.cross[i])):
413
WHAT = ["cross "+str(i),"picture "+str(6)]
414
H = H | picture_set(self.picture00,self.cross[i])
415
return list(H),WHAT
416
return [],[]
417
418
def find_hexad3(self, pts, x0, x1):
419
"""
420
INPUT::
421
pts -- a list of 3 elements of MINIMOG, not including
422
any "points at infinity"
423
x0,x1 -- in {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]}
424
425
OUTPUT::
426
hexad containing pts \union \{x0,x1\} of type 3 (square at
427
picture of "omitted point at infinity")
428
429
EXAMPLES::
430
sage: from sage.games.hexad import *
431
sage: M = Minimog(type="shuffle")
432
sage: M.find_hexad3([2,3,4],0,1)
433
([0, 1, 2, 3, 4, 11], ['square 2', 'picture 6'])
434
435
"""
436
MINIMOG = self.minimog
437
L = set(pts)
438
H = set([x0,x1])
439
for i in range(18):
440
if (not (MINIMOG[0][2] in H) and L <= picture_set(self.picture21,self.square[i])):
441
WHAT = ["square "+str(i),"picture "+str(MINIMOG[0][2])]
442
H = H | picture_set(self.picture21,self.square[i])
443
return list(H),WHAT
444
if (not (MINIMOG[2][1] in H) and L <= picture_set(self.picture02,self.square[i])):
445
WHAT = ["square "+str(i),"picture "+str(MINIMOG[2][1])]
446
H = H | picture_set(self.picture02,self.square[i])
447
return list(H),WHAT
448
if (not (MINIMOG[0][0] in H) and L <= picture_set(self.picture00,self.square[i])):
449
WHAT = ["square "+str(i),"picture "+str(MINIMOG[0][0])]
450
H = H | picture_set(self.picture00,self.square[i])
451
return list(H),WHAT
452
return [],[]
453
454
def find_hexad(self, pts):
455
"""
456
INPUT::
457
pts -- a list S of 5 elements of MINIMOG
458
459
OUTPUT::
460
hexad containing S \union \{x0\} of some type
461
462
NOTE:: 3 "points at infinity" = {MINIMOG[0][2], MINIMOG[2][1], MINIMOG[0][0]}
463
464
Theorem (Curtis, Conway): Each hexads is of exactly one of the following types:
465
0. $\{3 ``points at infinity''\}\cup \{{\rm any\ line}\}$,
466
1. the union of any two (distinct) parallel lines in the same picture,
467
2. one ``point at infinity'' union a cross in the corresponding picture,
468
3. two ``points at infinity'' union a square in the picture corresponding
469
to the omitted point at infinity.
470
More precisely, there are 132 such hexads (12 of type 0, 12 of type 1, 54 of type 2,
471
and 54 of type 3). They form a Steiner system of type $(5,6,12)$.
472
473
EXAMPLES::
474
sage: from sage.games.hexad import *
475
sage: M = Minimog(type="shuffle")
476
sage: M.find_hexad([0,1,2,3,4])
477
([0, 1, 2, 3, 4, 11], ['square 2', 'picture 6'])
478
sage: M.find_hexad([1,2,3,4,5])
479
([1, 2, 3, 4, 5, 6], ['square 8', 'picture 0'])
480
sage: M.find_hexad([2,3,4,5,8])
481
([2, 3, 4, 5, 8, 11], ['lines (1, 2)', 'picture 1'])
482
sage: M.find_hexad([0,1,2,4,6])
483
([0, 1, 2, 4, 6, 8], ['line 1', 'picture 1'])
484
sage: M = Minimog(type="modulo11")
485
sage: M.find_hexad([1,2,3,4,SR(infinity)]) # random (machine dependent?) order
486
([+Infinity, 2, 3, 4, 1, 10], ['square 8', 'picture 0'])
487
488
AUTHOR::
489
David Joyner (2006-05)
490
491
REFERENCES::
492
R. Curtis, ``The Steiner system $S(5,6,12)$, the Mathieu group $M_{12}$,
493
and the kitten,'' in {\bf Computational group theory}, ed. M. Atkinson,
494
Academic Press, 1984.
495
J. Conway, ``Hexacode and tetracode - MINIMOG and MOG,'' in {\bf Computational
496
group theory}, ed. M. Atkinson, Academic Press, 1984.
497
498
"""
499
MINIMOG = self.minimog
500
L = set(pts)
501
LL = L.copy()
502
## recall & means intersection
503
L2 = LL & set([MINIMOG[0][2],MINIMOG[2][1],MINIMOG[0][0]])
504
if len(L2) == 3: ## must be type 0 (line + pts at infty)
505
H,WHAT = self.find_hexad0(LL - set([MINIMOG[0][2],MINIMOG[2][1],MINIMOG[0][0]]))
506
return H,WHAT
507
if len(L2) == 2: ## type 0 or 3
508
if (MINIMOG[0][2] in LL and MINIMOG[2][1] in LL):
509
H,WHAT = self.find_hexad3(LL - set([MINIMOG[0][2],MINIMOG[2][1]]),MINIMOG[0][2],MINIMOG[2][1])
510
if H != []: # must be type 3
511
return list(H),WHAT
512
if H == []: ## could be type 0
513
H,WHAT = self.find_hexad0(LL - L2)
514
if H != []: # must be type 0
515
return list(H),WHAT
516
if (MINIMOG[2][1] in LL and MINIMOG[0][0] in LL):
517
H,WHAT = self.find_hexad3(LL - set([MINIMOG[2][1],MINIMOG[0][0]]),MINIMOG[2][1],MINIMOG[0][0])
518
if H != []: # must be type 3
519
return list(H),WHAT
520
if H == []: ## could be type 0
521
H,WHAT = self.find_hexad0(LL - L2)
522
if H != []: # must be type 0
523
return list(H),WHAT
524
if (MINIMOG[0][2] in LL and MINIMOG[0][0] in LL):
525
H,WHAT = self.find_hexad3(LL - set([MINIMOG[0][2],MINIMOG[0][0]]),MINIMOG[0][2],MINIMOG[0][0])
526
if H != []: # must be type 3
527
return list(H),WHAT
528
if H == []: ## could be type 0
529
H,WHAT = self.find_hexad0(LL - L2)
530
if H != []: # must be type 0
531
return list(H),WHAT
532
if len(L2) == 1:
533
H,WHAT = self.find_hexad2(LL - L2,list(L2)[0])
534
if H == []: ## not a cross in picture at infinity
535
if list(L2)[0] == MINIMOG[2][1]:
536
L1 = LL - L2
537
H,WHAT = self.find_hexad3(L1,MINIMOG[0][0],MINIMOG[2][1])
538
if H <> []:
539
return list(H),WHAT
540
L1 = LL - L2
541
H,WHAT = self.find_hexad3(L1,MINIMOG[0][2],MINIMOG[2][1])
542
if H <> []:
543
return list(H),WHAT
544
if list(L2)[0] == MINIMOG[0][0]:
545
L1 = (LL - L2)
546
H,WHAT = self.find_hexad3(L1,MINIMOG[0][0],MINIMOG[2][1])
547
if H <> []:
548
return list(H),WHAT
549
L1 = (LL - L2)
550
H,WHAT = self.find_hexad3(L1,MINIMOG[0][0],MINIMOG[0][2])
551
if H <> []:
552
return list(H),WHAT
553
if list(L2)[0] == MINIMOG[0][2]:
554
L1 = (LL - L2)
555
H,WHAT = self.find_hexad3(L1,MINIMOG[0][0],MINIMOG[0][2])
556
if H <> []:
557
return list(H),WHAT
558
L1 = (LL - L2)
559
H,WHAT = self.find_hexad3(L1,MINIMOG[2][1],MINIMOG[0][2])
560
if H <> []:
561
return list(H),WHAT
562
return list(H),WHAT
563
## a cross in a pic at infty
564
if len(L2) == 0: ## L is either a union of 2 lines or a cross
565
for i in LL:
566
for j in [MINIMOG[0][2],MINIMOG[2][1],MINIMOG[0][0]]:
567
H,WHAT = self.find_hexad2(LL - set([i]),j)
568
if (H != [] and i in H):
569
return list(H),WHAT ## L is in a cross
570
H,WHAT = self.find_hexad1(LL) ## L is a union of lines
571
return H,WHAT
572
573
def blackjack_move(self, L0):
574
"""
575
L is a list of cards of length 6, taken from {0,1,...,11}.
576
577
Mathematical blackjack::
578
Mathematical blackjack is played with 12 cards, labeled $0,...,11$
579
(for example: king, ace, $2$, $3$, ..., $10$, jack, where the king is
580
$0$ and the jack is $11$). Divide the 12 cards into two piles of $6$ (to be
581
fair, this should be done randomly). Each of the $6$ cards of one of these
582
piles are to be placed face up on the table. The remaining cards are in a
583
stack which is shared and visible to both players. If the sum of the cards
584
face up on the table is less than 21 then no legal move is possible so you must
585
shuffle the cards and deal a new game. (Conway calls such a game *={0|0},
586
where 0={|}; in this game the first player automatically wins.)
587
588
* Players alternate moves.
589
* A move consists of exchanging a card on the table with a lower card from the other pile.
590
* The player whose move makes the sum of the cards on the table under 21 loses.
591
592
The winning strategy (given below) for this game is due to Conway and Ryba.
593
There is a Steiner system $S(5,6,12)$ of hexads in the set $\{0,1,...,11\}$.
594
This Steiner system is associated to the MINIMOG of in the "shuffle numbering"
595
rather than the "modulo $11$ labeling".
596
597
Proposition (Ryba, Conway) For this Steiner system, the winning strategy is to choose a
598
move which is a hexad from this system.
599
600
601
EXAMPLES::
602
sage: M = Minimog(type="modulo11")
603
sage: M.blackjack_move([0,2,3,6,1,10])
604
'6 --> 5. The total went from 22 to 21.'
605
sage: M = Minimog(type="shuffle")
606
sage: M.blackjack_move([0,2,4,6,7,11])
607
'4 --> 3. The total went from 30 to 29.'
608
609
Is this really a hexad?
610
611
sage: M.find_hexad([11,2,3,6,7])
612
([0, 2, 3, 6, 7, 11], ['square 9', 'picture 1'])
613
614
So, yes it is, but here is further confirmation:
615
616
sage: M.blackjack_move([0,2,3,6,7,11])
617
This is a hexad.
618
There is no winning move, so make a random legal move.
619
[0, 2, 3, 6, 7, 11]
620
621
Now, suppose player 2 replaced the 11 by a 9. Your next move:
622
623
sage: M.blackjack_move([0,2,3,6,7,9])
624
'7 --> 1. The total went from 27 to 21.'
625
626
You have now won. Sage will even tell you so:
627
628
sage: M.blackjack_move([0,2,3,6,1,9])
629
'No move possible. Shuffle the deck and redeal.'
630
631
AUTHOR::
632
David Joyner (2006-05)
633
634
REFERENCES::
635
J. Conway and N. Sloane, "Lexicographic codes: error-correcting codes from
636
game theory,'' IEEE Trans. Infor. Theory32(1986)337-348.
637
J. Kahane and A. Ryba, "The hexad game,'' Electronic Journal of Combinatorics, 8 (2001)
638
http://www.combinatorics.org/Volume_8/Abstracts/v8i2r11.html
639
640
"""
641
MINIMOG = self.minimog
642
total = sum(L0)
643
if total <22:
644
return "No move possible. Shuffle the deck and redeal."
645
L = set(L0)
646
for x in L:
647
h,WHAT = self.find_hexad(L - set([x]))
648
if list(L0) == list(h):
649
print " This is a hexad. \n There is no winning move, so make a random legal move."
650
return L0
651
y = list(set(h) - (L - set([x])))[0]
652
#print x,y,h
653
if y < x:
654
return str(x) +' --> '+str(y)+". The total went from "+ str(total) +" to "+str(total-x+y)+"."
655
print "This is a hexad. \n There is no winning move, so make a random legal move."
656
return L0
657
658
659
660
661