tictactoe script - commented - may have pedagogical value
""" this program makes an optimal tictactoe move by answering the following questions in their given order until it is told where to put its mark: 1) can you win the game? if so then do it 2) could your opponent win the game if it was his turn? if so then put your own mark where a mark of his would win him the game 3) could you win the game if you had two turns in a row? if so then make a move that leaves you with the largest number of second moves that would win you the game if you could really make them 4) is the center square open? if so then put your mark there 5) are any of the corners open? if so then put your mark on one of them 6) put your mark on any open square """ #) tictactoe; python 3.6.1 count = lambda dictionary, value: list(dictionary.values()).count(value) subdictionary = lambda dictionary, keys: {key: dictionary[key] for key in keys} ex, oh, blank = 'X0 ' indices = list(range(3)) vectors = [(i,j) for i in indices for j in indices] startgrid = {vector: blank for vector in vectors} display = lambda grid: '\n-+-+-\n'.join('|'.join(grid[i,j] for j in indices) for i in indices) iscenter = lambda vector: vector == (1,1) iscorner = lambda vector: vector[0]%2 == vector[1]%2 == 0 horizontal = [[(i,j) for j in indices] for i in indices] vertical = [[(i,j) for i in indices] for j in indices] diagonal = [[(i,i) for i in indices], [(i,2-i) for i in indices]] linear = horizontal + vertical + diagonal getrows= lambda grid: [subdictionary(grid,coordlist) for coordlist in linear] movermark = lambda grid: ex if count(grid,ex) == count(grid,oh) else oh opponent = lambda mark: ex if mark == oh else oh if mark == ex else blank strike = lambda vector, rows, ownmark: int(any(row for row in rows if vector in row and count(row,blank)==1 and count(row,ownmark)==2)) parry= lambda vector, rows, ownmark: int(any(row for row in rows if vector in row and count(row,blank)==1 and count(row,opponent(ownmark))==2)) threaten = lambda vector, rows, ownmark: len([row for row in rows if vector in row and count(row,blank)==2 and count(row,ownmark)==1]) position = lambda vector, rows, ownmark: 2 * int(iscenter(vector)) + int(iscorner(vector)) evaluate = lambda vector, rows, ownmark: [f(vector,rows,ownmark) for f in (strike,parry,threaten,position)] def movevector(grid,ownmark): from random import choice rows = getrows(grid) value = lambda vector: evaluate(vector,rows,ownmark) candidates = [(i,j) for i in indices for j in indices if grid[i,j] == blank] maximum = value(max(candidates,key=value)) if candidates else None coords = [vector for vector in candidates if value(vector) == maximum] return choice(coords) if coords and blank in grid.values() else None def getwinner(grid): rows = getrows(grid) rows = [list(row.values()) for row in rows] return ex if [ex]*3 in rows else oh if [oh]*3 in rows else None def makemove(grid): grid = grid.copy() ownmark = movermark(grid) vector = movevector(grid,ownmark) if vector: grid[vector] = ownmark return grid def getinteger(lower,upper,prompt): integer = None while integer == None: try: integer = int(input(prompt)) assert lower <= integer <= upper except KeyboardInterrupt: raise except: pass return integer def play(mark): grid = startgrid.copy() if mark == ex: grid = makemove(grid) print('\n\n' + display(grid) + '\n\n') winner = None while not winner and blank in grid.values(): cellnumber = getinteger(1,9,'cell number: ') grid[divmod(cellnumber-1,3)] = movermark(grid) winner = getwinner(grid) if not winner: grid = makemove(grid) winner = getwinner(grid) print('\n\n' + display(grid) + '\n\n') message = winner + ' wins' if winner else 'tied game' print(message) -- https://mail.python.org/mailman/listinfo/python-list
seeking advice about strategic-game ai
i plan to try writing an ai for a strategic game, and i've pretty much narrowed the candidates down to either checkers or reversi. i would prefer to tackle the easier game, so can anybody tell me which one is easier to program decently? (or maybe i'm missing a good candidate - basically all i want is a game that's less trivial than tictactoe). by "decently" i mean that it should make reasonably skillful moves in a reasonable amount of time, but speed and playing strength take a backseat to the simplicity and well-motivatedness of the algorithm. (this isn't supposed to be a professional-caliber ai ... it will be more like a kid's science-fair project). more particularly, can anybody give me some high-level guidance about evaluation functions for either game? (no spoilers please - i want this to be really my own project). as far as reversi goes, my ideas on this matter are based mostly on the "basic diagram" in goro hasegawa's "how to win at othello". (i have a library hold on norvig's "paradigms of ai programming", which devotes an entire chapter to reversi, but the book hasn't come in yet). as for checkers, i was thinking about a weighted sum of three basic measurements ... if "you" and "i" are the players, then i would measure *) (my relative mobility) = (the number of moves i have) - (the number of moves you have) *) (my relative king presence) = (the number of kings i have) - (the number of kings you have) *) (my relative pawn presence) = (the number of pawns i have) - (the number of pawns you have) indeed, i've even wondered whether a viable evaluation could be based on relative mobility alone - that would, after all, work perfectly if there were no limit to the search horizon - but on the other hand i'm also prepared to find out that any viable evaluation needs to be more sophisticated. i wouldn't be surprised, for example, if the approach i'm suggesting could work but only if the weights in the sum are adjusted according to the number of moves made or some other criterion. anyway, that should suffice to give you an idea of where i'm at with this. thanks if you can help peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: tictactoe script - commented - may have pedagogical value
good point. this algorithm doesn't take account of the fact that one can make a threat (x's 147) by parrying a threat (o's 357). nevertheless i'm still certain that the components the algorithm is built from are the same components i use myself to play tictactoe, and i'm still certain that my own tictactoe playing is optimal. that's my motivation for doing it this way: i'm trying to formalize the algorithm i use myself. besides, exhaustive minimax search seems like cheating to me, since it doesn't generalize to less-trivial games. anyway, thanks for pointing out the error peace stm -- https://mail.python.org/mailman/listinfo/python-list
connect four (game)
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.move
Re: connect four (game)
On Friday, November 24, 2017 at 12:13:18 PM UTC-8, Terry Reedy wrote: > Since you did not start with tests or write tests as you wrote code, ... why on earth would you assume that? instantiate "window" and you'll see it works exactly as i intended; nobody's asking you to debug code for free; i'm looking for the kind of feedback the other respondent gave peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote: > Actually I've no idea what these tests are supposed to prove. me neither; i think you guys may be getting me out of my depth now > They are to do with one class called 'infinity', which is never used in the > rest > of the program apart from one line. > > I established that within a few seconds, and I would concentrate on what > 'infinity' is actually for, rather than go to considerable lengths to > test a class that may not actually be needed. my current version of "infinity" looks like this class Infinity: def __init__(self,signum): self.signum = (+1) if signum > 0 else (-1) def __repr__(self): return '+oo' if self.signum == (+1) else '-oo' def __lt__(self,other): return self.signum == (-1) def __le__(self,other): return self.signum == (-1) def __gt__(self,other): return self.signum == (+1) def __ge__(self,other): return self.signum == (+1) def __eq__(self,other): return isinstance(other,Infinity) and self.signum == other.signum the idea is that there should be exactly one object posinf (positive infinity) that compares as strictly greater than any number ever considered, and exactly one object neginf that compares as strictly less; as the code stands now there is no reason not to use +/-70 in that capacity; the "infinity" class is there so that the game-playing parts of the code (which at present are intentionally as primitive as possible) can be modified more smoothly later; the single place where "infinity" is instantiated is in the function "getvalue", which returns the value of a finished game: def getvalue(winner,accessibles): return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh else 0 if not accessibles else None if ex has won then the value of the game is posinf; if oh has won then it's neginf; if the game is tied (no winner but no accessible columns remaining) then the value of the game is zero; otherwise the game is not finished and its finished value is None peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Friday, November 24, 2017 at 8:07:07 AM UTC-8, Chris Angelico wrote: > This is the kind of function that needs a docstring and some comments. > What exactly is this doing? What are the "lines" of the board? What's > the difference between "linear" and "lines"? What exactly is it > returning? producing documentation is an extremely difficult task for me, but i've come up with the following: """ makelines(length,numrows,numcolumns) IS THE LIST OF ALL LISTS L, WITH LENGTH length, OF COORDINATES FROM A numrows x numcolumns MATRIX, SUCH THAT THE ENTRIES OF L ALL LIE IN A LINE: LET horizontal BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A HORIZONTAL LINE LET vertical BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A VERTICAL LINE LET downward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A DOWNWARD-SLOPING DIAGONAL LINE LET upward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN AN UPWARD-SLOPING DIAGONAL LINE THEN makelines(length,numrows,numcolumns) IS THE UNION OF ALL THE AFOREMENTIONED SETS """ def makelines(length,numrows,numcolumns): horizontal = [[(i, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] vertical = [[(i+k, j) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] downward = [[(i+k, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] upward = [[(i+k, j-k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] linear = horizontal + vertical + downward + upward return [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)] def getlines(board): coordlines = makelines(4,6,7) ## GLOBAL return [[board[square] for square in line] for line in coordlines i tried to remove all the superfluous spaces from that, but lining up code vertically is very helpful to me, so i don't think i can really dispense with the practice peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote: > I did, and it looks buggy to me. The top and left frame lines are > missing. If I click a square, the bottom square in the column lights > up. But then I have no idea whether those are your intentions or not. i hadn't noticed about the frame lines, but it's the same for me; but i'm hoping you meant to write that the TOP square in a column flashes when you "drop a token" down that column; if you really meant the bottom one then i'm totally baffled that it could be the top one for me and the bottom one for you ... is that something that can happen because of a bug? sorry if you were offended by what i wrote before; i didn't understand what you meant peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Friday, November 24, 2017 at 8:07:07 AM UTC-8, Chris Angelico wrote: > This is the kind of function that needs a docstring and some comments. > What exactly is this doing? What are the "lines" of the board? What's > the difference between "linear" and "lines"? What exactly is it > returning? producing documentation is an extremely difficult task for me, but i've come up with the following: """ makelines(length,numrows,numcolumns) IS THE LIST OF ALL LISTS L, WITH LENGTH length, OF COORDINATES FROM A numrows x numcolumns MATRIX, SUCH THAT THE ENTRIES OF L ALL LIE IN A LINE: LET horizontal BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A HORIZONTAL LINE LET vertical BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A VERTICAL LINE LET downward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A DOWNWARD-SLOPING DIAGONAL LINE LET upward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN AN UPWARD-SLOPING DIAGONAL LINE THEN makelines(length,numrows,numcolumns) IS THE UNION OF ALL THE AFOREMENTIONED SETS """ def makelines(length,numrows,numcolumns): horizontal = [[(i, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] vertical = [[(i+k, j) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] downward = [[(i+k, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] upward = [[(i+k, j-k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] linear = horizontal + vertical + downward + upward return [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)] def getlines(board): coordlines = makelines(4,6,7) ## GLOBAL return [[board[square] for square in line] for line in coordlines i tried to remove all the superfluous spaces from that, but lining up code vertically is very helpful to me, so i don't think i can really dispense with the practice peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote: > Actually I've no idea what these tests are supposed to prove. me neither; i think you guys may be getting me out of my depth now > They are to do with one class called 'infinity', which is never used in the rest > of the program apart from one line. > > I established that within a few seconds, and I would concentrate on what > 'infinity' is actually for, rather than go to considerable lengths to > test a class that may not actually be needed. my current version of "infinity" looks like this class Infinity: def __init__(self,signum): self.signum = (+1) if signum > 0 else (-1) def __repr__(self): return '+oo' if self.signum == (+1) else '-oo' def __lt__(self,other): return self.signum == (-1) def __le__(self,other): return self.signum == (-1) def __gt__(self,other): return self.signum == (+1) def __ge__(self,other): return self.signum == (+1) def __eq__(self,other): return isinstance(other,Infinity) and self.signum == other.signum the idea is that there should be exactly one object posinf (positive infinity) that compares as strictly greater than any number ever considered, and exactly one object neginf that compares as strictly less; as the code stands now there is no reason not to use +/-70 in that capacity; the "infinity" class is there so that the game-playing parts of the code (which at present are intentionally as primitive as possible) can be modified more smoothly later; the single place where "infinity" is instantiated is in the function "getvalue", which returns the value of a finished game: def getvalue(winner,accessibles): return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh else 0 if not accessibles else None if ex has won then the value of the game is posinf; if oh has won then it's neginf; if the game is tied (no winner but no accessible columns remaining) then the value of the game is zero; otherwise the game is not finished and its finished value is None peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote: > I did, and it looks buggy to me. The top and left frame lines are > missing. If I click a square, the bottom square in the column lights > up. But then I have no idea whether those are your intentions or not. i hadn't noticed about the frame lines, but it's the same for me; but i'm hoping you meant to write that the TOP square in a column flashes when you "drop a token" down that column; if you really meant the bottom one then i'm totally baffled that it could be the top one for me and the bottom one for you ... is that something that can happen because of a bug? sorry if you were offended by what i wrote before; i didn't understand what you meant peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 5:00:12 AM UTC-8, bartc wrote: > Actually I've no idea what these tests are supposed to prove. me neither; i think you guys may be getting me out of my depth now > They are to do with one class called 'infinity', which is never used in the rest > of the program apart from one line. > > I established that within a few seconds, and I would concentrate on what > 'infinity' is actually for, rather than go to considerable lengths to > test a class that may not actually be needed. my current version of "infinity" looks like this class Infinity: def __init__(self,signum): self.signum = (+1) if signum > 0 else (-1) def __repr__(self): return '+oo' if self.signum == (+1) else '-oo' def __lt__(self,other): return self.signum == (-1) def __le__(self,other): return self.signum == (-1) def __gt__(self,other): return self.signum == (+1) def __ge__(self,other): return self.signum == (+1) def __eq__(self,other): return isinstance(other,Infinity) and self.signum == other.signum the idea is that there should be exactly one object posinf (positive infinity) that compares as strictly greater than any number ever considered, and exactly one object neginf that compares as strictly less; as the code stands now there is no reason not to use +/-70 in that capacity; the "infinity" class is there so that the game-playing parts of the code (which at present are intentionally as primitive as possible) can be modified more smoothly later; the single place where "infinity" is instantiated is in the function "getvalue", which returns the value of a finished game: def getvalue(winner,accessibles): return Infinity(+1) if winner == ex else Infinity(-1) if winner == oh else 0 if not accessibles else None if ex has won then the value of the game is posinf; if oh has won then it's neginf; if the game is tied (no winner but no accessible columns remaining) then the value of the game is zero; otherwise the game is not finished and its finished value is None peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Friday, November 24, 2017 at 8:07:07 AM UTC-8, Chris Angelico wrote: > This is the kind of function that needs a docstring and some comments. > What exactly is this doing? What are the "lines" of the board? What's > the difference between "linear" and "lines"? What exactly is it > returning? producing documentation is an extremely difficult task for me, but i've come up with the following: """ makelines(length,numrows,numcolumns) IS THE LIST OF ALL LISTS L, WITH LENGTH length, OF COORDINATES FROM A numrows x numcolumns MATRIX, SUCH THAT THE ENTRIES OF L ALL LIE IN A LINE: LET horizontal BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A HORIZONTAL LINE LET vertical BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A VERTICAL LINE LET downward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN A DOWNWARD-SLOPING DIAGONAL LINE LET upward BE ALL THE APPROPRIATE-LENGTH LISTS WHOSE ENTRIES LIE IN AN UPWARD-SLOPING DIAGONAL LINE THEN makelines(length,numrows,numcolumns) IS THE UNION OF ALL THE AFOREMENTIONED SETS """ def makelines(length,numrows,numcolumns): horizontal = [[(i, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] vertical = [[(i+k, j) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] downward = [[(i+k, j+k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] upward = [[(i+k, j-k) for k in range(length)] for i in range(numrows) for j in range(numcolumns)] linear = horizontal + vertical + downward + upward return [line for line in linear if all(i in range(6) and j in range(7) for (i,j) in line)] def getlines(board): coordlines = makelines(4,6,7) ## GLOBAL return [[board[square] for square in line] for line in coordlines i tried to remove all the superfluous spaces from that, but lining up code vertically is very helpful to me, so i don't think i can really dispense with the practice peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Saturday, November 25, 2017 at 12:48:38 AM UTC-8, Terry Reedy wrote: > I did, and it looks buggy to me. The top and left frame lines are > missing. If I click a square, the bottom square in the column lights > up. But then I have no idea whether those are your intentions or not. i hadn't noticed about the frame lines, but it's the same for me; but i'm hoping you meant to write that the TOP square in a column flashes when you "drop a token" down that column; if you really meant the bottom one then i'm totally baffled that it could be the top one for me and the bottom one for you ... is that something that can happen because of a bug? sorry if you were offended by what i wrote before; i didn't understand what you meant peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Sunday, November 26, 2017 at 7:09:25 PM UTC-8, Michael Torrie wrote: > So you are using this Infinity class as a sentinel value of some kind? > Representing game state? There may be an easier way than a full on > custom type. Sometimes just a sentinel object is sufficient. Or an > enumeration. they're not sentinels; they're the maximum and minimum of the extended real numbers; the point is that, no matter how boards are evaluated (which is, of course, subject to change), a won game is always the most valuable and a lost game is always the least valuable; ordinary real numbers could be used for the purpose, but in that case i would have to figure out the maximum and minimum of the heuristic values the script assigns and then add/subtract one (for example) to get the value of a won/lost game peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Monday, November 27, 2017 at 2:10:56 AM UTC-8, Chris Angelico wrote: > Or you could use the floating-point values for positive and negative > infinity perfecto! thank you! peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Sunday, November 26, 2017 at 7:09:25 PM UTC-8, Michael Torrie wrote: > So you are using this Infinity class as a sentinel value of some kind? > Representing game state? There may be an easier way than a full on > custom type. Sometimes just a sentinel object is sufficient. Or an > enumeration. they're not sentinels; they're the maximum and minimum of the extended real numbers; the point is that, no matter how boards are evaluated (which is, of course, subject to change), a won game is always the most valuable and a lost game is always the least valuable; ordinary real numbers could be used for the purpose, but in that case i would have to figure out the maximum and minimum of the heuristic values the script assigns and then add/subtract one (for example) to get the value of a won/lost game peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: connect four (game)
On Monday, November 27, 2017 at 2:10:56 AM UTC-8, Chris Angelico wrote: > Or you could use the floating-point values for positive and negative > infinity perfecto! thank you! peace stm -- https://mail.python.org/mailman/listinfo/python-list
correctness proof for alpha-beta algorithm
hi all can anybody tell me where to look for a proof of the correctness of a minimax/negamax algorithm with alpha-beta pruning? thanks if you can help peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: correctness proof for alpha-beta algorithm
On Monday, December 18, 2017 at 10:16:07 PM UTC-8, Terry Reedy wrote: > Where or how have you looked so far? How formal do you want? i want full-on formal with lots of rigor and every possible detail spelled out; i've looked in a couple of books but my best lead so far is a paper by knuth called "an analysis of alpha-beta pruning" - what i need is along those lines but with just a few more of the details spelled out peace stm -- https://mail.python.org/mailman/listinfo/python-list
Re: correctness proof for alpha-beta algorithm
On Tuesday, December 19, 2017 at 3:28:39 PM UTC-8, Steve D'Aprano wrote: > Does this have anything specifically to do with Python programming? i'm working on a game-playing script (ie: in python), i want to incorporate pruning into my search algorithm, and i'd like to understand why it works; i'm not sure if that counts > If not, why are you asking here? Do you think that Python programmers are > especially well-known for their hard-core formal academic methodology? maybe i just think python programmers are smart or well-informed or something like that > We're pretty accepting of off-topic posts here, especially when they evolve > naturally from an on-topic post. But in future, if you're going to *start* an > off-topic thread from the first post, it would be polite to label it such > with an "[OT]" or "Off-topic" prefix to the subject line. can do -- https://mail.python.org/mailman/listinfo/python-list
Re: correctness proof for alpha-beta algorithm
On Tuesday, December 19, 2017 at 5:34:17 PM UTC-8, Paul Rubin wrote: > It frankly sounds like homework. https://en.wikipedia.org/wiki/Theorem -- https://mail.python.org/mailman/listinfo/python-list
unintuitive for-loop behavior
hello pythonistas i've had a nodding acquaintance with python for some time, and all along i assumed that for-loops got a namespace of their own; now i'm reading up on the language and i find out that's not the case: the loop variable gets put into the enclosing namespace, overwriting any former value that was already there; of course i realize there are situations where one is interested in the value that a loop variable has after the loop has been exited, but this behavior seems grossly unintuitive to me: has there ever been any discussion of giving for-loops the option of running in namespaces of their own? and it gets even worse; consider the following means of raising an exception: #)-- begin code def powerfunction(exponent): return lambda base: (base ** exponent) p1 = [powerfunction(exponent) for exponent in range(9)] p2 = [lambda base: (base ** exponent) for exponent in range(9)] assert p1[3](4) == p2[3](4) #) end code apparently the problem is that "exponent" gets evaluated when the relevant lambda function is run, not when it's defined, but no binding for "exponent" gets put into the enclosing namespace: it seems that python remembers this ghostly "exponent" for me on the theory that i don't WANT "p1" and "p2" to be the same; can anyone help to reconcile me to this semantics? thanks if you can help stm -- https://mail.python.org/mailman/listinfo/python-list
tkinter callbacks stop working
hello pythonistas the script below plays tictactoe; everything works; but if i replace the block at the bottom if True: with this instead def function(): function() then the tkinter callbacks don't work anymore; can anybody make sense of this? thanks if you can help peace stm ps: here's the code... ex, oh, blank = 'XO ' rows = [[3*i + j for j in range(3)] for i in range(3)] columns = [[3*i + j for i in range(3)] for j in range(3)] diagonals = [[3+3, 4, 5-3], [3-3, 4, 5+3]] lines = rows + columns + diagonals putmark= lambda board, square, mark: board[:square] + mark + board[square + 1:] getblanks = lambda board: [square for square in range(9) if board[square]==blank] getmover = lambda board: ex if board.count(ex)==board.count(oh) else oh getlines = lambda board: [[board[square] for square in line] for line in lines] getwinners = lambda board: [player for player in [ex, oh] if [player] * 3 in getlines(board)] def evaluate(board): winners = getwinners(board) mover= getmover(board) blanks = getblanks(board) value= (+1) if winners==[ex] else (-1) if winners==[oh] else 0 optimum = max if mover == ex else min if mover == oh else None if winners or not blanks: return value, [] values = [evaluate(putmark(board,square,mover))[0] for square in blanks] optimal = optimum(values) return optimal, [square for (index, square) in enumerate(blanks) if values[index]==optimal] isvalid = lambda board: len(getwinners(board)) < 2 and board.count(ex)-board.count(oh) in {0,1} cartesian = lambda strings: [''] if not strings else [x + ys for x in strings[0] for ys in cartesian(strings[1:])] getmoves = lambda: {board: evaluate(board)[1] for board in cartesian([marks] * 9) if isvalid(board)} def getmove(board): from random import choice blanks = getblanks(board) evens = [square for square in blanks if (square % 2)==0] return choice(evaluate(board)[1]) if len(blanks)<8 else 4 if 4 in blanks else choice(evens) def getdisplay(board): template = ' {} | {} | {} ' separator = '\n---\n' return separator.join(template.format(*(board[square] for square in row)) for row in rows) def getstatus(board): winners = getwinners(board) numblanks = board.count(blank) if winners: return winners[0] + ' wins' if numblanks==0: return 'draw' if numblanks==9: return 'X goes first' else:return getmover(board) + ' goes next' show = lambda board: print('\n' + getdisplay(board) + '\n\n' + getstatus(board) + '\n') def newgame(): global board board = blank * 9 show(board) def makemove(): global board board = board if getwinners(board) or blank not in board else putmark(board, getmove(board), getmover(board)) show(board) def takemove(square): global board board = board if getwinners(board) or board[square] != blank else putmark(board, square, getmover(board)) show(board) show = lambda board: status.set(getstatus(board)) or [squares[i].set(board[i]) for i in range(9)] if True: from tkinter import Tk, Frame, Label, Button window = Tk() status = StringVar() squares= [StringVar() for i in range(9)] statusframe= Frame(window) buttonframe= Frame(window) boardframe = Frame(window) statuslabel= Label(statusframe) newgamebutton = Button(buttonframe) makemovebutton = Button(buttonframe) rowframes = [Frame(boardframe) for i in range(3)] squarebuttons = [Button(rowframes[i//3]) for i in range(9)] statuslabel .configure(textvariable=status) newgamebutton .configure(command=newgame, text='new game') makemovebutton .configure(command=makemove, text='make move') for i in range(9): squarebuttons[i] .configure(textvariable=squares[i], command=lambda i=i:takemove(i)) statuslabel .configure(padx=0, pady=10) boardframe .configure(padx=20, pady=20) for button in squarebuttons: button .configure(width=4, height=2) boardframe .pack(side=TOP) buttonframe .pack(side=TOP) statusframe .pack(side=TOP) newgamebutton .pack(side=LEFT) makemovebutton .pack(side=RIGHT) statuslabel .pack(side=TOP) for frame in rowframes: frame .pack(side=TOP) for button in squarebuttons: button .pack(side=LEFT) newgame() window.title(' tictactoe') window.mainloop() """ #) """ #) -- https://mail.python.or
how to get python version ?
hi is there something analogous to sys.platform that lets you get the version of python you're using? sorry if the question is too see-spot-run. thanks if you can help peace stm -- https://mail.python.org/mailman/listinfo/python-list