omnichess/lib/data_structures/position_tree_node.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;
}
}