Skip to content

Instantly share code, notes, and snippets.

@rocallahan
Created January 28, 2022 20:25
Show Gist options
  • Save rocallahan/faa92557a875e8825f240524a94024b0 to your computer and use it in GitHub Desktop.
Save rocallahan/faa92557a875e8825f240524a94024b0 to your computer and use it in GitHub Desktop.
type BoardBits = u64;
const BOARD_SIZE: i64 = 8;
const ROW_SIZE: i64 = 4;
const ROW_COUNT: i64 = 5;
const ORCHARD_COUNT: i64 = 10;
const TYPE_COUNT: usize = 4;
fn row_bits(row_positions: i64) -> Vec<i64> {
let mut ret = Vec::new();
for i in 0..(1i64 << row_positions) {
if i.count_ones() as i64 == ROW_SIZE {
ret.push(i);
}
}
ret
}
fn plot(x: i64, y: i64) -> BoardBits {
1 << (x + y*BOARD_SIZE) as BoardBits
}
fn make_line_configurations_vector(start_x: i64, start_y: i64, dx: i64, dy: i64, visited_starts: &mut BoardBits, out: &mut Vec<Vec<BoardBits>>) {
if *visited_starts & plot(start_x, start_y) != 0 {
return;
}
*visited_starts |= plot(start_x, start_y);
let mut ret = Vec::new();
let mut step_count = 0;
while start_x + dx*(step_count + 1) < BOARD_SIZE && start_y + dy*(step_count + 1) < BOARD_SIZE &&
start_x + dx*(step_count + 1) >= 0 && start_y + dy*(step_count + 1) >= 0 {
step_count += 1;
*visited_starts |= plot(start_x + dx*step_count, start_y + dy*step_count);
}
if step_count >= ROW_SIZE - 1 {
let all_row_bits = row_bits(step_count + 1);
for bits in all_row_bits {
let mut v = 0;
for i in 0..=step_count {
if bits & (1 << i) != 0 {
v |= plot(start_x + dx*i, start_y + dy*i);
}
}
ret.push(v);
}
}
if !ret.is_empty() {
out.push(ret);
}
}
fn make_line_configurations() -> Vec<Vec<BoardBits>> {
let mut ret = Vec::new();
let mut visited_starts = [0; 8];
for start_y in 0..BOARD_SIZE {
for start_x in 0..BOARD_SIZE {
make_line_configurations_vector(start_x, start_y, 0, 1, &mut visited_starts[0], &mut ret);
make_line_configurations_vector(start_x, start_y, 1, 0, &mut visited_starts[1], &mut ret);
make_line_configurations_vector(start_x, start_y, 1, 1, &mut visited_starts[2], &mut ret);
make_line_configurations_vector(start_x, start_y, 1, 2, &mut visited_starts[3], &mut ret);
make_line_configurations_vector(start_x, start_y, 2, 1, &mut visited_starts[4], &mut ret);
}
for start_x in (0..BOARD_SIZE).rev() {
make_line_configurations_vector(start_x, start_y, -1, 1, &mut visited_starts[5], &mut ret);
make_line_configurations_vector(start_x, start_y, -1, 2, &mut visited_starts[6], &mut ret);
make_line_configurations_vector(start_x, start_y, -2, 1, &mut visited_starts[7], &mut ret);
}
}
ret
}
fn make_same_tree_boards(board: BoardBits, current_rows: i64, line_configurations: &[Vec<BoardBits>], ret: &mut Vec<BoardBits>) {
for i in 0..line_configurations.len() {
for line_configuration in line_configurations[i].iter() {
let new_board = board | *line_configuration;
if new_board.count_ones() > ORCHARD_COUNT as u32 {
continue;
}
if current_rows + 1 < ROW_COUNT {
make_same_tree_boards(new_board, current_rows + 1, &line_configurations[(i + 1)..], ret);
} else {
if new_board.count_ones() < ORCHARD_COUNT as u32 {
panic!("Did it with fewer trees!");
}
ret.push(new_board);
}
}
}
}
fn house() -> BoardBits {
plot(3, 0) | plot(4, 0) | plot(3, 1) | plot(4, 1)
}
fn print_board(bits: BoardBits) -> String {
let mut ret = String::new();
for y in 0..BOARD_SIZE {
for x in 0..BOARD_SIZE {
ret.push(if bits & plot(x, y) != 0 { '0' } else { '.' });
}
ret.push('\n');
}
ret
}
fn make_solution_boards(occupied: BoardBits, first_board_index: usize, orchard_boards: &[BoardBits], solution: &mut Vec<usize>, solution_boards: &mut Vec<Vec<usize>>) {
for i in first_board_index..orchard_boards.len() {
if occupied & orchard_boards[i] != 0 {
continue;
}
solution.push(i);
if solution.len() == TYPE_COUNT {
solution_boards.push(solution.clone());
} else {
let new_occupied = occupied | orchard_boards[i];
make_solution_boards(new_occupied, first_board_index + 1, orchard_boards, solution, solution_boards);
}
solution.pop();
}
}
fn print_solution(solution: Vec<usize>, orchard_boards: &[BoardBits]) -> String {
let mut chars = ['X'; 64];
let labels = ['A', 'B', 'C', 'D'];
for i in 0..TYPE_COUNT {
let b = orchard_boards[solution[i]];
for j in 0..64 {
if b & (1 << j) != 0 {
chars[j] = labels[i];
}
}
}
let mut ret = String::new();
ret.push_str("<div style='white-space:pre'>");
for y in 0..BOARD_SIZE {
for x in 0..BOARD_SIZE {
ret.push_str("<div class='");
ret.push(chars[(y*BOARD_SIZE + x) as usize]);
ret.push_str("'></div>");
}
ret.push('\n');
}
ret.push_str("</div>");
ret
}
fn main() {
let mut line_configurations = make_line_configurations();
// println!("Total line configurations: {}", line_configurations.iter().map(|v| v.len()).sum::<usize>());
let h = house();
for cfg in line_configurations.iter_mut() {
cfg.retain(|v| (v & h) == 0);
}
line_configurations.retain(|v| !v.is_empty());
// println!("House-checked line configurations: {}", line_configurations.iter().map(|v| v.len()).sum::<usize>());
let mut orchard_boards = Vec::new();
make_same_tree_boards(0, 0, &line_configurations, &mut orchard_boards);
/* println!("Found {} boards", orchard_boards.len());
for b in orchard_boards {
println!("{}", print_board(b));
}*/
let mut solutions = Vec::new();
make_solution_boards(0, 0, &orchard_boards, &mut Vec::new(), &mut solutions);
println!("Found {} solutions", solutions.len());
for s in solutions {
println!("{}", print_solution(s, &orchard_boards));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment