Skip to content

Instantly share code, notes, and snippets.

func negamax(position: Board, players: [Player], whoseTurn: Player, depth: Int, alpha: Int = Int.min, beta: Int = Int.max) -> (Int, Move?) {
let moves = position.generateMoves(player: whoseTurn)
if position.thereIsAWinner() != nil || (depth == 0) {
return (position.evaluate(evaluationFlags: appState.evaluationFlags, board: position, whoseTurn: whoseTurn, nextPlayer: nextPlayer(player: whoseTurn)), nil)
}
var bestScore = Int.min
var bestMove: Move?
for move in moves {
let clone = position.clone()
let _ = clone.makeMove(move: move, depth: depth)
// avoiding error where -Int.max (and maybe -Int.min) result in numeric overflow
// this could be more efficient with constants like let infinity = Int.max - 10
func negate(number: Int) -> Int {
if number == Int.max { return Int.min }
if number == Int.min { return Int.max }
else { return -number }
}
func negateMaximum(_ a: Int, _ b:Int) -> Int {
if a > b {
func miniMaxCore(position: Board, players: [Player], whoseTurn: Player, depth: Int) -> Int {
var bestValue = Int.min
let moves = position.generateMoves(player: whoseTurn)
for move in moves {
let clone = position.clone()
let _ = clone.makeMove(move: move, depth: depth)
if position.thereIsAWinner() != nil || (depth == 0) {
move.score = position.evaluate(evaluationFlags: appState.evaluationFlags, board: clone, whoseTurn: whoseTurn, nextPlayer: nextPlayer(player: whoseTurn))
}
else {
public func evaluate(evaluationFlags: EvaluationFlags, board: Board, whoseTurn: Player, nextPlayer: Player) -> Int {
var score = 0
for rank in 0..<board.squaresHigh {
for file in 0..<board.squaresWide {
if let man = board.squares[file][rank].man {
if man.player == whoseTurn {
if evaluationFlags.material {
score += man.value
}
if evaluationFlags.mobility {
func getBestMove(players: [Player], whoseTurn: Player, position: Board) async -> Move? {
var best: Move?
switch appState.game.aiType {
case .random:
best = getRandomMove(moves: position.generateMoves(player: whoseTurn))
case .kamikaze:
best = miniMax(position: position, players: players, whoseTurn: players[1], depth: 0)
case .minimax:
best = miniMax(position: position, players: players, whoseTurn: players[1], depth: appState.searchDepth)
case .pruner:
public func generateMoves(player: Player) -> [Move]
{
var moves = [Move]()
for rank in 0..<squaresHigh {
for file in 0..<squaresWide {
if let man = squares[file][rank].man {
if man.player == player {
moves += (man.generateMoves(board: self, x: file, y: rank))
}
}
import SwiftUI
struct GhostModifier: ViewModifier {
let hasGhost: Bool
let isInAWall: Bool
func body(content: Content) -> some View {
if hasGhost {
if isInAWall {
content
func blockedByWall(man: Man, targetSquare: Square) -> Bool {
return targetSquare.squareType == .wall && !man.tools.contains(.ghost)
}
squareView(file: file, rank: rank, color: viewModel.getBackgroundColor(file: file, rank: rank))
.artifactModifier(tool: viewModel.showTool(file: file, rank: rank), squareSize: viewModel.squareSize)
.handoffableModifier(isHighlighted: viewModel.handOffable[file][rank])
import SwiftUI
struct HandoffableModifier: ViewModifier {
let isHighlighted: Bool
func body(content: Content) -> some View {
if isHighlighted {
ZStack {
GeometryReader { geometry in
content