In [1]:
import sdm as sdmlib
from collections import defaultdict
import random
from IPython.display import clear_output
empty = ' '
In [2]:
class Player(object):
def __init__(self, name):
self.name = name
def on_invalid_move(self):
raise Exception('Ops')
def on_finish(self, winner, seq):
pass
def next_move(self, step, board):
v = []
for i, row in enumerate(board):
for j, x in enumerate(row):
if x == empty:
v.append((i, j))
return random.choice(v)
In [3]:
class SDMPlayer(object):
def __init__(self, name):
self.name = name
self.bits = 256
self.sample = 1000000
self.scanner_type = sdmlib.SDM_SCANNER_THREAD
self.address_space = sdmlib.AddressSpace.init_random(self.bits, self.sample)
self.counter = sdmlib.Counter.init_zero(self.bits, self.sample)
self.sdm = sdmlib.SDM(self.address_space, self.counter, 103, self.scanner_type)
self.bs_steps = [sdmlib.Bitstring.init_random(self.bits) for _ in range(10)]
self.code_bits = self.bits // 9
self.bs_codes = {
'X': sdmlib.Bitstring.init_random(self.code_bits),
'O': sdmlib.Bitstring.init_random(self.code_bits),
' ': sdmlib.Bitstring.init_random(self.code_bits),
}
self.reset_stats()
def reset_stats(self):
self.stats = defaultdict(int)
def on_invalid_move(self):
raise Exception('Ops')
def board_to_bitstring(self, board):
bs = sdmlib.Bitstring.init_zeros(self.bits)
bit = 0
for row in board:
for x in row:
code = self.bs_codes[x]
for i in range(self.code_bits):
bs.set_bit(bit, code.get_bit(i))
bit += 1
return bs
def bitstring_to_board(self, ref):
board = [[empty]*3 for _ in range(3)]
bit = 0
for i in range(3):
for j in range(3):
bs1 = sdmlib.Bitstring.init_zeros(self.code_bits)
for k in range(self.code_bits):
bs1.set_bit(k, ref.get_bit(bit))
bit += 1
found = False
for x, code in self.bs_codes.items():
if code == bs1:
board[i][j] = x
found = True
if not found:
#print 'Not found'
return None
return board
def on_finish(self, winner, seq):
debug = False
if winner == self.name:
prev = None
if debug:
print('Learning...')
for step, board in enumerate(seq):
if prev is not None:
if debug:
print_board(prev)
print('')
print_board(board)
print('--')
bs1 = self.board_to_bitstring(prev)
bs2 = self.board_to_bitstring(board)
self.sdm.write(bs1 ^ self.bs_steps[step], bs2)
prev = board
def next_move(self, step, board):
bs1 = self.board_to_bitstring(board)
bs2 = self.sdm.iter_read(bs1 ^ self.bs_steps[step], max_iter=12)
board2 = self.bitstring_to_board(bs2)
if board2 is None:
return self.random_move(step, board)
diff = []
for i in range(3):
for j in range(3):
if board[i][j] != board2[i][j]:
if board[i][j] == empty and board2[i][j] == self.name:
diff.append((i, j))
if diff:
self.stats['sdm'] += 1
return random.choice(diff)
return self.random_move(step, board)
#print diff
#print ''
#print_board(board)
#print ''
#print_board(board2)
#print ''
#raise Exception
def random_move(self, step, board):
self.stats['random'] += 1
v = []
for i, row in enumerate(board):
for j, x in enumerate(row):
if x == empty:
v.append((i, j))
return random.choice(v)
In [4]:
def print_board(board):
for row in board:
print(row)
def check_all_equal(*args):
if len(set(args)) == 1 and args[0] != empty:
return True
return False
def check_for_winner(board):
for i in range(3):
if check_all_equal(board[i][0], board[i][1], board[i][2]):
return board[i][0]
if check_all_equal(board[0][i], board[1][i], board[2][i]):
return board[0][i]
if check_all_equal(board[0][0], board[1][1], board[2][2]):
return board[0][0]
if check_all_equal(board[0][2], board[1][1], board[2][0]):
return board[0][2]
return None
def copy_board(board):
v = []
for row in board:
v.append(list(row))
return v
def play(p1, p2):
board = [[empty]*3 for _ in range(3)]
end = False
players = [p1, p2]
random.shuffle(players)
index = 0
step = 0
sequence = [board]
winner = None
while not end:
cur_player = players[index]
i, j = cur_player.next_move(step, board)
if board[i][j] != empty:
cur_player.on_invalid_move()
board = copy_board(board)
board[i][j] = cur_player.name
sequence.append(board)
winner = check_for_winner(board)
if winner is not None:
end = True
v = []
for i, row in enumerate(board):
for j, x in enumerate(row):
if x == empty:
v.append((i, j))
if len(v) == 0:
end = True
index = (index+1)%2
step += 1
return winner, sequence
In [5]:
p1 = SDMPlayer('X')
p2 = Player('O')
In [ ]:
n = 200
wins = defaultdict(int)
for i in range(n):
winner, seq = play(p1, p2)
p1.on_finish(winner, seq)
p2.on_finish(winner, seq)
wins[winner] += 1
clear_output(wait=True)
print('Game #{:5d}: {} {}'.format(i+1, list(wins.items()), list(p1.stats.items())))
#print ''
#print_board(seq[-1])
#print ''
#for board in seq:
# print_board(board)
# print ''
In [6]:
bs1 = p1.board_to_bitstring([[' ', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']])
bs2 = p1.board_to_bitstring([['X', ' ', ' '], [' ', ' ', ' '], [' ', ' ', ' ']])
bs3 = p1.board_to_bitstring([[' ', 'X', ' '], [' ', ' ', ' '], [' ', ' ', ' ']])
bs4 = p1.board_to_bitstring([[' ', ' ', 'X'], [' ', ' ', ' '], [' ', ' ', ' ']])
bs5 = p1.board_to_bitstring([[' ', ' ', ' '], ['X', ' ', ' '], [' ', ' ', ' ']])
bs6 = p1.board_to_bitstring([[' ', ' ', ' '], [' ', 'X', ' '], [' ', ' ', ' ']])
In [13]:
#p1.sdm.write(bs1, bs2)
#p1.sdm.write(bs1, bs3)
#p1.sdm.write(bs1, bs4)
p1.sdm.write(bs1, bs5)
#p1.sdm.write(bs1, bs6)
In [14]:
rd1 = p1.sdm.read(bs1)
In [15]:
p1.bitstring_to_board(rd1)
Out[15]:
In [ ]:
In [ ]: