def DefaultGame(self): self.height = 7 self.width = 7 self.game = PegGameInstance(height=7, width=7) self.game.boards = [ PegBoardState(height=7, width=7, time=t) for t in range(31) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): if i == j and i == 3: self.game[0][i][j].state = PegState.DEAD else: self.game[0][i][j].state = PegState.ALIVE # Intermediate states for t in range(1, 30): for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): self.game[t][i][j].state = PegState.DONTCARE # Final state for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): if i == j and i == 3: self.game[30][i][j].state = PegState.ALIVE else: self.game[30][i][j].state = PegState.DEAD
def __init__(self, n, symbols): self.n = n self.symbols = symbols self.board = None self.la = LiteralAllocator() self.literal2board = dict() self.board2literal = dict() self.cnf = CNF() self.InitSquare() self.Assert()
def Test1D(self): self.height = 1 self.width = 7 numGen = 3 self.game = PegGameInstance(height=self.height, width=self.width) self.game.boards = [ PegBoardState(height=self.height, width=self.width, time=t) for t in range(numGen) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(self.width): if i != 3: self.game[0][0][i].state = PegState.ALIVE else: self.game[0][0][i].state = PegState.DEAD # Intermediate states for t in range(1, numGen): for i in range(self.width): self.game[t][0][i].state = PegState.DONTCARE
def BasicTest(self): self.height = 5 self.width = 5 numGen = 3 self.game = PegGameInstance(height=self.height, width=self.width) self.game.boards = [ PegBoardState(height=self.height, width=self.width, time=t) for t in range(numGen) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(self.height): for j in range(self.width): if i == j and i == 2: self.game[0][i][j].state = PegState.DEAD else: self.game[0][i][j].state = PegState.ALIVE # Intermediate states for t in range(1, numGen): for i in range(self.height): for j in range(self.width): self.game[t][i][j].state = PegState.DONTCARE
class EulerSquare: def __init__(self, n, symbols): self.n = n self.symbols = symbols self.board = None self.la = LiteralAllocator() self.literal2board = dict() self.board2literal = dict() self.cnf = CNF() self.InitSquare() self.Assert() def InitSquare(self): self.board = [] for row in range(self.n): cols = [] for col in range(self.n): symbols = [] for symbol in range(self.symbols): symbolVals = [] for symbolVal in range(self.n): literal = self.la.getLiteral() self.board2literal[(row, col, symbol, symbolVal)] = literal symbolVals.append(literal) symbols.append(symbolVals) cols.append(symbols) self.board.append(cols) # number of possible symbol values | how many symbol types | columns | rows # self.board = [[[[self.la.getLiteral() for _ in range(self.n)] for _ in range(self.symbols)] for _ in range(self.n)] for _ in range(self.n)] # pp.pprint(self.board) def Assert(self): # Asserts that for each symbol, it doesn't share a row or column with the same symbol for symbol in range(self.symbols): for row in range(self.n): for col in range(self.n): for i in range(self.n): for j in range(self.n): if (row == i) ^ (col == j): for symbolVal in range(self.n): self.cnf.addClause([ -self.board[row][col][symbol] [symbolVal], -self.board[i][j][symbol][symbolVal] ]) # Assert that each symbol has a single value assigned for symbol in range(self.symbols): for row in range(self.n): for col in range(self.n): self.cnf.mergeWithRaw( SATUtils.exactlyOne(self.board[row][col][symbol], forceInefficient=True)[0]) # For each pair of symbols, they never appear twice for symbolA, symbolB in itertools.combinations(range(self.symbols), 2): for symbolValA in range(self.n): for symbolValB in range(self.n): # get pairs of literals and AND them together. That value must be # true exactly 1 time for each pairing of symbol types. impliedLiterals = [] for row in range(self.n): for col in range(self.n): clauses, C = Tseytin.AND( self.board[row][col][symbolA][symbolValA], self.board[row][col][symbolB][symbolValB], self.la.getLiteral()) impliedLiterals.append(C) self.cnf.mergeWithRaw(clauses) self.cnf.mergeWithRaw( SATUtils.atLeast(impliedLiterals, 1)[0]) # pp.pprint(sorted(self.cnf.rawCNF(), key=lambda x: [abs(_) for _ in x])) def Solve(self): finalVals = pycosat.solve(self.cnf.rawCNF()) if finalVals == 'UNSAT': print(finalVals) return rows = [] for row in range(self.n): cols = [] for col in range(self.n): symbols = [] for symbol in range(self.symbols): for symbolVal in range(self.n): val = self.board2literal[(row, col, symbol, symbolVal)] if val in finalVals: symbols.append(symbolVal) break cols.append(symbols) rows.append(cols) pp.pprint(rows)
def __init__(self, height=0, width=0): self.height = height self.width = width self.game = None self.literalAllocator = LiteralAllocator() self.cnf = CNF()
class PegSolitaire: def __init__(self, height=0, width=0): self.height = height self.width = width self.game = None self.literalAllocator = LiteralAllocator() self.cnf = CNF() def Test1D(self): self.height = 1 self.width = 7 numGen = 3 self.game = PegGameInstance(height=self.height, width=self.width) self.game.boards = [ PegBoardState(height=self.height, width=self.width, time=t) for t in range(numGen) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(self.width): if i != 3: self.game[0][0][i].state = PegState.ALIVE else: self.game[0][0][i].state = PegState.DEAD # Intermediate states for t in range(1, numGen): for i in range(self.width): self.game[t][0][i].state = PegState.DONTCARE def DefaultGame(self): self.height = 7 self.width = 7 self.game = PegGameInstance(height=7, width=7) self.game.boards = [ PegBoardState(height=7, width=7, time=t) for t in range(31) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): if i == j and i == 3: self.game[0][i][j].state = PegState.DEAD else: self.game[0][i][j].state = PegState.ALIVE # Intermediate states for t in range(1, 30): for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): self.game[t][i][j].state = PegState.DONTCARE # Final state for i in range(7): for j in range(7): if i in range(2, 5) or j in range(2, 5): if i == j and i == 3: self.game[30][i][j].state = PegState.ALIVE else: self.game[30][i][j].state = PegState.DEAD def BasicTest(self): self.height = 5 self.width = 5 numGen = 3 self.game = PegGameInstance(height=self.height, width=self.width) self.game.boards = [ PegBoardState(height=self.height, width=self.width, time=t) for t in range(numGen) ] self.literalAllocator = LiteralAllocator() # Start state for i in range(self.height): for j in range(self.width): if i == j and i == 2: self.game[0][i][j].state = PegState.DEAD else: self.game[0][i][j].state = PegState.ALIVE # Intermediate states for t in range(1, numGen): for i in range(self.height): for j in range(self.width): self.game[t][i][j].state = PegState.DONTCARE def assignLiterals(self): for t in range(len(self.game.boards)): for i in range(self.height): for j in range(self.width): if self.game[t][i][j].state != PegState.DNE: self.game[t][i][ j].variable = self.literalAllocator.getLiteral() print(self.game) def FillInSequence(self): sequence = self.game.boards if len(sequence) <= 1: raise Exception('A sequence needs at least 2 elements!') for board in sequence: assert isinstance(board, PegBoardState) assert board.height == sequence[0].height and board.width == sequence[0].width, \ 'Cannot compare boards with different dimensions.' self.assignLiterals() height = sequence[0].height width = sequence[0].width self.assertTransitions() self.assertOneMovePerTurn() self.assertFixedStates() for solution in pycosat.itersolve(self.cnf.rawCNF()): updatedSequence = [] for tiling in sequence: newTilingA = PegBoardState(tiling.height, tiling.width, tiling.time) for row in range(tiling.height): for col in range(tiling.width): if tiling[row][col].state != PegState.DNE: if tiling[row][col].variable in solution: if tiling[row][ col].state == PegState.ALIVE or tiling[ row][ col].state == PegState.DONTCARE: # This means that we either forced the cell to be alive or we derived a possible value newTilingA[row][col].state = PegState.ALIVE else: # raise Exception("Computed state is incompatible with original state") pass elif -tiling[row][col].variable in solution: if tiling[row][ col].state == PegState.DEAD or tiling[ row][ col].state == PegState.DONTCARE: # This means that we either forced the cell to be dead or we derived a possible value newTilingA[row][col].state = PegState.DEAD pass else: # raise Exception("Computed state is incompatible with original state") pass else: raise Exception( "Input wasn't even in the solution! Something is clearly wrong here." ) updatedSequence.append(newTilingA) gameSolution = PegGameInstance() gameSolution.SetFrames(updatedSequence) print(gameSolution) break def assertTransitions(self): self.assertAllTriplets() def assertFixedStates(self): fixedVals = [] for t in range(1): #len(self.game.boards)): for row in range(self.height): for col in range(self.width): if self.game.boards[t][row][col].state == PegState.ALIVE: fixedVals.append( self.game.boards[t][row][col].variable) if self.game.boards[t][row][col].state == PegState.DEAD: fixedVals.append( -self.game.boards[t][row][col].variable) self.cnf.mergeWithRaw([[x] for x in fixedVals]) def assertTriplet(self, jumper, skipped, endpoint, time): a = self.game.boards[time][jumper[0]][jumper[1]].variable b = self.game.boards[time][skipped[0]][skipped[1]].variable c = self.game.boards[time][endpoint[0]][endpoint[1]].variable x = self.game.boards[time + 1][jumper[0]][jumper[1]].variable y = self.game.boards[time + 1][skipped[0]][skipped[1]].variable z = self.game.boards[time + 1][endpoint[0]][endpoint[1]].variable clauses = [[-a, -b, c, -x, y], [-a, -b, c, -x, -z], [-a, -b, c, x, -y], [-a, -b, c, -y, -z], [-a, -b, c, x, z], [-a, -b, c, y, z]] self.cnf.mergeWithRaw(clauses) def assertAllTriplets(self): for t in range(len(self.game.boards) - 1): for row in range(self.height): for col in range(self.width): for direction in [[-1, 0], [1, 0], [0, -1], [0, 1]]: xDir = direction[0] yDir = direction[1] jumper = [row, col] skipped = [row + xDir, col + yDir] endpoint = [row + 2 * xDir, col + 2 * yDir] if self.isValidTriple(jumper, skipped, endpoint): self.assertTriplet(jumper, skipped, endpoint, t) def assertOneMovePerTurn(self): initPop = 0 for row in range(self.height): for col in range(self.width): if self.game.boards[0][row][col].state == PegState.ALIVE: initPop += 1 for t in range(len(self.game.boards)): boardLiterals = [] for row in range(self.height): for col in range(self.width): if self.game.boards[t][row][col].state != PegState.DNE: boardLiterals.append( self.game.boards[t][row][col].variable) # Try swapping for SATUtils.atLeast to check for faster speeds newClauses, highestLiteral = SATUtils.exactlyR( boardLiterals, initPop - t, startLiteral=self.literalAllocator.getCurrLiteral()) if highestLiteral >= self.literalAllocator.getCurrLiteral(): self.literalAllocator.getLiterals( highestLiteral - self.literalAllocator.getCurrLiteral() + 1) self.cnf.mergeWithRaw(newClauses) def isValidTriple(self, jumper, skipped, endpoint): if endpoint[0] not in range(self.width) or endpoint[1] not in range( self.height): return False if skipped[0] not in range(self.width) or skipped[1] not in range( self.height): return False if self.game.boards[0][jumper[0]][jumper[1]].state == PegState.DNE: return False if self.game.boards[0][skipped[0]][skipped[1]].state == PegState.DNE: return False if self.game.boards[0][endpoint[0]][endpoint[1]].state == PegState.DNE: return False return True