Example #1
0
// Roughly orders moves in order of most likely to be good to least.
// Examines all checks first, followed by captures, followed by good moves.
// "Good moves" are sorted by their board evaluation after they are played.
// If quiescence is set to true, then only checks and captures are returned.
func orderedMoves(b *engine.Board, quiescence bool) []*engine.Move {
	checks := make([]*engine.Move, 0)
	captures := make([]*engine.Move, 0)
	rest := make([]*engine.Move, 0)
	// parentscore := EvalBoard(b)
	for _, move := range b.AllLegalMoves() {
		b.ForceMove(move)
		if b.IsCheck(b.Turn) {
			checks = append(checks, move)
		} else if move.Capture != 0 {
			captures = append(captures, move)
		} else if !quiescence {
			childscore := EvalBoard(b) * float64(b.Turn*-1)
			// if (b.Turn == -1 && childscore > parentscore) || (b.Turn == 1 && childscore < parentscore) {
			move.Score = childscore
			rest = append(rest, move)
			// }
		}
		b.UndoMove(move)
	}
	if !quiescence {
		sort.Sort(sort.Reverse(ByScore(rest)))
	}
	orderedmoves := make([]*engine.Move, len(checks)+len(captures)+len(rest))
	index := 0
	for _, l := range [][]*engine.Move{checks, captures, rest} {
		for _, m := range l {
			m.Score = 0
			orderedmoves[index] = m
			index++
		}
	}
	return orderedmoves
}
Example #2
0
// Child level returns an evaluation
func AlphaBetaChild(b *engine.Board, depth int, alpha, beta float64, volatile bool) float64 {
	var movelist []*engine.Move
	if b.IsOver() != 0 {
		return EvalBoard(b)
	} else if depth == 0 {
		if !volatile {
			return EvalBoard(b)
		}
		depth += 1
		movelist = orderedMoves(b, true)
	} else {
		movelist = orderedMoves(b, false)
	}
	var score float64
	if b.Turn == 1 {
		for _, move := range movelist {
			b.ForceMove(move)
			if !volatile && (move.Capture != 0 || b.IsCheck(b.Turn)) {
				score = AlphaBetaChild(b, depth-1, alpha, beta, true)
			} else {
				score = AlphaBetaChild(b, depth-1, alpha, beta, false)
			}
			b.UndoMove(move)
			if score > alpha {
				alpha = score
			}
			if alpha >= beta {
				return alpha
			}
		}
		return alpha
	} else {
		for _, move := range movelist {
			b.ForceMove(move)
			if !volatile && (move.Capture != 0 || b.IsCheck(b.Turn)) {
				score = AlphaBetaChild(b, depth-1, alpha, beta, true)
			} else {
				score = AlphaBetaChild(b, depth-1, alpha, beta, false)
			}
			b.UndoMove(move)
			if score < beta {
				beta = score
			}
			if beta <= alpha {
				return beta
			}
		}
		return beta
	}
	return 0
}
Example #3
0
// 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
}