Compare commits
No commits in common. "test" and "master" have entirely different histories.
11
TODO
11
TODO
|
@ -1,11 +0,0 @@
|
||||||
TODO
|
|
||||||
----
|
|
||||||
|
|
||||||
- make an interface for picking moves
|
|
||||||
- make an interface, period
|
|
||||||
- back-propagate values up the tree
|
|
||||||
|
|
||||||
BUGS
|
|
||||||
----
|
|
||||||
|
|
||||||
- test framework makes mistake
|
|
125
board2.py
125
board2.py
|
@ -1,125 +0,0 @@
|
||||||
#!/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
|
|
138
cli.py
138
cli.py
|
@ -1,138 +0,0 @@
|
||||||
#!/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()
|
|
17
node.py
17
node.py
|
@ -1,17 +0,0 @@
|
||||||
# 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
|
|
12
pos.py
12
pos.py
|
@ -21,26 +21,16 @@ class TwoDPos:
|
||||||
l = 1
|
l = 1
|
||||||
def __init__(self, mode, param):
|
def __init__(self, mode, param):
|
||||||
if mode == TwoDPos.g:
|
if mode == TwoDPos.g:
|
||||||
try:
|
|
||||||
self.pos = (
|
self.pos = (
|
||||||
TwoDUtils.mappings[param[0]],
|
TwoDUtils.mappings[param[0]],
|
||||||
int(param[1]) - 1,
|
int(param[1]) - 1,
|
||||||
)
|
)
|
||||||
except KeyError:
|
|
||||||
self.pos = (
|
|
||||||
int(param[0]) - 1,
|
|
||||||
int(param[1]) - 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
elif mode == TwoDPos.l:
|
elif mode == TwoDPos.l:
|
||||||
self.pos = (
|
self.pos = (
|
||||||
param[0] * 3 + param[2],
|
param[0] * 3 + param[2],
|
||||||
param[1] * 3 + param[3],
|
param[1] * 3 + param[3] + 1,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return ' '.join([self.glob(), str(self.local())])
|
|
||||||
|
|
||||||
def glob(self):
|
def glob(self):
|
||||||
ret = []
|
ret = []
|
||||||
ret.append(TwoDUtils.reverse[self.pos[0]])
|
ret.append(TwoDUtils.reverse[self.pos[0]])
|
||||||
|
|
51
test.py
51
test.py
|
@ -1,51 +0,0 @@
|
||||||
#!/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