// First-level NegaScout search function. // When called, alpha and beta should be set to the lowest and highest values possible. func NegaScout(b *engine.Board, depth int, alpha, beta float64) *engine.Move { if b.IsOver() != 0 || depth == 0 { b.Lastmove.Score = EvalBoard(b) return &b.Lastmove } var move engine.Move // not indended for actual use orderedmoves := b.AllLegalMoves() var score float64 for i, m := range orderedmoves { childboard := b.CopyBoard() childboard.Move(m) if i != 0 { score = -NegaScoutChild(childboard, depth-1, -alpha-1, -alpha) if alpha < score && score < beta { score = -NegaScoutChild(childboard, depth-1, -beta, -alpha) } } else { score = -NegaScoutChild(childboard, depth-1, -beta, -alpha) } alpha = math.Max(alpha, score) if alpha >= beta { move = *m.CopyMove() move.Score = alpha break } } return &move }
// First-level negamax search function. func NegaMax(b *engine.Board, depth int) *engine.Move { if b.IsOver() != 0 || depth == 0 { b.Lastmove.Score = EvalBoard(b) return &b.Lastmove } var move engine.Move move.Score = LOSS for _, m := range b.AllLegalMoves() { childboard := b.CopyBoard() childboard.Move(m) childscore := -NegaMaxChild(childboard, depth-1) if childscore > move.Score { move = *m.CopyMove() move.Score = childscore if move.Score == WIN { return &move } } } return &move }
// Standard minmax search with alpha beta pruning. // Initial call: alpha set to lowest value, beta set to highest. // Top level returns a move. func AlphaBeta(b *engine.Board, depth int, alpha, beta float64) *engine.Move { if b.IsOver() != 0 || depth == 0 { return nil } var bestmove *engine.Move = nil var result float64 movelist := orderedMoves(b, false) if b.Turn == 1 { for _, move := range movelist { b.ForceMove(move) if move.Capture != 0 || b.IsCheck(b.Turn) { result = AlphaBetaChild(b, depth-1, alpha, beta, true) } else { result = AlphaBetaChild(b, depth-1, alpha, beta, false) } b.UndoMove(move) if result > alpha { alpha = result bestmove = move bestmove.Score = alpha } if alpha >= beta { bestmove = move bestmove.Score = alpha return bestmove } } if bestmove == nil { return b.AllLegalMoves()[0] } return bestmove } else { for _, move := range movelist { b.ForceMove(move) if move.Capture != 0 || b.IsCheck(b.Turn) { result = AlphaBetaChild(b, depth-1, alpha, beta, true) } else { result = AlphaBetaChild(b, depth-1, alpha, beta, false) } if LOG { fmt.Println(move.ToString(), result) } b.UndoMove(move) if result < beta { beta = result bestmove = move bestmove.Score = beta } if beta <= alpha { bestmove = move bestmove.Score = beta return bestmove } } if bestmove == nil { return b.AllLegalMoves()[0] } return bestmove } if bestmove == nil { return b.AllLegalMoves()[0] } return bestmove }