File: pygadgets-products/unzipped/_PyToe/TicTacToe/unconverted-python2X/temp.notes.txt

***PLEASE IGNORE THIS FILE***


_grid...

# Intro: Of course, you can get a lot of work done without
# Canvases too.  In fact, the ideas of packing frames and
# using grids are often suffiecient for contructing complex
# GUI layouts.  Our next example demonstrate this idea: it
# uses a simple grid of labels to build a game board.
# Tic-tac-toe, naughts-and-crosses, N-across
# by default, 3-across=ttt, but can vary Degree to change 
# board size (the number of row and column)
#
# - this is an application of grids, but too complex
#   to show where grids introduced--new case study at end
#   of gui chapter (?)
# - probs: pack mixed with grid if GuiMaker is used 
# - squares = {}   # or append cell to row, row to cols
# - cells and board share same State objects--changes to 
#   one auto noticed by other ref--ex of where shared objs
#   are a Good Thing  (could use lists instead of State attrs);
#
# add GuiMaker menus - quit, help=about box
#   from guimaker import GuiMakerWindow 
#
# alt in CountAcrossDown:
#   countRows = []
#   for row in range(self.degree):
#       countRows.append(tally.copy())
#       for col in range(self.degree):
#           mark = board[(row, col)]
#           countRows[row][mark] = countRows[row][mark] + 1
#
# ??? Degree chould probably be a self.attr so can vary per 
# instance in process (as is, can change module-level var
# from outside, but effects all games created before or after)
#    -> fixed, but mention diff in text
#
# mention uses dicts for board/counts; alt = [[0]*Degree]*Degree
# simulates a 2D matrix with a 1D hashtable, where keys=row,col 
# tuples;  (hash + tuple-compare) versus (offset + offset) -> faster?
#
# - mention minimax move lookahead search, versus heuristics only (see sbar)
# - mention tuple unpacking assigment in heuristic header
# - mention: originally had all moves selection logic in one
# big/long method; much more readable when split out into 
# separate methods--rule of thumb: keep methods short!
# if you find yourself adding comments before a big block of
# code because you can't understand what it does, it's probably
# time to move that block into a named method of its own.
# - mention that could use frames and pack here too--1 per row,
# but since I"m goin gto show you how to do this to build a
# calculator in the text processing chapter, I'll use grid here;
#
# ??? test degree = 4, 5, 2;  dumb mode
# ??? expand or change heuristic score logic?
# ??? GuiMaker not set up for grid() completely--makeWidgets, framemenus
# ??? resizing doesnt work
# ??? smart mode not working
# --- self.quit fails; Frame.quit(self) works; why???
#    NO->Frame.quit fails too; need sys.exit()
#        depends on what is next after test end call;
#        exits if nothing, else returns (quit doesn't end process)
#
#####################################################################
# Sidebar: Is PyToe artificially intelligent?  (end of chapter)
# Well, maybe, but it depends on what you call intelligent.
# PyToe is smart enough to notice imminent wins and losses,
# and to reasonably select from a set of alternative moves.
# When a win or loss isn't imminent, it uses a scoring scheme,
# sometimes called a _heuristic_, to rank the "goodness" of 
# alternative moves.
# 
# But PyToe's view is limited to the next move; it's unable to
# look ahead through a series of moves and countermoves to
# analyse the consequences of a given move.  Especially for
# more complex two-player games such as chess, it's more 
# traditional to search through all possible moves and 
# countermoves, and pick moves that maximize the chances of
# reaching a win, and minimize moves that can lead to a loss.
# In fact, there's a name for this technique: _minimax_ search.
# (VERIFY NAME)
# 
# Minimax game search is described fully in most AI texts.  But 
# roughly, such a search generates new boards ("states") for each
# possible move, with the candidate move made.  For each new board,
# it then generates boards with all possible countermoves, and so 
# on, generating all possible moves at each level, and detecting
# wins and loses along the way.  Such a search lets the program 
# look ahead in the game to be more informed about the consequences
# of its actions.  In practice, the search may stop after so many
# levels of lookahead, and apply a heuristic to score the resulting
# board state; especially for complex games or large boards, it's 
# not practical to explore all possible moves and countermoves 
# to end game states (you'd run out of time and memory).  PyToe
# picks moves with some intelligence, but has no notion of lookahead;
# that may be okay for this simple game, but may hurt in others.
# 
# But can PyToe be called an "expert system"--a system that encodes 
# and applies expert-level knowledge?  Again, maybe.  In some sense, 
# its move selection logic can be viewed as domain knowledge, encoded 
# in the Python language.  In fact, selects moves more or less the 
# way I would (though I usually look ahead to possible countermoves
# too).  General expert systems, though, usually encode domain 
# knowledge rules in a more symbolic form, and apply it using
# more general-purpose algorithms called "inference engines".
# We'll see such a system in the last chapter in this part of
# the book--the PyExpert expert system shell.
# 
# All of which doesn't quite answer the question this sidebar
# raises.  If pressed, I'd say you could call PyToe intelligent 
# if you can't tell it's a machine, and if it's smart enough 
# to beat you on a regular basis.  For me, that's a positive.
####################################################################



_dict...

# poss opts:
#    x make board just marks (not State), use board.copy() (not deepcopy) [this]
#    - don't board.copy(): make move, recur, unmake move (ok, since depth-1st)
#    - use arrays for board, indexing (not hash + compare)
#    - use scoreMove at cutoff depth
#
# see tictactoe_times.txt
#
# Poss: entire part3 chapter on AI:
#    - functional programming tools
#    - gaming
#    - holmes
# Intro: Of course, you can get a lot of work done without
# Canvases too.  In fact, the ideas of packing frames and
# using grids are often sufficient for contructing complex
# GUI layouts.  Our next example demonstrate this idea: it
# uses a simple grid of labels to build a game board.
# Tic-tac-toe, naughts-and-crosses, N-across
# by default, 3-across=ttt, but can vary Degree to change 
# board size (the number of row and column)
#
# - this is an application of grids, but too complex
#   to show where grids introduced--new case study at end
#   of gui chapter (?)
# - probs: pack mixed with grid if GuiMaker is used 
# - squares = {}   # or append cell to row, row to cols
# - cells and board share same State objects--changes to 
#   one auto noticed by other ref--ex of where shared objs
#   are a Good Thing  (could use lists instead of State attrs);
#
# add GuiMaker menus - quit, help=about box
#   from Gui.Tools.guimaker import GuiMakerWindow 
#
# alt in CountAcrossDown:
#   countRows = []
#   for row in range(self.degree):
#       countRows.append(tally.copy())
#       for col in range(self.degree):
#           mark = board[(row, col)]
#           countRows[row][mark] = countRows[row][mark] + 1
#
# --- Degree csould probably be a self.attr so can vary per 
# instance in process (as is, can change module-level var
# from outside, but effects all games created before or after)
#    -> fixed, but mention diff in text
#
# mention uses dicts for oard/counts; alt = [[0]*Degree]*Degree
# simulates a 2D matrix with a 1D hashtable, where keys=row,col 
# tuples;  (hash + tuple-compare) versus (offset + offset) -> faster?
#
# - mention minimax move lookahead search, versus heuristics only (see sbar)
# - mention tuple unpacking assigment in heuristic header
# - mention: originally had all moves selection logic in one
# big/long method; much more readable when split out into 
# separate methods--rule of thumb: keep methods short!
# if you find yourself adding comments before a big block of
# code because you can't understand what it does, it's probably
# time to move that block into a named method of its own.
# - mention that could use frames and pack here too--1 per row,
# but since I"m goin gto show you how to do this to build a
# calculator in the text processing chapter, I'll use grid here;
#
# grid resolution--use pack instead; to much of a hack to call
# makeWidgets outside of guimaker classes (need to avoid toplevel
# frame completely, else won't resize correctly--need grids within 
# grids, not frames)
#
# --- test degree = 4, 5, 2;  naive/dumb mode
# --- expand or change heuristic score logic?
# ??? GuiMaker not set up for grid() completely--makeWidgets, framemenus
# --- resizing doesnt work (does for frames)
# --- smart mode not working
# --- self.quit fails; Frame.quit(self) works; why?
#    NO->Frame.quit fails too; need sys.exit()
#        depends on what is next after test end call;
#        exits if nothing, else returns (quit doesn't end process)
# ---show cmdline exs: 
#    TicTacToe.py -degree 5 -mode naive -bg blue -fg white -fontsz 30
#    TicTacToe.py -degree 10 -fontsz 30
# ---mention precount so each test is a single hash op, not array scan
#
# ---isWinFor could reuse checkWin logic; move, ckeck, undo
#    changed -> now does
#
# coding alt: 
# Notice how the smart mode's move selection logic detects 
# imminent wins and losses: it mark a candidate move on 
# the board, rune the end-game win detector, and then unmarks
# the candidate move.  It plays a sort of 'what if' experiment.
# I originally coded smart mode's isWin/isLoss tests
# to use the count arrays rather than the end-game win check, 
# because I thought it would be faster (hashing versus multiple
# table scans).  As it turned out, pickMove was fast enough to 
# appear instantaneous, so I used the end-game chack instead.
# In fact, move selection is so fast, that I decide to add a 
# 2-secnd delay (time.sleep(2)), to make it easier for the user
# to notice which move hte machine picked.  (Years of using 
# slower AI languages have made me paranoid).
#               
#   def isWinFor(self, playerMark, 
#                (row, col), 
#                ((countRows, countCols), (countDiag1, countDiag2)) ):
#       return (
#           (countCols.get((col, playerMark), 0) == self.degree-1)
#            or
#           (countRows.get((row, playerMark), 0) == self.degree-1)
#            or
#           (row == col and 
#            countDiag1[playerMark] == self.degree-1)
#            or
#           (row + col == self.degree-1 and 
#            countDiag2[playerMark] == self.degree-1) )
#
#   def isWin(self, move, countMarks): 
#       return self.isWinFor(self.machineMark, move, countMarks)
#   def isBlock(self, move, countMarks): 
#       return self.isWinFor(self.userMark, move, countMarks)
#
#--nasty mode seems to lose for -degree 10 -- misses block!
#     FIXED: wasusing Degree, not self.degree, and need to divide
#            simplr score by board size, else gets larger than 
#            moves where patterns kicked in
#--center not used in nasty
#     OK! -> the diagonals don't intersect in an even-degree
#            board (e.g., 10x10), but do if odd (9x9)
#--remove trace calls
#
#???--can be beaten if pick corners 
#???--write grid/loop versionsas subclasses
#
#--alt: empties = filter((lambda coord, b=board: b[coord].mark == Empty), 
#                         board.keys())
# ???apply static score at cutoff levels
# ???verify minimax working: maxdepth correct?  values propogating ok?
#
# ??? minimax can still be beaten, if top row picked (lists) or
# left col picked (dict)
#
#####################################################################
####################################################################



_lists...

# poss opts:
#    x make board just marks (not State), use board.copy() (not deepcopy)
#    x use arrays for board, indexing (not hash + compare) [this]
#      also speeds draw and checkWin - use 'in' and list.count on entire row
#    - don't board.copy-- just set mark, recure, set Empty  [has little effect]
#    - use scoreMove at cutoff depth
#    - checkFinish should only look for wins at move just made, not all r,c
#
# Record class replaces record dictionary
#
# see tictactoe_times.txt:
#
#   4 times slower on DC power (better diffs, == slower machine)
#   (occasionally almost as fast on DC, iff CPU not scaled back when starts)
#
#   2D lists with row,col,player in checkWin???
#   2D lists are faster than dict board (1 sec at slow CPU)
#   mark/reur/empty not much faster than board.copy()
#   board.copy() much faster than copy.deepcopy()
#
# with lists, sometimes delays win, if can make a move that leads to
# a win 2 ways; depends on order of empties on board
#
# note that order of move picks varies between list and dict alts,
# because list alt checks empties by row and col, and dict alt
# checks empties by order in dict--board.keys(), which is random, 
# diff from fixed row/col scan; dict and list versions pick moves
# identically if dict version uses board.sort() to get fixed order:
# in findMin and findMax:
#
#      b = board.keys()
#      b.sort()              # order search by (row, col) tuples
#      for move in b:
#      #for move in board.keys():
#
# enable commented-out traces to see boards
#
# note that could also implement board as Button widgets, with 'command'
# callbacks (se calculator gui in lang chapter); here, coded as labels
# with mouse buttin press bind callbacks; effect is similar (but no
# depress effect on push like you get with buttons);
#
# Poss: entire part3 chapter on AI:
#    - functional programming tools
#    - gaming
#    - holmes
# Intro: Of course, you can get a lot of work done without
# Canvases too.  In fact, the ideas of packing frames and
# using grids are often sufficient for contructing complex
# GUI layouts.  Our next example demonstrate this idea: it
# uses a simple grid of labels to build a game board.
# Tic-tac-toe, naughts-and-crosses, N-across
# by default, 3-across=ttt, but can vary Degree to change 
# board size (the number of row and column)
#
# - this is an application of grids, but too complex
#   to show where grids introduced--new case study at end
#   of gui chapter (?)
# - probs: pack mixed with grid if GuiMaker is used 
# - squares = {}   # or append cell to row, row to cols
# - cells and board share same State objects--changes to 
#   one auto noticed by other ref--ex of where shared objs
#   are a Good Thing  (could use lists instead of State attrs);
#
# add GuiMaker menus - quit, help=about box
#   from guimaker import GuiMakerWindow 
#
# alt in CountAcrossDown:
#   countRows = []
#   for row in range(self.degree):
#       countRows.append(tally.copy())
#       for col in range(self.degree):
#           mark = board[(row, col)]
#           countRows[row][mark] = countRows[row][mark] + 1
#
# --- Degree csould probably be a self.attr so can vary per 
# instance in process (as is, can change module-level var
# from outside, but effects all games created before or after)
#    -> fixed, but mention diff in text
#
# mention uses dicts for oard/counts; alt = [[0]*Degree]*Degree
# simulates a 2D matrix with a 1D hashtable, where keys=row,col 
# tuples;  (hash + tuple-compare) versus (offset + offset) -> faster?
#
# - mention minimax move lookahead search, versus heuristics only (see sbar)
# - mention tuple unpacking assigment in heuristic header
# - mention: originally had all moves selection logic in one
# big/long method; much more readable when split out into 
# separate methods--rule of thumb: keep methods short!
# if you find yourself adding comments before a big block of
# code because you can't understand what it does, it's probably
# time to move that block into a named method of its own.
# - mention that could use frames and pack here too--1 per row,
# but since I"m goin gto show you how to do this to build a
# calculator in the text processing chapter, I'll use grid here;
#
# grid resolution--use pack instead; to much of a hack to call
# makeWidgets outside of guimaker classes (need to avoid toplevel
# frame completely, else won't resize correctly--need grids within 
# grids, not frames)
#
# --- test degree = 4, 5, 2;  naive/dumb mode
# --- expand or change heuristic score logic?
# ??? GuiMaker not set up for grid() completely--makeWidgets, framemenus
# --- resizing doesnt work (does for frames)
# --- smart mode not working
# --- self.quit fails; Frame.quit(self) works; why?
#    NO->Frame.quit fails too; need sys.exit()
#        depends on what is next after test end call;
#        exits if nothing, else returns (quit doesn't end process)
# ---show cmdline exs: 
#    TicTacToe.py -degree 5 -mode naive -bg blue -fg white -fontsz 30
#    TicTacToe.py -degree 10 -fontsz 30
# ---mention precount so each test is a single hash op, not array scan
#
# ---isWinFor could reuse checkWin logic; move, ckeck, undo
#    changed -> now does
#
# coding alt: 
# Notice how the smart mode's move selection logic detects 
# imminent wins and losses: it mark a candidate move on 
# the board, rune the end-game win detector, and then unmarks
# the candidate move.  It plays a sort of 'what if' experiment.
# I originally coded smart mode's isWin/isLoss tests
# to use the count arrays rather than the end-game win check, 
# because I thought it would be faster (hashing versus multiple
# table scans).  As it turned out, pickMove was fast enough to 
# appear instantaneous, so I used the end-game chack instead.
# In fact, move selection is so fast, that I decide to add a 
# 2-secnd delay (time.sleep(2)), to make it easier for the user
# to notice which move hte machine picked.  (Years of using 
# slower AI languages have made me paranoid).
#               
#   def isWinFor(self, playerMark, 
#                (row, col), 
#                ((countRows, countCols), (countDiag1, countDiag2)) ):
#       return (
#           (countCols.get((col, playerMark), 0) == self.degree-1)
#            or
#           (countRows.get((row, playerMark), 0) == self.degree-1)
#            or
#           (row == col and 
#            countDiag1[playerMark] == self.degree-1)
#            or
#           (row + col == self.degree-1 and 
#            countDiag2[playerMark] == self.degree-1) )
#
#   def isWin(self, move, countMarks): 
#       return self.isWinFor(self.machineMark, move, countMarks)
#   def isBlock(self, move, countMarks): 
#       return self.isWinFor(self.userMark, move, countMarks)
#
#--nasty mode seems to lose for -degree 10 -- misses block!
#     FIXED: wasusing Degree, not self.degree, and need to divide
#            simplr score by board size, else gets larger than 
#            moves where patterns kicked in
#--center not used in nasty
#     OK! -> the diagonals don't intersect in an even-degree
#            board (e.g., 10x10), but do if odd (9x9)
#--remove trace calls
#
#???--can be beaten if pick corners 
#     - too pesimistic; if all look like min can win (-1),
#       use static eval at top;
#           => DONE, 11/11 (can still beat, but not by 
#              picking all in top row, r-to-l)
#???--write grid/loop version as subclasses
#???--add text mode as subclass; loop version?
#???--recode to only check win for last mover (or exercise)
#
#--alt: empties = filter((lambda coord, b=board: b[coord].mark == Empty), 
#                         board.keys())
#--this fails:  self.board = [[0] * self.degree] * self.degree              
#--note 3L formula in expert2; else overflows normal int
#
# ???apply static score at cutoff levels
# ???verify minimax working: maxdepth correct?  values propogating ok?
#
#####################################################################
#
# exponential nature of game tree searches
# minimax not practical for larger boards
# as is, at degree=5, after opening move by user, there are:
#     24 * 23 * 22 * 21 * 20 = 5,100,480 board states to analyse
#       - 25 slots - 1 taken = 24 possible moves
#       - for each othe 24 possible moves, there are 23 countermoves (2 taken)
#       - for each of the 23 countermoves, 22 possible next moves (3 taken)
#       - maxDepth will be 1 (numer marks) + 4 = 5 levels deep
# work totally pointless on larger boards, since neither player will 
#   reach a win after just 5 moves
# need to stop and statically score board a some fixed depth
# alpha-beta cutoff helps trim search space
#
# self.after_idle(self.machineMove)
#  doe not work to keep gui active while piccking move; 
#  no widget updates while 'thinking'; could code move
#  picker as a thread, call self.update before start a
#  new search node, etc.
#
#show 3 alts: all poss dueto fact that classes are rt objs, not decls
#
#def TicTacToe(mode=Mode, **args):
#    try:
#        classname = 'TicTacToe' + mode            # e.g., -mode Minimax
#        classobj  = eval(classname)               # get class by string name
#    except:
#        print 'Bad -mode flag value:', mode
#    return apply(eval(classname), (), args)       # run class constructor
#
#
#    classes = {'random':  TicTacToeRandom,
#               'smart':   TicTacToeSmart,
#               'expert1': TicTacToeExpert1,
#               'expert2': TicTacToeExpert2,
#               'minimax': TicTacToeMinimax}
#    try: 
#        return apply(classes[mode], (), args)
#    except KeyError:
#        print 'Bad -mode flag value:', mode
#
#
#    if mode == 'random':
#        return apply(TicTacToeRandom,  (), args)
#    if mode == 'smart':
#        return apply(TicTacToeSmart, (), args)
#    if mode == 'expert1':
#        return apply(TicTacToeExpert1, (), args)
#    if mode == 'expert2':
#        return apply(TicTacToeExpert2, (), args)
#    if mode == 'minimax':
#        return apply(TicTacToeMinimax, (), args)
#    assert 0, 'Bad mode argument'
#####################################################################
# Sidebar: Is PyToe artificially intelligent?  (end of chapter)
# Well, maybe, but it depends on what you call intelligent.
# PyToe is smart enough to notice imminent wins and losses,
# and to reasonably select from a set of alternative moves.
# When a win or loss isn't imminent, it uses a scoring scheme,
# sometimes called a _heuristic_, to rank the "goodness" of 
# alternative moves.
# 
# But PyToe's view is limited to the next move; it's unable to
# look ahead through a series of moves and countermoves to
# analyse the consequences of a given move.  Especially for
# more complex two-player games such as chess, it's more 
# traditional to search through all possible moves and 
# countermoves, and pick moves that maximize the chances of
# reaching a win, and minimize moves that can lead to a loss.
# In fact, there's a name for this technique: _minimax_ search.
# (VERIFY NAME)
# 
# Minimax game search is described fully in most AI texts.  But 
# roughly, such a search generates new boards ("states") for each
# possible move, with the candidate move made.  For each new board,
# it then generates boards with all possible countermoves, and so 
# on, generating all possible moves at each level, and detecting
# wins and loses along the way.  Such a search lets the program 
# look ahead in the game to be more informed about the consequences
# of its actions.  In practice, the search may stop after so many
# levels of lookahead, and apply a heuristic to score the resulting
# board state; especially for complex games or large boards, it's 
# not practical to explore all possible moves and countermoves 
# to end game states (you'd run out of time and memory).  PyToe
# picks moves with some intelligence, but has no notion of lookahead;
# that may be okay for this simple game, but may hurt in others.
# (Acutally, the 'nasty' mode's scoring system accounts for wins
# and losses 2 moves away; but to look further ahead, we'd need
# to kepp adding hard-coded rules, and this is less than a general
# algorithm solution).
# 
# But can PyToe be called an "expert system"--a system that encodes 
# and applies expert-level knowledge?  Again, maybe.  In some sense, 
# its move selection logic can be viewed as domain knowledge, encoded 
# in the Python language.  In fact, selects moves more or less the 
# way I would (though I usually look ahead to possible countermoves
# too).  General expert systems, though, usually encode domain 
# knowledge rules in a more symbolic form, and apply it using
# more general-purpose algorithms called "inference engines".
# We'll see such a system in the last chapter in this part of
# the book--the PyExpert expert system shell.
####################################################################




