<Grundy number>
Grundy 数, Gi,j, は次の 'Corner the Queen' ゲームなどで重要な役割を果たす数で, ゲーム盤のマス目に付属する量です。次のように定義すると |
<Task>
ここの課題は、与えられたゲーム盤のすべてのマス目について Gi,j を計算することです。 やり方は queen2 に出ています。まず左の式が Gi,j についての一次式であることを認識します。順番をうまく取ればスーッと答えが出ます。 |
Table of Grundy numbers (zeros are stressed) | |
CornerTheQueen.Py
|
CornerTheQueen.MOD
|
Source codes | |
<Python (Object Oriented Programming)> [Main] Main_CornerTheQueen.py [Module] CornerTheQueen.py# Corner The Queen, 8-25-2023 from scipy import * import numpy as np import matplotlib.pyplot as plt import CornerTheQueen as CQ print('\x1b[38;2;5;86;243m'+'Queen'+'\x1b[0m') #blue print('\x1b[38;2;255;0;0m'+'Queen'+'\x1b[0m') #red print() isDn = False pr = CQ.calcGrundy(9) print(pr) print() pr.outGr(isDn) # Corner The Queen, 8-25-2023 # gives Grundy numbers for the game of "Corner The Queen" import numpy as np boardSize = 31 maxMember = 2*boardSize toChk = False def intToStr(i,n): s = str(i) le = len(s) while le<n: s = " " + s le += 1 return s def sumLists(a, b, c): p=[] for q in a: p.append(q) for q in b: p.append(q) for q in c: p.append(q) p.sort() return p def mex(gList): wList = [] for i in range(maxMember): wList.append(i) if toChk: print('wholeList=',wList) for p in gList: if wList.count(p)>0: wList.remove(p) else: if toChk: print(p," is not in list") if toChk: print('work list=',wList) k = 0 while(True): if wList.count(k)>0: # print('min=',k) break k += 1 if k>maxMember: k=-1 # strange result! break return k class calcGrundy: def __init__(self, N): self.Gr = np.zeros((boardSize,boardSize),dtype=int) self.N = N def moveH(x,y): mySet = [] for xx in range(x): mySet.append(self.Gr[xx,y]) return mySet def moveV(x,y): mySet = [] for yy in range(y): mySet.append(self.Gr[x,yy]) return mySet def moveT(x,y): mySet = [] tn = min(x,y) for tt in range(tn): mySet.append(self.Gr[x-tn+tt,y-tn+tt]) return mySet for z in range(N): self.Gr[z,0] = z self.Gr[0,z] = z ######## Execution starts here ######## for n in range(N-1): nn = n + 1 # nn=1..N-1 for x in range(nn): xSet = sumLists(moveH(x,nn), moveV(x,nn), moveT(x,nn)) self.Gr[x,nn] = mex(xSet) for y in range(nn): ySet = sumLists(moveH(nn,y), moveV(nn,y), moveT(nn,y)) self.Gr[nn,y] = mex(ySet) tSet = sumLists(moveH(nn,nn), moveV(nn,nn), moveT(nn,nn)) self.Gr[nn,nn] = mex(tSet) ####### Execution finished here ######## ####### Output of Grundy values ######## print('Grundy values for board size = ', N) for j in range(N): for i in range(N): print(" ",self.Gr[i,j],end="") print() print() ######## End of Grundy value out ######## ######## Methods ########## def outGr(self,isDn): sR0 = '\x1b[38;2;255;0;0m' sR1 = '\x1b[0m' print('Grundy values for board size = ', self.N) print('----------------------------------------') def printArray(j): print(intToStr(j,3),"] ", end="") for i in range(self.N): w = self.Gr[i,j] s = intToStr(w,3) if w==0: s = sR0 + s + sR1 print(s,end="") print() if isDn: print(' ',end="") for i in range(self.N): s = intToStr(i,3) print(s,end="") print() print('----------------------------------------') for j in range(self.N): printArray(j) else: for j in range(self.N): jj=self.N - 1 - j printArray(jj) print('----------------------------------------') print(' ',end="") for i in range(self.N): s = intToStr(i,3) print(s,end="") print() |
<Modula-2 (Structured Programming)>
[MAIN] CornerTheQueen.MOD [SUB] SubQueenGame.MOD・・・ BEGIN openTextWin(W1,'Graphic Application'); initXDSgraph(_big); prepareWholeSet(); WrStr(' Calculating Grundy values for maximum board size, '); WrInt(_boardSize,1); WrLn; initGrundy(Gr); calcGrundy(Gr); listOfZeros(); ・・・ PROCEDURE mex(Set: gSetTp): INTEGER; VAR i: INTEGER; BEGIN prepareWholeSet(); minComplementSet(Set,i); RETURN i; END mex; PROCEDURE moveH(x,y: INTEGER): gSetTp; VAR xx: INTEGER; mySet : gSetTp; BEGIN mySet := gSetTp{}; FOR xx:=0 TO x-1 DO INCL(mySet, Gr[xx,y]); END; RETURN mySet; END moveH; PROCEDURE moveV(x,y: INTEGER): gSetTp; VAR yy: INTEGER; mySet : gSetTp; BEGIN mySet := gSetTp{}; FOR yy:=0 TO y-1 DO INCL(mySet, Gr[x,yy]); END; RETURN mySet; END moveV; PROCEDURE moveT(x,y: INTEGER): gSetTp; VAR tt,tn : INTEGER; mySet : gSetTp; BEGIN mySet := gSetTp{}; tn := min(x,y); FOR tt:= 0 TO tn-1 DO INCL(mySet, Gr[x-tn+tt,y-tn+tt]); END; RETURN mySet; END moveT; PROCEDURE calcGrundy(VAR Gr: grundyTp); VAR x,y,z,n,xx,yy,N: INTEGER; mySet : gSetTp; BEGIN N := _boardSize; Gr[0,0]:= 0; numA:= 0; numB:= 0; FOR n:=1 TO N-1 DO (* circumference*) FOR x:=0 TO n-1 DO mySet := moveH(x,n) + moveV(x,n) + moveT(x,n); Gr[x,n]:= mex(mySet); IF Gr[x,n]=0 THEN IF x<n THEN zeroA[numA].x:= x; zeroA[numA].y:= n; INC(numA); ELSE zeroB[numB].x:= x; zeroB[numB].y:= n; INC(numB); END; END; END; FOR y:=0 TO n-1 DO mySet := moveH(n,y) + moveV(n,y) + moveT(n,y); Gr[n,y]:= mex(mySet); IF Gr[n,y]=0 THEN IF n<y THEN zeroA[numA].x:= n; zeroA[numA].y:= y; INC(numA); ELSE zeroB[numB].x:= n; zeroB[numB].y:= y; INC(numB); END; END; mySet := moveH(n,n) + moveV(n,n) + moveT(n,n); Gr[n,n]:=mex(mySet); IF Gr[n,n]=0 THEN WinAuxIO.hitKey('Zero in diagonal posision, OK?'); END; END; END calcGrundy; |