connect four (game)
namenobodywants at gmail.com
namenobodywants at gmail.com
Fri Nov 24 10:33:22 EST 2017
hi all
i've just finished my first excursion into artificial intelligence with a game less trivial than tictactoe, and here it is in case anybody can offer criticism/suggestions/etc
peace
stm
###############################
#) connectfour - python 3.6.1
###############################
from tkinter import *
from random import choice
class infinity:
def __init__(self,signum): self.signum = signum
def __repr__(self): return '+oo' if self.signum > 0 else '-oo'
def __lt__(self,other): return False if self.signum > 0 else True
def __le__(self,other): return False if self.signum > 0 else True
def __gt__(self,other): return True if self.signum > 0 else False
def __ge__(self,other): return True if self.signum > 0 else False
def __eq__(self,other): return isinstance(other,infinity) and self.signum == other.signum
ex, oh, blank = 'red black white' .split()
startboard = {(i,j):blank for i in range(6) for j in range(7)}
def getlines(board):
horizontal = [[(i, j+k) for k in range(4)] for i in range(6) for j in range(7)]
vertical = [[(i+k, j) for k in range(4)] for i in range(6) for j in range(7)]
positive = [[(i+k, j+k) for k in range(4)] for i in range(6) for j in range(7)]
negative = [[(i+k, j-k) for k in range(4)] for i in range(6) for j in range(7)]
linear = horizontal + vertical + positive + negative
lines = [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)]
return [[board[square] for square in line] for line in lines]
def getwinner(board):
lines = getlines(board)
return ex if [ex]*4 in lines else oh if [oh]*4 in lines else None
def getmover(board):
boardvalues = list(board.values())
return ex if boardvalues.count(ex)==boardvalues.count(oh) else oh
def getoptimum(mover):
return max if mover == ex else min
def getaccessibles(board):
return [j for j in range(7) if board[0,j] == blank]
def getvalue(winner,accessibles):
return infinity(+1) if winner == ex else infinity(-1) if winner == oh else 0 if not accessibles else None
def makemove(board,column,mover):
board = board.copy()
empties = [row for row in range(6) if board[row,column] == blank]
if not empties: return board
board[max(empties),column] = mover
return board
def takemoveback(board,column):
board = board.copy()
occupied = [row for row in range(6) if board[row,column] != blank]
if not occupied: return board
board[min(occupied),column] = blank
return board
def guessvalue(board):
lines = getlines(board)
exs = [line for line in lines if line.count(ex)==3 and line.count(oh)==0]
ohs = [line for line in lines if line.count(oh)==3 and line.count(ex)==0]
return len(exs)-len(ohs)
def heuristicvalue(board,depth):
winner = getwinner(board)
accessibles = getaccessibles(board)
value = getvalue(winner,accessibles)
if value != None: return value
if depth == 0: return guessvalue(board)
mover = getmover(board)
optimum = getoptimum(mover)
children = [makemove(board,column,mover) for column in accessibles]
return optimum(heuristicvalue(child,depth-1) for child in children)
def getmoves(board,depth):
accessibles = getaccessibles(board)
if not accessibles: return []
mover = getmover(board)
optimum = getoptimum(mover)
children = [makemove(board,column,mover) for column in accessibles]
values = [heuristicvalue(child,depth) for child in children]
bestvalue = optimum(values)
return [accessibles[index] for index in range(len(accessibles)) if values[index] == bestvalue]
class grid:
def __init__(self,window):
self.window = window
self.boardframe = Frame(window.root)
self.rowframes = [Frame(self.boardframe) for anonymous in range(6)]
self.squarebuttons = [Button(self.rowframes[number//7], width=3, command=self.window.squarecommand(number), background=blank) for number in range(42)]
def pack(self):
self.boardframe .pack(side=TOP)
[frame .pack(side=TOP) for frame in self.rowframes]
[button .pack(side=LEFT) for button in self.squarebuttons]
class caption:
def __init__(self,window):
self.window = window
self.statusframe = Frame(window.root)
self.statuslabel = Label(self.statusframe, height=2)
def pack(self):
self.statusframe .pack(side=TOP)
self.statuslabel .pack(side=LEFT)
class buttonpanel:
def __init__(self,window,depth):
self.window = window
self.controlframe = Frame(window.root)
self.makemoveframe = Frame(self.controlframe)
self.takebackframe = Frame(self.controlframe)
self.startoverframe = Frame(self.controlframe)
self.makemovebutton = Button(self.makemoveframe, text='make move', command=self.window.movecommand(depth))
self.takebackbutton = Button(self.takebackframe, text='take back', command=self.window.takeback)
self.startoverbutton = Button(self.startoverframe, text='start over', command=self.window.startover)
def pack(self):
self.controlframe .pack(side=TOP)
self.makemoveframe .pack(side=LEFT)
self.takebackframe .pack(side=LEFT)
self.startoverframe .pack(side=RIGHT)
self.makemovebutton .pack(side=TOP)
self.takebackbutton .pack(side=TOP)
self.startoverbutton .pack(side=TOP)
class window:
def __init__(self, depth=2):
self.root = Tk()
self.grid = grid (self)
self.caption = caption (self)
self.buttonpanel = buttonpanel(self, depth=2)
self.grid .pack()
self.caption .pack()
self.buttonpanel .pack()
self.startover()
self.root.title('connect four')
self.root.mainloop()
def startover(self):
self.board = startboard
self.movelist = []
self.display()
def display(self):
winner = getwinner(self.board)
mover = getmover (self.board)
tie = blank not in self.board.values()
status = winner + ' wins' if winner else 'tied game' if tie else mover + ' to move'
[self.grid.squarebuttons[number].config(background=self.board[divmod(number,7)]) for number in range(42)]
self.caption.statuslabel.config(text = status.upper() if winner or tie else status)
def squarecommand(self,number):
def returnvalue():
if getwinner(self.board) or blank not in self.board.values(): return
column = number % 7
self.board = makemove(self.board, column, getmover(self.board))
self.display()
self.grid.squarebuttons[column].flash()
self.movelist += [column]
return returnvalue
def movecommand(self,depth):
def returnvalue():
if getwinner(self.board) or blank not in self.board.values(): return
column = choice(getmoves(self.board,depth))
self.board = makemove(self.board, column, getmover(self.board))
self.display()
self.grid.squarebuttons[column].flash()
self.movelist += [column]
return returnvalue
def takeback(self):
if not self.movelist: return
self.board = takemoveback(self.board, self.movelist[-1])
self.display()
self.movelist = self.movelist[:-1]
More information about the Python-list
mailing list