import 'dart:collection'; import 'package:omnichess/classes/position.dart'; import 'package:omnichess/constants/piece.dart'; import 'package:omnichess/functions/legal_moves.dart'; class BestMoveSearcher { bool _isRunning = false; bool _isStopped = false; Future getPositionBaseValue(Position position) async { if (await LegalMoves.isCheckmate(position)) { return position.isWhiteTurn ? -(1 << 63) // min int (white is checkmated) : ((1 << 63) - 1); // max int (black is checkmated) } int value = 0; for (int i = 0; i < 64; i++) { value += switch (position.board[i]) { Piece.whiteQueen => 900, Piece.whiteRook => 500, Piece.whiteBishop => 300, Piece.whiteKnight => 300, Piece.whitePawn => 100, Piece.blackQueen => -900, Piece.blackRook => -500, Piece.blackBishop => -300, Piece.blackKnight => -300, Piece.blackPawn => -100, _ => 0, }; } return value; } Future search(Position position) async { _isRunning = true; (int, String, Position)? bestMove; Queue<(int, String, Position)> evaluatedMoves = Queue(); await for (final (String, Position) move in LegalMoves.getLegalMoves(position)) { final (int, String, Position) evaluatedMove = (await getPositionBaseValue(move.$2), move.$1, move.$2); if ( null == bestMove || (bestMove.$1 < evaluatedMove.$1 && position.isWhiteTurn) || (bestMove.$1 > evaluatedMove.$1 && !position.isWhiteTurn) ) { bestMove = evaluatedMove; } evaluatedMoves.add(evaluatedMove); await Future.delayed(Duration.zero); if (_isStopped) { break; } // TODO evaluate checkmate } if (evaluatedMoves.isEmpty) { _isRunning = false; _isStopped = false; return null; } // TODO search // IDEA implement a BFS with pruning on the ones that give suboptimal values _isRunning = false; _isStopped = false; return bestMove?.$2; } Future stop() async { if (!_isRunning) { return; } _isStopped = true; } }