···1515[dependencies]
1616gleam_stdlib = ">= 0.44.0 and < 2.0.0"
1717iv = ">= 1.3.2 and < 2.0.0"
1818+birl = ">= 1.8.0 and < 2.0.0"
18191920[dev-dependencies]
2021gleeunit = ">= 1.0.0 and < 2.0.0"
+1
manifest.toml
···1717]
18181919[requirements]
2020+birl = { version = ">= 1.8.0 and < 2.0.0" }
2021gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
2122gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
2223iv = { version = ">= 1.3.2 and < 2.0.0" }
+25-2
src/starfish.gleam
···11+import birl
12import gleam/bool
23import gleam/result
34import starfish/internal/board
···118119 move.legal(game)
119120}
120121121121-pub fn search(game: Game, to_depth depth: Int) -> Result(Move, Nil) {
122122- search.best_move(game, depth)
122122+/// Used to determine how long to search positions
123123+pub type SearchCutoff {
124124+ /// Search to a specific depth
125125+ Depth(depth: Int)
126126+ /// Search for a given number of milliseconds.
127127+ ///
128128+ /// NOTE: The process will usually take slightly longer than the specified time.
129129+ /// It would be expensive to check the time every millisecond, so it is checked
130130+ /// periodically. This is usually less than 10ms, but it can be higher than that.
131131+ Time(milliseconds: Int)
132132+}
133133+134134+/// Finds the best move for a given position, or returns an error if no moves are
135135+/// legal (If it's checkmate or stalemate)
136136+pub fn search(game: Game, until cutoff: SearchCutoff) -> Result(Move, Nil) {
137137+ let until = case cutoff {
138138+ Depth(depth:) -> fn(current_depth) { current_depth > depth }
139139+ Time(milliseconds:) -> {
140140+ let end_time = birl.monotonic_now() + milliseconds * 1000
141141+ fn(_) { birl.monotonic_now() >= end_time }
142142+ }
143143+ }
144144+145145+ search.best_move(game, until)
123146}
124147125148pub fn apply_move(game: Game, move: Move) -> Game {