From 96fb485c872375713d2ac4b7d3983f590f26395a Mon Sep 17 00:00:00 2001 From: Mitchell M Date: Mon, 22 Dec 2025 11:32:20 -0600 Subject: [PATCH] engine work --- tak_lib/src/engine.rs | 234 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 4 deletions(-) diff --git a/tak_lib/src/engine.rs b/tak_lib/src/engine.rs index afb0f7a..eea4b0a 100644 --- a/tak_lib/src/engine.rs +++ b/tak_lib/src/engine.rs @@ -1,5 +1,5 @@ use crate::{ - Board, Direction, Move, + Board, Move, piece::{ColoredPiece, Piece}, }; @@ -28,7 +28,7 @@ impl Board { let top_piece = tiles[x as usize][y as usize].top_piece(); if top_piece == ColoredPiece::None { // possible moves are place moves - get_placement_moves(x, y, can_place_caps) + insert_placement_moves(x, y, can_place_caps) } else if top_piece.color() == to_move { get_movement_moves(x, y, tiles[x as usize][y as usize].stack_len()) } else { @@ -38,7 +38,7 @@ impl Board { } } -fn get_placement_moves(x: u8, y: u8, can_place_caps: bool) -> Vec> { +fn insert_placement_moves(x: u8, y: u8, can_place_caps: bool) -> Vec> { let mut moves = Vec::with_capacity(2 + can_place_caps as usize); moves.push(Move::Place { piece: Piece::Flat, @@ -68,6 +68,232 @@ fn get_movement_moves(x: u8, y: u8, stack_len: u8) -> Vec(max_grab: u8, max_dist: u8) -> impl Iterator {} +fn get_drop_amounts( + // shared state + buf: &mut [u8; N], + i: usize, + insert_fn: &mut impl FnMut([u8; N]), + // recursive parameters + pieces: u8, + len: u8, + end_w_capstone: bool, +) { + debug_assert!(len > 0 || pieces == 0); + // base cases + if pieces == 0 { + insert_fn(buf.clone()); + return; + } + if pieces == 1 { + buf[i] = 1; + insert_fn(buf.clone()); + buf[i] = 0; + return; + } + if len == 1 { + buf[i] = pieces; + insert_fn(buf.clone()); + buf[i] = 0; + return; + } + + // recursive case + for n in 1..=pieces { + buf[i] = n; + get_drop_amounts(buf, i + 1, insert_fn, pieces - n, len - 1, end_w_capstone); + } + buf[i] = 0; +} + +#[cfg(test)] +fn expect_get_drop_ammounts( + pieces: u8, + len: u8, + end_w_capstone: bool, + expected_drop_list: Vec<[u8; N]>, +) { + use std::collections::HashSet; + + let mut buf = [0; N]; + let mut drop_list = Vec::new(); + let mut insert_fn = |drops: [u8; N]| { + drop_list.push(drops); + }; + get_drop_amounts(&mut buf, 0, &mut insert_fn, pieces, len, end_w_capstone); + + let expected_drop_set: HashSet<_> = expected_drop_list.iter().cloned().collect(); + let drop_set: HashSet<_> = drop_list.iter().cloned().collect(); + if drop_set.len() != drop_list.len() { + panic!("drop list had duplicate values"); + } + if expected_drop_set != drop_set { + let mut err_str = String::new(); + for entry in expected_drop_list { + if drop_set.contains(&entry) { + err_str += &format!("\t{:?} {:?}\n", entry, entry); + } else { + err_str += &format!("\t{:?}\n", entry); + } + } + for entry in drop_list { + if expected_drop_set.contains(&entry) { + continue; + } + let blank = format!("{:?}", entry) + .chars() + .map(|_| ' ') + .collect::(); + err_str += &format!("\t{} {:?}\n", blank, entry); + } + panic!("incorrect drop list!\n{}", err_str); + } +} + +#[test] +fn test_full_len_drop_amounts() { + expect_get_drop_ammounts(1, 1, false, vec![[1]]); + expect_get_drop_ammounts(1, 1, false, vec![[1, 0]]); + expect_get_drop_ammounts(1, 1, false, vec![[1, 0, 0]]); + expect_get_drop_ammounts(2, 2, false, vec![[1, 1, 0, 0, 0], [2, 0, 0, 0, 0]]); + expect_get_drop_ammounts( + 3, + 3, + false, + vec![ + [1, 1, 1, 0, 0], + [1, 2, 0, 0, 0], + [2, 1, 0, 0, 0], + [3, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 4, + 4, + false, + vec![ + [1, 1, 1, 1, 0], + [1, 1, 2, 0, 0], + [1, 2, 1, 0, 0], + [1, 3, 0, 0, 0], + [2, 1, 1, 0, 0], + [2, 2, 0, 0, 0], + [3, 1, 0, 0, 0], + [4, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 5, + 5, + false, + vec![ + [1, 1, 1, 1, 1], + [1, 1, 1, 2, 0], + [1, 1, 2, 1, 0], + [1, 1, 3, 0, 0], + [1, 2, 1, 1, 0], + [1, 2, 2, 0, 0], + [1, 3, 1, 0, 0], + [1, 4, 0, 0, 0], + [2, 1, 1, 1, 0], + [2, 1, 2, 0, 0], + [2, 2, 1, 0, 0], + [2, 3, 0, 0, 0], + [3, 1, 1, 0, 0], + [3, 2, 0, 0, 0], + [4, 1, 0, 0, 0], + [5, 0, 0, 0, 0], + ], + ); +} + +#[test] +fn test_truncated_drop_amounts() { + expect_get_drop_ammounts( + 3, + 2, + false, + vec![[1, 2, 0, 0, 0], [2, 1, 0, 0, 0], [3, 0, 0, 0, 0]], + ); + expect_get_drop_ammounts(3, 1, false, vec![[3, 0, 0, 0, 0]]); + expect_get_drop_ammounts( + 4, + 3, + false, + vec![ + [1, 1, 2, 0, 0], + [1, 2, 1, 0, 0], + [1, 3, 0, 0, 0], + [2, 1, 1, 0, 0], + [2, 2, 0, 0, 0], + [3, 1, 0, 0, 0], + [4, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 4, + 2, + false, + vec![ + [1, 3, 0, 0, 0], + [2, 2, 0, 0, 0], + [3, 1, 0, 0, 0], + [4, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 5, + 4, + false, + vec![ + [1, 1, 1, 2, 0], + [1, 1, 2, 1, 0], + [1, 1, 3, 0, 0], + [1, 2, 1, 1, 0], + [1, 2, 2, 0, 0], + [1, 3, 1, 0, 0], + [1, 4, 0, 0, 0], + [2, 1, 1, 1, 0], + [2, 1, 2, 0, 0], + [2, 2, 1, 0, 0], + [2, 3, 0, 0, 0], + [3, 1, 1, 0, 0], + [3, 2, 0, 0, 0], + [4, 1, 0, 0, 0], + [5, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 5, + 3, + false, + vec![ + [1, 1, 3, 0, 0], + [1, 2, 2, 0, 0], + [1, 3, 1, 0, 0], + [1, 4, 0, 0, 0], + [2, 1, 2, 0, 0], + [2, 2, 1, 0, 0], + [2, 3, 0, 0, 0], + [3, 1, 1, 0, 0], + [3, 2, 0, 0, 0], + [4, 1, 0, 0, 0], + [5, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts( + 5, + 2, + false, + vec![ + [1, 4, 0, 0, 0], + [2, 3, 0, 0, 0], + [3, 2, 0, 0, 0], + [4, 1, 0, 0, 0], + [5, 0, 0, 0, 0], + ], + ); + expect_get_drop_ammounts(5, 1, false, vec![[5, 0, 0, 0, 0]]); +}