_loop...

# Intro: Of course, you can get a lot of work done without
# Canvases too.  In fact, the ideas of packing frames and
# using grids are often suffiecient for contructing complex
# GUI layouts.  Our next example demonstrate this idea: it
# uses a simple grid of labels to build a game board.
# Tic-tac-toe, naughts-and-crosses, N-across
# by default, 3-across=ttt, but can vary Degree to change 
# board size (the number of row and column)
#
# - this is an application of grids, but too complex
#   to show where grids introduced--new case study at end
#   of gui chapter (?)
# - probs: pack mixed with grid if GuiMaker is used 
# - squares = {}   # or append cell to row, row to cols
# - cells and board share same State objects--changes to 
#   one auto noticed by other ref--ex of where shared objs
#   are a Good Thing  (could use lists instead of State attrs);
#
# add GuiMaker menus - quit, help=about box
#   from guimaker import GuiMakerWindow 
#
# alt in CountAcrossDown:
#   countRows = []
#   for row in range(self.degree):
#       countRows.append(tally.copy())
#       for col in range(self.degree):
#           mark = board[(row, col)]
#           countRows[row][mark] = countRows[row][mark] + 1
#
# ??? Degree chould probably be a self.attr so can vary per 
# instance in process (as is, can change module-level var
# from outside, but effects all games created before or after)
#    -> fixed, but mention diff in text
#
# mention uses dicts for oard/counts; alt = [[0]*Degree]*Degree
# simulates a 2D matrix with a 1D hashtable, where keys=row,col 
# tuples;  (hash + tuple-compare) versus (offset + offset) -> faster?
#
# - mention minimax move lookahead search, versus heuristics only (see sbar)
# - mention tuple unpacking assigment in heuristic header
# - mention: originally had all moves selection logic in one
# big/long method; much more readable when split out into 
# separate methods--rule of thumb: keep methods short!
# if you find yourself adding comments before a big block of
# code because you can't understand what it does, it's probably
# time to move that block into a named method of its own.
# - mention that could use frames and pack here too--1 per row,
# but since I"m goin gto show you how to do this to build a
# calculator in the text processing chapter, I'll use grid here;
#
# ??? test degree = 4, 5, 2;  dumb mode
# ??? expand or change heuristic score logic?
# ??? GuiMaker not set up for grid() completely--makeWidgets, framemenus
# ??? resizing doesnt work
# ??? smart mode not working
# --- self.quit fails; Frame.quit(self) works; why???
#    NO->Frame.quit fails too; need sys.exit()
#        depends on what is next after test end call;
#        exits if nothing, else returns (quit doesn't end process)
#
# ??? recoded with explicit play() loop, not sys.exit();
# explain wait_variable(var): puases caller until the 
# variable (a Tkinter variable, not plain Python var) has
# changed value; set in button-press handler; other GUI 
# actions and events are processed during wait, so screen
# will redraw, File/Quit ends program/gui, etc.; Tkinter
# vars are global in scope, but Tkinter auto generates 
# and uses unique Tk var names behind the scenes--treat
# like normal Python objects;
# show older version as alt coding:
#    ???  (is the alt more event driven?)
#        What if they click mouse before loop gets back to wait?
#
#####################################################################
###################################################################




