91 lines
3.0 KiB
Dart
91 lines
3.0 KiB
Dart
import 'package:omnichess/classes/best_move_searcher.dart';
|
|
import 'package:omnichess/classes/position.dart';
|
|
import 'package:omnichess/constants/numbers.dart';
|
|
import 'package:omnichess/data_structures/search_heap.dart';
|
|
import 'package:omnichess/functions/legal_moves.dart';
|
|
|
|
class PositionTreeNode {
|
|
|
|
int priority;
|
|
int value;
|
|
int nodeCount;
|
|
int depth;
|
|
final String move;
|
|
final Position position;
|
|
final Iterable<(String, Position)> legalMoves;
|
|
SearchHeap<String, PositionTreeNode> children;
|
|
SearchHeap<String, PositionTreeNode> childrenByValue;
|
|
|
|
String get bestLine {
|
|
final String? childBestLine = childrenByValue.firstOrNull?.bestLine;
|
|
return "$move${null == childBestLine ? "" : " $childBestLine"}";
|
|
}
|
|
|
|
PositionTreeNode({
|
|
required this.priority,
|
|
required this.value,
|
|
required this.move,
|
|
required this.position,
|
|
required this.legalMoves,
|
|
required this.children,
|
|
required this.childrenByValue,
|
|
}):
|
|
nodeCount = 0,
|
|
depth = 0;
|
|
|
|
factory PositionTreeNode.fromPosition(Position position, [ String move = "" ]) {
|
|
final int value = BestMoveSearcher.getPositionBaseValue(position);
|
|
final Iterable<(String, Position)> legalMoves = LegalMoves.getLegalMoves(position);
|
|
return PositionTreeNode(
|
|
priority: BestMoveSearcher.getPositionBasePriority(position, value, legalMoves, 0),
|
|
value: value,
|
|
move: move,
|
|
position: position,
|
|
legalMoves: legalMoves,
|
|
children: SearchHeap<String, PositionTreeNode>(
|
|
getKey: (PositionTreeNode node) => node.move,
|
|
getPriority: (PositionTreeNode node) => node.priority,
|
|
),
|
|
childrenByValue: SearchHeap<String, PositionTreeNode>(
|
|
getKey: (PositionTreeNode node) => node.move,
|
|
getPriority: position.isWhiteTurn
|
|
? (PositionTreeNode node) => -node.value
|
|
: (PositionTreeNode node) => node.value,
|
|
),
|
|
);
|
|
}
|
|
|
|
void computeStep() {
|
|
if (legalMoves.isEmpty) {
|
|
return;
|
|
}
|
|
if (children.isEmpty) {
|
|
_computeChildren();
|
|
return;
|
|
}
|
|
final PositionTreeNode firstChild = children.first;
|
|
final int initialFirstChildNodeCount = firstChild.nodeCount;
|
|
firstChild.computeStep();
|
|
children.updateElement(firstChild.move);
|
|
childrenByValue.updateElement(firstChild.move);
|
|
nodeCount += firstChild.nodeCount - initialFirstChildNodeCount;
|
|
if (firstChild.depth + 1 > depth) {
|
|
depth = firstChild.depth + 1;
|
|
}
|
|
priority = (children.first.priority == Numbers.maxInteger) ? children.first.priority : children.first.priority + 1;
|
|
value = childrenByValue.first.value;
|
|
}
|
|
|
|
void _computeChildren() {
|
|
for (final (String, Position) move in legalMoves) {
|
|
final PositionTreeNode positionTreeNode = PositionTreeNode.fromPosition(move.$2, move.$1);
|
|
children.add(positionTreeNode);
|
|
childrenByValue.add(positionTreeNode);
|
|
}
|
|
nodeCount = legalMoves.length;
|
|
priority = (children.first.priority == Numbers.maxInteger) ? children.first.priority : children.first.priority + 1;
|
|
depth = 1;
|
|
value = childrenByValue.first.value;
|
|
}
|
|
|
|
} |