import numpy as np
import theano
import theano.tensor as T
%load_ext Cython
import lasagne
from lasagne.layers.dnn import Conv2DDNNLayer as conv2d
from IPython.display import HTML, display
from random import randint
floatX = theano.config.floatX
floatX
Using gpu device 0: GeForce GTX 965M (CNMeM is disabled, CuDNN 4007) /usr/local/lib/python3.4/dist-packages/theano/tensor/signal/downsample.py:5: UserWarning: downsample module has been moved to the pool module. warnings.warn("downsample module has been moved to the pool module.")
Couldn't import dot_parser, loading of dot files will not be possible.
'float32'
%%cython
# cython: infer_types=True, annotation_typing=True
## cython: infer_types.verbose=True
from IPython.display import HTML, display
import numpy as np
floatX = np.float32
binary6 = np.array([ list(map(int,bin(2**6+i)[:2:-1])) for i in range(2**6)], dtype=floatX)
height = np.array([-1]*65, dtype=np.int32)
for __i in range(6):
height[2**__i]=__i
cdef class Connect4:
cdef public:
long turn
long long[2] data
cpdef long get_col_row(self, col: long, row: long):
pos = col * 7 + row
mask = (<long long>1) << pos
if self.data[1] & mask:
return 2
return bool(self.data[0] & mask)
cpdef long is_end(self):
cdef long long mask
bitboard = self.data[1-self.turn%2]
bound = (<long long>1)<<48 # 49 = 7*(6+1)
# horizontal: 0x204081 = 1|(1<<7)|(1<<14)|(1<<21)
# vertical: 0xf = 1|(1<<1)|(1<<2)|(1<<3)
# up-right: 0x1010101 = 1|(1<<8)|(1<<16)|(1<<24)
# down-right: 0x208208 = (1<<3)|(1<<9)|(1<<15)|(1<<21)
for mask in [0x204081, 0xf, 0x1010101, 0x208208]:
while mask < bound:
if mask & bitboard == mask:
return True
mask <<= 1
return False
def __init__(self, data=None, turn=0):
if data is not None:
self.data = data[:]
else:
self.data = [0, 0]
self.turn = turn
def _np_branch(self):
c = self.turn%2 # who's turn
base = np.zeros((3,7,6), dtype=floatX)
base[2] = 1
pos, moves = [], []
red, yellow = self.data
for i in range(7):
mask = ((red|yellow) &0x3f) + 1
p = height[mask]
if p != -1:
moves.append(i)
pos.append(height[mask])
base[c, i] = binary6[red&0x3f]
base[1-c, i] = binary6[yellow&0x3f]
red >>= 7
yellow >>= 7
boards = np.zeros( (len(moves), 3, 7, 6), dtype=floatX)
for i in range(len(moves)):
m, p = moves[i], pos[i]
boards[i]=base
boards[i, 0, m, p] = 1
return moves, boards
cpdef move(self, col:long, test=False):
# assert 0<= col <7
shift = col*7
mask = (((self.data[0]|self.data[1]) >> shift) &0x3f) +1
# print("mask=", mask)
if mask >= 64:
return None
if not test:
self.data[self.turn%2] |= (mask<<shift)
self.turn += 1
return self
def board_data(self):
for i in range(7):
for j in range(6):
c = self.get_col_row(i,j)
if c!=0:
yield i,j,c
def _repr_html_(self):
def pos(i):
return int(7+(220-6.5)*i/8)
imgstr = "<img src='img/%s.png' width='23px' height='23px' style='position: absolute; top: %spx; left: %spx;margin-top: 0;z-index: %d' />"
header = """<div style="width: 200px; height:180px;position: relative;background: blue">"""
header += "\n".join(imgstr%('empty', pos(5-j), pos(i), 0) for i in range(7) for j in range(6))
return header +"\n".join(imgstr%('red_coin' if c==1 else 'yellow_coin', pos(5-j), pos(i), 2) for (i,j,c) in self.board_data()) +"</div>"
def display(self):
display(HTML(self._repr_html_()))
def __repr__(self):
row_str = lambda j: "".join(".ox"[self.get_col_row(i,j)] for i in range(7))
return "\n".join(row_str(j) for j in range(5,-1,-1))
input_var = T.tensor4('inputs')
target_var = T.vector('targets')
l_in = lasagne.layers.InputLayer(shape=(None, 3, 7, 6), input_var=input_var)
_ = conv2d(l_in, num_filters=400, filter_size = 5, pad='same')
_ = conv2d(_, num_filters=200, filter_size = 3, pad='same')
_ = conv2d(_, num_filters=100, filter_size = 3, pad='same')
_ = conv2d(_, num_filters=50, filter_size = 3, pad='same')
_ = conv2d(_, num_filters=25, filter_size = 3, pad='same')
l_out = lasagne.layers.DenseLayer(_, num_units=1, nonlinearity=lasagne.nonlinearities.tanh, W=lasagne.init.GlorotUniform())
prediction = lasagne.layers.get_output(l_out).flatten()
V = theano.function([input_var], prediction)
# load
import pickle
values = pickle.load(open("c4-conv3.pkl","rb"))
lasagne.layers.set_all_param_values(l_out, values)
from IPython.display import clear_output
game = Connect4()
c = randint(0, 1)
moves, boards = None, None
while 1:
clear_output()
display(HTML(game._repr_html_()))
if boards is not None:
print(V(boards))
if game.turn >= 42 or game.is_end():
break
if game.turn%2 == c:
#game.move(MC_agent(game))
#while game.move(randint(0,6)) is None: continue
moves, boards = game._np_branch()
game.move(moves[np.argmax(V(boards))])
else:
game.move(int(input("your turn")))
[ 0.99999511 0.30652273 1. 0.29646683 0.2878364 0.28512001]