@@ -42,39 +42,40 @@ def min_value(state):
4242# ______________________________________________________________________________
4343
4444def expectiminimax (state , game ):
45- """Returns the best move for a player after dice are thrown. The game tree
45+ """Return the best move for a player after dice are thrown. The game tree
4646 includes chance nodes along with min and max nodes. [Figure 5.11]"""
4747 player = game .to_move (state )
4848
49- def max_value (state ):
50- if game .terminal_test (state ):
51- return game .utility (state , player )
49+ def max_value (state , dice_roll ):
5250 v = - infinity
5351 for a in game .actions (state ):
5452 v = max (v , chance_node (state , a ))
53+ game .dice_roll = dice_roll
5554 return v
5655
57- def min_value (state ):
58- if game .terminal_test (state ):
59- return game .utility (state , player )
56+ def min_value (state , dice_roll ):
6057 v = infinity
6158 for a in game .actions (state ):
6259 v = min (v , chance_node (state , a ))
60+ game .dice_roll = dice_roll
6361 return v
6462
6563 def chance_node (state , action ):
6664 res_state = game .result (state , action )
65+ if game .terminal_test (res_state ):
66+ return game .utility (res_state , player )
6767 sum_chances = 0
6868 num_chances = 21
6969 dice_rolls = list (itertools .combinations_with_replacement ([1 , 2 , 3 , 4 , 5 , 6 ], 2 ))
7070 if res_state .to_move == 'W' :
7171 for val in dice_rolls :
7272 game .dice_roll = (- val [0 ], - val [1 ])
73- sum_chances += max_value (res_state ) * (1 / 36 if val [0 ] == val [1 ] else 1 / 18 )
73+ sum_chances += max_value (res_state ,
74+ (- val [0 ], - val [1 ])) * (1 / 36 if val [0 ] == val [1 ] else 1 / 18 )
7475 elif res_state .to_move == 'B' :
7576 for val in dice_rolls :
7677 game .dice_roll = val
77- sum_chances += min_value (res_state ) * (1 / 36 if val [0 ] == val [1 ] else 1 / 18 )
78+ sum_chances += min_value (res_state , val ) * (1 / 36 if val [0 ] == val [1 ] else 1 / 18 )
7879 return sum_chances / num_chances
7980
8081 # Body of expectiminimax:
@@ -403,6 +404,8 @@ def actions(self, state):
403404 """Returns a list of legal moves for a state."""
404405 player = state .to_move
405406 moves = state .moves
407+ if len (moves ) == 1 and len (moves [0 ]) == 1 :
408+ return moves
406409 legal_moves = []
407410 for move in moves :
408411 board = copy .deepcopy (state .board )
@@ -414,10 +417,11 @@ def result(self, state, move):
414417 board = copy .deepcopy (state .board )
415418 player = state .to_move
416419 board .move_checker (move [0 ], self .dice_roll [0 ], player )
417- board .move_checker (move [1 ], self .dice_roll [1 ], player )
420+ if len (move ) == 2 :
421+ board .move_checker (move [1 ], self .dice_roll [1 ], player )
418422 to_move = ('W' if player == 'B' else 'B' )
419423 return GameState (to_move = to_move ,
420- utility = self .compute_utility (board , move , to_move ),
424+ utility = self .compute_utility (board , move , player ),
421425 board = board ,
422426 moves = self .get_all_moves (board , to_move ))
423427
@@ -437,6 +441,8 @@ def get_all_moves(self, board, player):
437441 all_points = board .points
438442 taken_points = [index for index , point in enumerate (all_points )
439443 if point [player ] > 0 ]
444+ if board .checkers_at_home (player ) == 1 :
445+ return [(taken_points [0 ], )]
440446 moves = list (itertools .permutations (taken_points , 2 ))
441447 moves = moves + [(index , index ) for index , point in enumerate (all_points )
442448 if point [player ] >= 2 ]
@@ -446,11 +452,11 @@ def display(self, state):
446452 """Display state of the game."""
447453 board = state .board
448454 player = state .to_move
455+ print ("Current State : " )
449456 for index , point in enumerate (board .points ):
450457 if point ['W' ] != 0 or point ['B' ] != 0 :
451- print ("Point : " , index , " W : " , point ['W' ], " B : " , point ['B' ])
452- print ("player : " , player )
453-
458+ print ("Point : " , index , " W : " , point ['W' ], " B : " , point ['B' ])
459+ print ("To play : " , player )
454460
455461 def compute_utility (self , board , move , player ):
456462 """If 'W' wins with this move, return 1; if 'B' wins return -1; else return 0."""
@@ -482,7 +488,7 @@ def __init__(self):
482488 self .allow_bear_off = {'W' : False , 'B' : False }
483489
484490 def checkers_at_home (self , player ):
485- """Returns the no. of checkers at home for a player."""
491+ """Return the no. of checkers at home for a player."""
486492 sum_range = range (0 , 7 ) if player == 'W' else range (17 , 24 )
487493 count = 0
488494 for idx in sum_range :
@@ -516,7 +522,7 @@ def is_legal_move(self, start, steps, player):
516522 return move1_legal and move2_legal
517523
518524 def move_checker (self , start , steps , player ):
519- """Moves a checker from starting point by a given number of steps"""
525+ """Move a checker from starting point by a given number of steps"""
520526 dest = start + steps
521527 dest_range = range (0 , 24 )
522528 self .points [start ][player ] -= 1
0 commit comments