“Those who are crazy enough to think they can change the world are the ones who do.” — Steve Jobs 💡
Author: Jery Rodríguez Fernández — Group: C312 👤
This repository implements an autonomous HEX player that combines classical adversarial search (Minimax with alpha–beta pruning) for small/medium boards and Monte Carlo Tree Search (MCTS) for larger boards. It also includes an automated parameter search module based on a Genetic Algorithm (GA) to optimize the evaluation heuristic. The design focuses on modularity, performance, and reproducible experiments. ⚙️📈🤖
-
solution.py— Experiment orchestrator and entrypoint. Responsibilities:- Read and expose configuration (board sizes, RNG seed, heuristic weight vectors, runtime options). ⚙️
- Instantiate game engine and strategy implementations (
MinimaxorMCTS) according to board size and game phase. 🧩 - Run matches and tournaments, log results, persist statistics and learned weight vectors. 📊
- Load and apply weight combinations produced by
genetic_algorithm.pyfor automated evaluation. 🔁
-
strategy.pdy— Strategy and heuristic implementations used by Minimax and by MCTS rollouts. Key technical components:- Minimax with alpha–beta pruning and adaptive depth control (depth depends on board size and proximity to terminal nodes). ♟️✂️
- Multi-signal heuristic combining: territorial control, minimum connection distance (BFS), connected-component metrics (count and largest component size), threatened-cell analysis, and prioritized move ordering. 🔎🧠
- Move generator optimized for pruning: adjacent-to-stone moves first, then other candidates; intra-group ordering by Manhattan distance to strategic anchors (center/edges), dynamically adapted by game phase. 📐➡️
- Heuristic parameters: 6-dimensional weight vector
(p1..p6)that linearly combines normalized signals;p6is used as a phase threshold to switch spatial focus (center → edges). Implementations reuse intermediate graph representations (DSU, cached components) to speed evaluations and reduce redundant work. 🧩💾
-
genetic_algorithm.py— Automated search of effective heuristic weight vectors using a Genetic Algorithm (GA). Operational details:- Representation: each individual is a 6D real-valued vector
(p1,...,p6)encoding heuristic coefficients and the phase threshold. 🧬 - Fitness: each individual plays
mmatches against a reference opponent (or opponent pool); fitness = win percentage (higher is better). 🏁 - Evolutionary operators: selection (top-k or tournament), crossover with probability
p_c, mutation with probabilityp_m. Hyperparameters: populationn, matches per individualm, selection sizek, crossoverp_c, mutationp_m, generationsw. 🔁⚙️ - Outputs: persisted best vectors per generation; example strong solution found:
(p1..p6) = (16.92, 2.81, 5.15, 16.76, 1, 43.41). 🏆 - Practical opening strategy: optionally sample randomly from a pre-seeded set of vectors to diversify early-game behavior. 🎲
- Representation: each individual is a 6D real-valued vector
The evaluation is a linear combination of normalized feature signals. In compact form:
An additional scalar parameter
- Minimax: alpha–beta pruning, iterative deepening (where applicable), transposition/caching table support, and heuristic move ordering to reduce branching factor. Time and memory trade-offs are configurable per board size. ⏱️💾
- MCTS: UCT-based selection with domain-specific rollout policy. Rollouts are biased towards adjacency to existing stones to produce higher-quality playouts for Hex. Tree and rollout layers use fast DSU/graph checks to detect wins early. 🌲🔍
- DSU (Disjoint Set Union) is heavily used for quick connection/win detection during both search and rollouts — amortized near-constant checks speed up simulations considerably. 🔗
- Representation: float vector of length 6; use bounded ranges and normalization for numerical stability. 🔢
- Fitness evaluation: use parallelized match workers when evaluating many individuals to scale with CPU cores. 🧵⚡
- Operators: prefer simulated binary crossover (SBX) or uniform crossover for continuous genes; Gaussian or adaptive mutations for exploration. 🔁
- Hyperparameter tuning: balance
n,m, andwdepending on compute budget — largermyields better fitness estimates but increases compute cost linearly. 📐
- Cache feature computations (component counts, BFS distances) and invalidate incrementally on local moves. 🗃️
- Use prioritized move generators and shallow heuristic evaluations during alpha–beta to prune aggressively. ✂️
- Parallelize GA evaluations and, where safe, MCTS rollouts. Use modest locking or per-thread RNG streams to ensure reproducible results. 🔀
Run a simple match or experiment via solution.py. Example:
python solution.py --board-size 11 --strategy mcts --seed 42For GA experiments:
python genetic_algorithm.py --population 50 --matches 20 --generations 100 --crossover 0.8 --mutation 0.02