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
|
12
pos.py
12
pos.py
|
@ -21,16 +21,26 @@ 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] + 1,
|
param[1] * 3 + param[3],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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]])
|
||||||
|
|
|
@ -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