// Play asks for input from an external source until a valid move is given. func (human *HumanAgent) Play( referee *mancala.Referee, player mancala.PlayerIndex, ) (mancala.HouseIndex, error) { move := mancala.HouseIndex(-1) var moveLine string for move == -1 { fmt.Printf("%s, make a move:\n", strings.Title(player.String())) fmt.Scanf("%s", &moveLine) fmt.Println() parsedMove, err := strconv.Atoi(moveLine) if err != nil { fmt.Println("Input must be an integer.") fmt.Println() moveLine = "" } else if _, err := referee.SimulateMove( player, mancala.HouseIndex(parsedMove), ); err != nil { fmt.Printf("Illegal move: %v.\n", err) fmt.Println() moveLine = "" move = -1 } else { move = mancala.HouseIndex(parsedMove) } } return move, nil }
// testCaptureLoop is a simulateTestCaseGenerator which generates a test case // where the current mancala.Player captures after looping around the // mancala.Board. func testCaptureLoop(player mancala.PlayerIndex) simulateTestCase { grid := mancala.Grid{} grid[player] = mancala.Row{17, 0, 0, 0, 0, 0} grid[player.Other()] = mancala.Row{} board := mancala.NewInitializedBoard(0, 0, grid) expectedGrid := mancala.Grid{} expectedGrid[player] = mancala.Row{0, 2, 2, 2, 2, 2} expectedGrid[player.Other()] = mancala.Row{0, 1, 1, 1, 1, 1} player1Score := 0 player2Score := 0 if player == mancala.Player1 { player1Score += 2 } else { player2Score += 2 } expectedBoard := mancala.NewInitializedBoard( player1Score, player2Score, expectedGrid, ) return simulateTestCase{ referee: mancala.NewInitializedReferee( []mancala.Board{}, board, ), move: 0, expectedBoard: expectedBoard, expectedErr: nil, } }
// testAlreadySeenBoard is a simulateTestCaseGenerator which generates a test // case where the current mancala.Board is in the mancala.Referee's // mancala.Board history. func testAlreadySeenBoard(player mancala.PlayerIndex) simulateTestCase { seenGrid := mancala.Grid{} seenGrid[player] = mancala.Row{0, 1, 1, 1, 1, 1} seenGrid[player.Other()] = mancala.Row{1, 0, 0, 0, 0, 0} grid := mancala.Grid{} grid[player] = mancala.Row{5, 0, 0, 0, 0, 0} grid[player.Other()] = mancala.Row{1, 0, 0, 0, 0, 0} referee := mancala.NewInitializedReferee( []mancala.Board{mancala.NewInitializedBoard(0, 0, seenGrid)}, mancala.NewInitializedBoard(0, 0, grid), ) player1Score := 0 player2Score := 0 if player == mancala.Player1 { player1Score += 5 player2Score++ } else { player2Score += 5 player1Score++ } expectedBoard := mancala.NewInitializedBoard( player1Score, player2Score, mancala.Grid{}, ) return simulateTestCase{ referee: referee, move: 0, expectedBoard: expectedBoard, expectedErr: nil, } }
// NewRootState creates the root State of a mancala game search tree with a // mancala.Referee and mancala.PlayerIndex. func NewRootState( referee *mancala.Referee, index mancala.PlayerIndex, ) *State { return &State{ parent: nil, referee: referee, information: NewInformation(referee.Board(), index.Other(), -1), } }
// ProtectValueChecker is a ValueChecker which returns the number of seeds the // opponent can capture after a move multipled by -1, showing that moves which // let opponent's capture more seeds are unfavorable. func ProtectValueChecker(state *State, index mancala.PlayerIndex) int { var max int first := true for _, child := range state.ReachableStates() { captured := CaptureValueChecker(child, index.Other()) if first || captured > max { max = captured first = false } } return -max }
// testCaptureAllHouses is a simulateTestCaseGenerator which generates a test // case where the current mancala.Player captures all of the other // mancala.Player's houses from the end of the other mancala.Player's row to the // beginning. func testCaptureAllHouses(player mancala.PlayerIndex) simulateTestCase { grid := mancala.Grid{} grid[player] = mancala.Row{0, 0, 0, 0, 0, 6} grid[player.Other()] = mancala.Row{1, 1, 1, 1, 1, 1} board := mancala.NewInitializedBoard(0, 0, grid) expectedGrid := mancala.Grid{} expectedGrid[player] = mancala.Row{} expectedGrid[player.Other()] = mancala.Row{2, 2, 2, 2, 2, 2} expectedBoard := mancala.NewInitializedBoard(0, 0, expectedGrid) return simulateTestCase{ referee: mancala.NewInitializedReferee( []mancala.Board{}, board, ), move: 5, expectedBoard: expectedBoard, expectedErr: nil, } }
// testSowLoopToStart is a simulateTestCaseGenerator which generates a test case // where the current mancala.Player sows in a loop around the mancala.Board just // past the house the mancala.Player started sowing from. func testSowLoopToStart(player mancala.PlayerIndex) simulateTestCase { grid := mancala.Grid{} grid[player] = mancala.Row{0, 0, 0, 0, 0, 45} grid[player.Other()] = mancala.Row{} board := mancala.NewInitializedBoard(0, 0, grid) expectedGrid := mancala.Grid{} expectedGrid[player] = mancala.Row{4, 4, 4, 4, 4, 0} expectedGrid[player.Other()] = mancala.Row{5, 4, 4, 4, 4, 4} expectedBoard := mancala.NewInitializedBoard(0, 0, expectedGrid) return simulateTestCase{ referee: mancala.NewInitializedReferee( []mancala.Board{}, board, ), move: 5, expectedBoard: expectedBoard, expectedErr: nil, } }
// testSowToOtherSide is a simulateTestCaseGenerator which generates a test case // where the current mancala.Player sows to the middle of the other // mancala.Player's mancala.Row. func testSowToOtherSide(player mancala.PlayerIndex) simulateTestCase { grid := mancala.Grid{} grid[player] = mancala.Row{0, 0, 6, 0, 0, 0} grid[player.Other()] = mancala.Row{} board := mancala.NewInitializedBoard(0, 0, grid) expectedGrid := mancala.Grid{} expectedGrid[player] = mancala.Row{0, 0, 0, 1, 1, 1} expectedGrid[player.Other()] = mancala.Row{1, 1, 1, 0, 0, 0} expectedBoard := mancala.NewInitializedBoard(0, 0, expectedGrid) return simulateTestCase{ referee: mancala.NewInitializedReferee( []mancala.Board{}, board, ), move: 2, expectedBoard: expectedBoard, expectedErr: nil, } }
// testNoSeeds is a simulateTestCaseGenerator which generates a test case where // the other mancala.Player has no seeds and the current mancala.Player has a // move which will give the other mancala.Player seeds and doesn't make it. func testNoSeedsCanReach(player mancala.PlayerIndex) simulateTestCase { grid := mancala.Grid{} grid[player] = mancala.Row{1, 0, 0, 0, 0, 1} board := mancala.NewInitializedBoard(0, 0, grid) return simulateTestCase{ referee: mancala.NewInitializedReferee( []mancala.Board{}, board, ), move: 0, expectedBoard: board, expectedErr: fmt.Errorf( "moves exist which can give %v seeds but move at %d "+ "doesn't", player.Other(), 0, ), } }