Compare commits
9 Commits
Author | SHA1 | Date |
---|---|---|
randomuser | 467e53b1ce | |
randomuser | 9d7cfee1f9 | |
randomuser | b5f2efb316 | |
randomuser | 842291d6d6 | |
randomuser | b30c1a7ffe | |
randomuser | c7f28a5c64 | |
randomuser | 845a0bcaad | |
randomuser | 8c55d05404 | |
randomuser | 15aab805b9 |
|
@ -0,0 +1,11 @@
|
|||
TODO
|
||||
----
|
||||
|
||||
- make an interface for picking moves
|
||||
- make an interface, period
|
||||
- back-propagate values up the tree
|
||||
|
||||
BUGS
|
||||
----
|
||||
|
||||
- test framework makes mistake
|
|
@ -0,0 +1,125 @@
|
|||
#!/usr/bin/env python
|
||||
import copy
|
||||
from pos import TwoDPos
|
||||
|
||||
class BoardTools:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def winning(self, b):
|
||||
for i in range(3):
|
||||
if b[i][0] == b[i][1] == b[i][2]:
|
||||
if b[i][0] != Board.unplayed:
|
||||
return b[i][0]
|
||||
if b[0][i] == b[1][i] == b[2][i]:
|
||||
if b[0][i] != Board.unplayed:
|
||||
return b[0][i]
|
||||
if b[0][0] == b[1][1] == b[2][2]:
|
||||
if b[0][0] != Board.unplayed:
|
||||
return b[0][0]
|
||||
if b[2][0] == b[1][1] == b[0][2]:
|
||||
if b[2][0] != Board.unplayed:
|
||||
return b[2][0]
|
||||
spaces = 0
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if b[i][j] != Board.unplayed:
|
||||
spaces += 1
|
||||
if spaces == 9:
|
||||
return Board.tie
|
||||
return Board.unplayed
|
||||
|
||||
class Board:
|
||||
unplayed = 0
|
||||
cross = 1
|
||||
nought = 2
|
||||
tie = 3
|
||||
|
||||
def __init__(self):
|
||||
self.board = [
|
||||
[
|
||||
[
|
||||
[Board.unplayed for i in range(3)]
|
||||
for j in range(3)
|
||||
]
|
||||
for k in range(3)
|
||||
]
|
||||
for l in range(3)
|
||||
]
|
||||
self.moves = []
|
||||
self.turn = Board.cross
|
||||
|
||||
def copy(self):
|
||||
new = Board()
|
||||
new.board = copy.deepcopy(self.board)
|
||||
new.moves = copy.deepcopy(self.moves)
|
||||
new.turn = copy.deepcopy(self.turn)
|
||||
|
||||
return new
|
||||
|
||||
def set(self, a, b, c, d, val):
|
||||
self.board[a][b][c][d] = val
|
||||
|
||||
def get(self, a, b, c, d):
|
||||
return self.board[a][b][c][d]
|
||||
|
||||
def alternate(self):
|
||||
if self.turn == Board.cross:
|
||||
self.turn = Board.nought
|
||||
else:
|
||||
self.turn = Board.cross
|
||||
|
||||
def subWin(self, x, y):
|
||||
return BoardTools.winning(None, self.board[x][y])
|
||||
|
||||
def metaboard(self):
|
||||
return [[BoardTools.winning(None, self.board[x][y]) for x in range(3)] for y in range(3)]
|
||||
|
||||
def win(self):
|
||||
return BoardTools.winning(self.metaboard())
|
||||
|
||||
def append(self, move):
|
||||
self.moves.append(move)
|
||||
self.set(*move.local(), self.turn)
|
||||
self.alternate()
|
||||
|
||||
def reachableEmpty(self):
|
||||
metaboard = self.metaboard()
|
||||
buf = []
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if metaboard[j][i] == Board.unplayed:
|
||||
for k in range(3):
|
||||
for l in range(3):
|
||||
if self.board[i][j][k][l] == Board.unplayed:
|
||||
buf.append(TwoDPos(TwoDPos.l, (i, j, k, l)))
|
||||
return buf
|
||||
|
||||
def possible(self):
|
||||
# check if board is in final state
|
||||
isFinal = BoardTools.winning(self, self.metaboard())
|
||||
if isFinal in [Board.tie, Board.cross, Board.nought]:
|
||||
return []
|
||||
try:
|
||||
move = self.moves[-1]
|
||||
except IndexError:
|
||||
buf = []
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
for k in range(3):
|
||||
for l in range(3):
|
||||
buf.append(TwoDPos(TwoDPos.l, (i, j, k, l)))
|
||||
|
||||
return buf
|
||||
|
||||
local = move.local()
|
||||
if self.subWin(local[2], local[3]) in [Board.tie, Board.nought, Board.cross]:
|
||||
return self.reachableEmpty()
|
||||
|
||||
buf = []
|
||||
for i in range(3):
|
||||
for j in range(3):
|
||||
if self.board[local[2]][local[3]][i][j] == Board.unplayed:
|
||||
buf.append(TwoDPos(TwoDPos.l, (local[2], local[3], i, j)))
|
||||
|
||||
return buf
|
|
@ -0,0 +1,138 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from board2 import Board
|
||||
from board2 import BoardTools
|
||||
from pos import TwoDPos
|
||||
from pos import TwoDUtils
|
||||
from node import Node
|
||||
|
||||
class StateError(BaseException):
|
||||
pass
|
||||
|
||||
piecemaps = {
|
||||
0: '.',
|
||||
1: 'x',
|
||||
2: 'o',
|
||||
}
|
||||
mappings = TwoDUtils.reverse
|
||||
|
||||
def tree_of_node(node, count=5):
|
||||
if count == 1:
|
||||
score = 0
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
p = TwoDPos(TwoDPos.g, (i + 1, j + 1))
|
||||
a, b, c, d = p.local()
|
||||
if node.inner.board[a][b][c][d] == Board.cross:
|
||||
score += 1
|
||||
elif node.inner.board[a][b][c][d] == Board.nought:
|
||||
score -= 1
|
||||
|
||||
return score
|
||||
|
||||
parent = node
|
||||
print("considering board with moveset " + str(parent.inner.moves))
|
||||
|
||||
possible = parent.inner.possible()
|
||||
if len(possible) != 0:
|
||||
print("permuting!")
|
||||
for i in possible:
|
||||
copy = parent.inner.copy()
|
||||
copy.append(i)
|
||||
childnode = Node()
|
||||
childnode.inner = copy
|
||||
parent.children.append(childnode)
|
||||
for i in parent.children:
|
||||
tree_of_node(i, count - 1)
|
||||
else:
|
||||
print("calculated score")
|
||||
rawscore = BoardTools.winning(None, parent.inner.metaboard())
|
||||
if rawscore == Board.cross:
|
||||
score = -1
|
||||
elif rawscore == Board.nought:
|
||||
score = 1
|
||||
elif rawscore == Board.tie:
|
||||
score = 0
|
||||
else:
|
||||
score = None
|
||||
raise StateError("aaaa")
|
||||
|
||||
print("score" + str(score))
|
||||
return score
|
||||
|
||||
def render(board):
|
||||
print("123 456 789")
|
||||
moves = board.possible()
|
||||
moves = [i.glob() for i in moves]
|
||||
for i in range(9):
|
||||
buf = []
|
||||
for j in range(9):
|
||||
ri = mappings[i]
|
||||
string = ''.join([ri, str(j + 1)])
|
||||
pos = TwoDPos(TwoDPos.g, string)
|
||||
item = board.get(*pos.local())
|
||||
if string in moves:
|
||||
buf.append('?')
|
||||
else:
|
||||
buf.append(piecemaps[item])
|
||||
if j in [2, 5]:
|
||||
buf.append(" | ")
|
||||
if j == 8:
|
||||
buf.append(" " + ri)
|
||||
print(''.join(buf))
|
||||
if i in [2, 5]:
|
||||
print("----+-----+----")
|
||||
|
||||
print("to play: " + str(board.turn))
|
||||
|
||||
def help_text():
|
||||
print("m - make a move")
|
||||
print("p - see coordinates of legal moves")
|
||||
print("t - see whose turn it is")
|
||||
print("r - render the board to the screen")
|
||||
print("q - quit program")
|
||||
print("h - show help (this list)")
|
||||
|
||||
def move(board, move):
|
||||
move = TwoDPos(TwoDPos.g, move)
|
||||
print(move)
|
||||
board.append(move)
|
||||
|
||||
def possibilities(board):
|
||||
print(board.possible())
|
||||
|
||||
def turn(board):
|
||||
print("to play: " + str(board.turn))
|
||||
|
||||
def main():
|
||||
b = Board()
|
||||
print("type h for help")
|
||||
while True:
|
||||
# try:
|
||||
cmd = input("> ")
|
||||
spl = cmd.split(' ')
|
||||
if spl[0] == "m":
|
||||
move(b, spl[1])
|
||||
elif spl[0] == "p":
|
||||
possibilities(b)
|
||||
elif spl[0] == "t":
|
||||
turn(b)
|
||||
elif spl[0] == "r":
|
||||
render(b)
|
||||
elif spl[0] == "h":
|
||||
help_text()
|
||||
elif spl[0] == "z":
|
||||
# create node from current board
|
||||
node = Node()
|
||||
node.inner = b
|
||||
|
||||
tree_of_node(node)
|
||||
|
||||
elif spl[0] == "q":
|
||||
break;
|
||||
# except:
|
||||
# print("error occured")
|
||||
return
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,17 @@
|
|||
# node implementation
|
||||
|
||||
class Node:
|
||||
def __init__(self):
|
||||
self.children = []
|
||||
self.score = None
|
||||
self.inner = None
|
||||
def calculate(self):
|
||||
if self.children == []:
|
||||
return self.score
|
||||
total = 0
|
||||
items = 0
|
||||
for i in self.children:
|
||||
score = i.calculate()
|
||||
if score != None:
|
||||
items += 1
|
||||
total += score
|
20
pos.py
20
pos.py
|
@ -21,16 +21,26 @@ class TwoDPos:
|
|||
l = 1
|
||||
def __init__(self, mode, param):
|
||||
if mode == TwoDPos.g:
|
||||
self.pos = (
|
||||
TwoDUtils.mappings[param[0]],
|
||||
int(param[1]) - 1,
|
||||
)
|
||||
try:
|
||||
self.pos = (
|
||||
TwoDUtils.mappings[param[0]],
|
||||
int(param[1]) - 1,
|
||||
)
|
||||
except KeyError:
|
||||
self.pos = (
|
||||
int(param[0]) - 1,
|
||||
int(param[1]) - 1,
|
||||
)
|
||||
|
||||
elif mode == TwoDPos.l:
|
||||
self.pos = (
|
||||
param[0] * 3 + param[2],
|
||||
param[1] * 3 + param[3] + 1,
|
||||
param[1] * 3 + param[3],
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return ' '.join([self.glob(), str(self.local())])
|
||||
|
||||
def glob(self):
|
||||
ret = []
|
||||
ret.append(TwoDUtils.reverse[self.pos[0]])
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from board2 import Board
|
||||
from pos import TwoDPos
|
||||
|
||||
b = Board()
|
||||
print(b.possible())
|
||||
print("moving to d4")
|
||||
b.append(TwoDPos(TwoDPos.g, "d4"))
|
||||
print(b.possible())
|
||||
print("moving to b2")
|
||||
b.append(TwoDPos(TwoDPos.g, "b2"))
|
||||
print(b.possible())
|
||||
print("moving to d5")
|
||||
b.append(TwoDPos(TwoDPos.g, "d5"))
|
||||
print(b.possible())
|
||||
print("moving to b5")
|
||||
b.append(TwoDPos(TwoDPos.g, "b5"))
|
||||
print(b.possible())
|
||||
print("moving to d6")
|
||||
b.append(TwoDPos(TwoDPos.g, "d6"))
|
||||
print(b.possible())
|
||||
print("moving to b8")
|
||||
b.append(TwoDPos(TwoDPos.g, "b8"))
|
||||
print(b.possible())
|
||||
print("there should be a square captured in the middle")
|
||||
print("moving to a7")
|
||||
b.append(TwoDPos(TwoDPos.g, "a7"))
|
||||
print(b.possible())
|
||||
print("moving to c3")
|
||||
b.append(TwoDPos(TwoDPos.g, "c3"))
|
||||
print(b.possible())
|
||||
print("moving to g7")
|
||||
b.append(TwoDPos(TwoDPos.g, "g7"))
|
||||
print(b.possible())
|
||||
print("moving to b3")
|
||||
b.append(TwoDPos(TwoDPos.g, "b3"))
|
||||
print(b.possible())
|
||||
print("moving to d7")
|
||||
b.append(TwoDPos(TwoDPos.g, "d7"))
|
||||
print(b.possible())
|
||||
print("moving to a3")
|
||||
b.append(TwoDPos(TwoDPos.g, "a3"))
|
||||
print(b.possible())
|
||||
print("moving to c9")
|
||||
b.append(TwoDPos(TwoDPos.g, "c9"))
|
||||
print(b.possible())
|
||||
print("moving to g9")
|
||||
b.append(TwoDPos(TwoDPos.g, "g9"))
|
||||
print(b.possible())
|
||||
|
Loading…
Reference in New Issue