_slow...

# Poss: entire part3 chapter on AI:
#    - functional programming tools
#    - gaming
#    - holmes
# Intro: Of course, you can get a lot of work done without
# Canvases too.  In fact, the ideas of packing frames and
# using grids are often sufficient for contructing complex
# GUI layouts.  Our next example demonstrate this idea: it
# uses a simple grid of labels to build a game board.
# Tic-tac-toe, naughts-and-crosses, N-across
# by default, 3-across=ttt, but can vary Degree to change 
# board size (the number of row and column)
#
# - this is an application of grids, but too complex
#   to show where grids introduced--new case study at end
#   of gui chapter (?)
# - probs: pack mixed with grid if GuiMaker is used 
# - squares = {}   # or append cell to row, row to cols
# - cells and board share same State objects--changes to 
#   one auto noticed by other ref--ex of where shared objs
#   are a Good Thing  (could use lists instead of State attrs);
#
# add GuiMaker menus - quit, help=about box
#   from guimaker import GuiMakerWindow 
#
# alt in CountAcrossDown:
#   countRows = []
#   for row in range(self.degree):
#       countRows.append(tally.copy())
#       for col in range(self.degree):
#           mark = board[(row, col)]
#           countRows[row][mark] = countRows[row][mark] + 1
#
# --- Degree csould probably be a self.attr so can vary per 
# instance in process (as is, can change module-level var
# from outside, but effects all games created before or after)
#    -> fixed, but mention diff in text
#
# mention uses dicts for oard/counts; alt = [[0]*Degree]*Degree
# simulates a 2D matrix with a 1D hashtable, where keys=row,col 
# tuples;  (hash + tuple-compare) versus (offset + offset) -> faster?
#
# - mention minimax move lookahead search, versus heuristics only (see sbar)
# - mention tuple unpacking assigment in heuristic header
# - mention: originally had all moves selection logic in one
# big/long method; much more readable when split out into 
# separate methods--rule of thumb: keep methods short!
# if you find yourself adding comments before a big block of
# code because you can't understand what it does, it's probably
# time to move that block into a named method of its own.
# - mention that could use frames and pack here too--1 per row,
# but since I"m goin gto show you how to do this to build a
# calculator in the text processing chapter, I'll use grid here;
#
# grid resolution--use pack instead; to much of a hack to call
# makeWidgets outside of guimaker classes (need to avoid toplevel
# frame completely, else won't resize correctly--need grids within 
# grids, not frames)
#
# --- test degree = 4, 5, 2;  naive/dumb mode
# --- expand or change heuristic score logic?
# ??? GuiMaker not set up for grid() completely--makeWidgets, framemenus
# --- resizing doesnt work (does for frames)
# --- smart mode not working
# --- self.quit fails; Frame.quit(self) works; why?
#    NO->Frame.quit fails too; need sys.exit()
#        depends on what is next after test end call;
#        exits if nothing, else returns (quit doesn't end process)
# ---show cmdline exs: 
#    TicTacToe.py -degree 5 -mode naive -bg blue -fg white -fontsz 30
#    TicTacToe.py -degree 10 -fontsz 30
# ---mention precount so each test is a single hash op, not array scan
#
# ---isWinFor could reuse checkWin logic; move, ckeck, undo
#    changed -> now does
#
# coding alt: 
# Notice how the smart mode's move selection logic detects 
# imminent wins and losses: it mark a candidate move on 
# the board, rune the end-game win detector, and then unmarks
# the candidate move.  It plays a sort of 'what if' experiment.
# I originally coded smart mode's isWin/isLoss tests
# to use the count arrays rather than the end-game win check, 
# because I thought it would be faster (hashing versus multiple
# table scans).  As it turned out, pickMove was fast enough to 
# appear instantaneous, so I used the end-game chack instead.
# In fact, move selection is so fast, that I decide to add a 
# 2-secnd delay (time.sleep(2)), to make it easier for the user
# to notice which move hte machine picked.  (Years of using 
# slower AI languages have made me paranoid).
#               
#   def isWinFor(self, playerMark, 
#                (row, col), 
#                ((countRows, countCols), (countDiag1, countDiag2)) ):
#       return (
#           (countCols.get((col, playerMark), 0) == self.degree-1)
#            or
#           (countRows.get((row, playerMark), 0) == self.degree-1)
#            or
#           (row == col and 
#            countDiag1[playerMark] == self.degree-1)
#            or
#           (row + col == self.degree-1 and 
#            countDiag2[playerMark] == self.degree-1) )
#
#   def isWin(self, move, countMarks): 
#       return self.isWinFor(self.machineMark, move, countMarks)
#   def isBlock(self, move, countMarks): 
#       return self.isWinFor(self.userMark, move, countMarks)
#
#--nasty mode seems to lose for -degree 10 -- misses block!
#     FIXED: wasusing Degree, not self.degree, and need to divide
#            simplr score by board size, else gets larger than 
#            moves where patterns kicked in
#--center not used in nasty
#     OK! -> the diagonals don't intersect in an even-degree
#            board (e.g., 10x10), but do if odd (9x9)
#--remove trace calls
#
#???--can be beaten if pick corners 
#???--write grid/loop versionsas subclasses
#
#       empties = filter((lambda coord, b=board: b[coord].mark == Empty), 
#                         board.keys())
#
#####################################################################
#####################################################################





[Home page] Books Code Blog Python Author Train Find ©M.Lutz