From c66e25bb9bd8b952373599c7ab6a5c4d53504c26 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:02:50 +0000 Subject: [PATCH 1/4] Initial plan From 1572d88d67fdd84d4952ba58a97cd2d9c61d128c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:08:58 +0000 Subject: [PATCH 2/4] Add add_grid_edges helper and refactor 3 puzzle files Co-authored-by: semiexp <7336994+semiexp@users.noreply.github.com> --- cspuz_solver_backend/src/board.rs | 50 +++++++++++++++++++ cspuz_solver_backend/src/puzzle/crosswall.rs | 25 +--------- .../src/puzzle/litherslink.rs | 25 +--------- .../src/puzzle/slitherlink.rs | 25 +--------- 4 files changed, 53 insertions(+), 72 deletions(-) diff --git a/cspuz_solver_backend/src/board.rs b/cspuz_solver_backend/src/board.rs index 88ecd132..cf11b7dd 100644 --- a/cspuz_solver_backend/src/board.rs +++ b/cspuz_solver_backend/src/board.rs @@ -421,6 +421,56 @@ impl Board { } } + /// Renders grid edges (for puzzles like Slitherlink, Litherslink, Crosswall). + /// + /// This helper function adds edge items to the board based on a GridEdges structure. + /// - Vertical edges are rendered at positions (y * 2 + 1, x * 2) + /// - Horizontal edges are rendered at positions (y * 2, x * 2 + 1) + /// + /// # Arguments + /// * `edges` - The grid edges to render (with .vertical and .horizontal fields) + /// * `color` - Color to use for the rendered edges + /// * `true_kind` - ItemKind to use when edge value is true + /// * `false_kind` - ItemKind to use when edge value is false + pub fn add_grid_edges( + &mut self, + edges: &graph::GridEdges>>>, + color: &'static str, + true_kind: ItemKind, + false_kind: ItemKind, + ) { + let height = self.height; + let width = self.width; + + // Render vertical edges + for y in 0..height { + for x in 0..=width { + if let Some(b) = edges.vertical[y][x] { + self.push(Item { + y: y * 2 + 1, + x: x * 2, + color, + kind: if b { true_kind.clone() } else { false_kind.clone() }, + }); + } + } + } + + // Render horizontal edges + for y in 0..=height { + for x in 0..width { + if let Some(b) = edges.horizontal[y][x] { + self.push(Item { + y: y * 2, + x: x * 2 + 1, + color, + kind: if b { true_kind.clone() } else { false_kind.clone() }, + }); + } + } + } + } + pub fn to_json(&self) -> String { let kind = "grid"; let height = self.height; diff --git a/cspuz_solver_backend/src/puzzle/crosswall.rs b/cspuz_solver_backend/src/puzzle/crosswall.rs index a194f044..92083710 100644 --- a/cspuz_solver_backend/src/puzzle/crosswall.rs +++ b/cspuz_solver_backend/src/puzzle/crosswall.rs @@ -29,30 +29,7 @@ pub fn solve(url: &str) -> Result { } if let Some(is_line) = ans { - for y in 0..height { - for x in 0..=width { - if let Some(b) = is_line.vertical[y][x] { - board.push(Item { - y: y * 2 + 1, - x: x * 2, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } - for y in 0..=height { - for x in 0..width { - if let Some(b) = is_line.horizontal[y][x] { - board.push(Item { - y: y * 2, - x: x * 2 + 1, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } + board.add_grid_edges(&is_line, "green", ItemKind::Wall, ItemKind::Cross); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/litherslink.rs b/cspuz_solver_backend/src/puzzle/litherslink.rs index 808d8c5f..24ea4bba 100644 --- a/cspuz_solver_backend/src/puzzle/litherslink.rs +++ b/cspuz_solver_backend/src/puzzle/litherslink.rs @@ -23,30 +23,7 @@ pub fn solve(url: &str) -> Result { } } if let Some(is_line) = &ans { - for y in 0..height { - for x in 0..=width { - if let Some(b) = is_line.vertical[y][x] { - board.push(Item { - y: y * 2 + 1, - x: x * 2, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } - for y in 0..=height { - for x in 0..width { - if let Some(b) = is_line.horizontal[y][x] { - board.push(Item { - y: y * 2, - x: x * 2 + 1, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } + board.add_grid_edges(is_line, "green", ItemKind::Wall, ItemKind::Cross); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/slitherlink.rs b/cspuz_solver_backend/src/puzzle/slitherlink.rs index 9c9bb314..0afd283f 100644 --- a/cspuz_solver_backend/src/puzzle/slitherlink.rs +++ b/cspuz_solver_backend/src/puzzle/slitherlink.rs @@ -29,30 +29,7 @@ pub fn solve(url: &str) -> Result { } } if let Some(is_line) = &is_line { - for y in 0..height { - for x in 0..=width { - if let Some(b) = is_line.vertical[y][x] { - board.push(Item { - y: y * 2 + 1, - x: x * 2, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } - for y in 0..=height { - for x in 0..width { - if let Some(b) = is_line.horizontal[y][x] { - board.push(Item { - y: y * 2, - x: x * 2 + 1, - color: "green", - kind: if b { ItemKind::Wall } else { ItemKind::Cross }, - }) - } - } - } + board.add_grid_edges(is_line, "green", ItemKind::Wall, ItemKind::Cross); } Ok(board) From 8d5634767c2c0c6194ee1a4af4bc5289eab827ec Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:15:57 +0000 Subject: [PATCH 3/4] Add add_block_dot_answer helper and refactor 12 puzzle files Co-authored-by: semiexp <7336994+semiexp@users.noreply.github.com> --- cspuz_solver_backend/src/board.rs | 30 +++++++++++++++++++ cspuz_solver_backend/src/puzzle/akichiwake.rs | 15 ++-------- cspuz_solver_backend/src/puzzle/aqre.rs | 15 ++-------- cspuz_solver_backend/src/puzzle/chocona.rs | 13 +------- cspuz_solver_backend/src/puzzle/cocktail.rs | 13 +------- .../src/puzzle/double_lits.rs | 13 +------- .../src/puzzle/heyawake_internal.rs | 15 ++-------- .../src/puzzle/inverse_litso.rs | 13 +------- cspuz_solver_backend/src/puzzle/lits.rs | 13 +------- cspuz_solver_backend/src/puzzle/norinori.rs | 13 +------- cspuz_solver_backend/src/puzzle/nuritwin.rs | 13 +------- cspuz_solver_backend/src/puzzle/shimaguni.rs | 13 +------- cspuz_solver_backend/src/puzzle/stostone.rs | 13 +------- .../src/puzzle/yajilin_regions.rs | 13 +------- 14 files changed, 46 insertions(+), 159 deletions(-) diff --git a/cspuz_solver_backend/src/board.rs b/cspuz_solver_backend/src/board.rs index cf11b7dd..43f87a01 100644 --- a/cspuz_solver_backend/src/board.rs +++ b/cspuz_solver_backend/src/board.rs @@ -471,6 +471,36 @@ impl Board { } } + /// Renders Block/Dot items based on boolean answer grid (for region-based puzzles). + /// + /// This helper function adds Block or Dot items to the board for cells that have + /// determined values in the answer grid. + /// + /// # Arguments + /// * `is_black` - Answer grid with Option values + /// * `color` - Color to use for the rendered items + pub fn add_block_dot_answer( + &mut self, + is_black: &Vec>>, + color: &'static str, + ) { + let height = self.height; + let width = self.width; + + for y in 0..height { + for x in 0..width { + if let Some(b) = is_black[y][x] { + self.push(Item::cell( + y, + x, + color, + if b { ItemKind::Block } else { ItemKind::Dot }, + )); + } + } + } + } + pub fn to_json(&self) -> String { let kind = "grid"; let height = self.height; diff --git a/cspuz_solver_backend/src/puzzle/akichiwake.rs b/cspuz_solver_backend/src/puzzle/akichiwake.rs index c99a9ed5..4fab903a 100644 --- a/cspuz_solver_backend/src/puzzle/akichiwake.rs +++ b/cspuz_solver_backend/src/puzzle/akichiwake.rs @@ -25,19 +25,8 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); - for y in 0..height { - for x in 0..width { - if let Some(is_black) = &is_black { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + if let Some(is_black) = &is_black { + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/aqre.rs b/cspuz_solver_backend/src/puzzle/aqre.rs index 8423d089..eee48806 100644 --- a/cspuz_solver_backend/src/puzzle/aqre.rs +++ b/cspuz_solver_backend/src/puzzle/aqre.rs @@ -25,19 +25,8 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); - for y in 0..height { - for x in 0..width { - if let Some(is_black) = &is_black { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + if let Some(is_black) = &is_black { + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/chocona.rs b/cspuz_solver_backend/src/puzzle/chocona.rs index 448895cc..d42f0162 100644 --- a/cspuz_solver_backend/src/puzzle/chocona.rs +++ b/cspuz_solver_backend/src/puzzle/chocona.rs @@ -25,18 +25,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &is_black { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/cocktail.rs b/cspuz_solver_backend/src/puzzle/cocktail.rs index d1feb380..d0c01bf9 100644 --- a/cspuz_solver_backend/src/puzzle/cocktail.rs +++ b/cspuz_solver_backend/src/puzzle/cocktail.rs @@ -22,18 +22,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = is_black { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(&is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); diff --git a/cspuz_solver_backend/src/puzzle/double_lits.rs b/cspuz_solver_backend/src/puzzle/double_lits.rs index c500f327..15286097 100644 --- a/cspuz_solver_backend/src/puzzle/double_lits.rs +++ b/cspuz_solver_backend/src/puzzle/double_lits.rs @@ -22,18 +22,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = ans { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(&is_black, "green"); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/heyawake_internal.rs b/cspuz_solver_backend/src/puzzle/heyawake_internal.rs index caadeb25..a695b6d6 100644 --- a/cspuz_solver_backend/src/puzzle/heyawake_internal.rs +++ b/cspuz_solver_backend/src/puzzle/heyawake_internal.rs @@ -41,19 +41,8 @@ pub fn solve(url: &str, is_ayeheya: bool) -> Result { board.add_borders(&borders, "black"); - for y in 0..height { - for x in 0..width { - if let Some(is_black) = &is_black { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + if let Some(is_black) = &is_black { + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/inverse_litso.rs b/cspuz_solver_backend/src/puzzle/inverse_litso.rs index 94d15837..121f961e 100644 --- a/cspuz_solver_backend/src/puzzle/inverse_litso.rs +++ b/cspuz_solver_backend/src/puzzle/inverse_litso.rs @@ -24,18 +24,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &is_black { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/lits.rs b/cspuz_solver_backend/src/puzzle/lits.rs index 5f1405e2..15d7266e 100644 --- a/cspuz_solver_backend/src/puzzle/lits.rs +++ b/cspuz_solver_backend/src/puzzle/lits.rs @@ -22,18 +22,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &ans { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/norinori.rs b/cspuz_solver_backend/src/puzzle/norinori.rs index d6ac4258..0b53910a 100644 --- a/cspuz_solver_backend/src/puzzle/norinori.rs +++ b/cspuz_solver_backend/src/puzzle/norinori.rs @@ -18,18 +18,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &ans { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/nuritwin.rs b/cspuz_solver_backend/src/puzzle/nuritwin.rs index 234a6283..be235edf 100644 --- a/cspuz_solver_backend/src/puzzle/nuritwin.rs +++ b/cspuz_solver_backend/src/puzzle/nuritwin.rs @@ -18,18 +18,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &ans { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/shimaguni.rs b/cspuz_solver_backend/src/puzzle/shimaguni.rs index eb438555..1df1a3a7 100644 --- a/cspuz_solver_backend/src/puzzle/shimaguni.rs +++ b/cspuz_solver_backend/src/puzzle/shimaguni.rs @@ -21,18 +21,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &is_black { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/stostone.rs b/cspuz_solver_backend/src/puzzle/stostone.rs index 6c4eb4d2..0a8d7b8f 100644 --- a/cspuz_solver_backend/src/puzzle/stostone.rs +++ b/cspuz_solver_backend/src/puzzle/stostone.rs @@ -21,18 +21,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some(is_black) = &is_black { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); assert_eq!(rooms.len(), clues.len()); diff --git a/cspuz_solver_backend/src/puzzle/yajilin_regions.rs b/cspuz_solver_backend/src/puzzle/yajilin_regions.rs index dedd32f9..15ba1242 100644 --- a/cspuz_solver_backend/src/puzzle/yajilin_regions.rs +++ b/cspuz_solver_backend/src/puzzle/yajilin_regions.rs @@ -37,18 +37,7 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); if let Some((ref is_line, ref is_black)) = ans { - for y in 0..height { - for x in 0..width { - if let Some(b) = is_black[y][x] { - board.push(Item::cell( - y, - x, - "green", - if b { ItemKind::Block } else { ItemKind::Dot }, - )); - } - } - } + board.add_block_dot_answer(is_black, "green"); let mut skip_line = vec![]; for y in 0..height { From b9d6ad0b782dc268af5d26abf4d198f427cf5f21 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:18:12 +0000 Subject: [PATCH 4/4] Fix parameter passing consistency Co-authored-by: semiexp <7336994+semiexp@users.noreply.github.com> --- cspuz_solver_backend/src/puzzle/cocktail.rs | 4 ++-- cspuz_solver_backend/src/puzzle/crosswall.rs | 4 ++-- cspuz_solver_backend/src/puzzle/double_lits.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cspuz_solver_backend/src/puzzle/cocktail.rs b/cspuz_solver_backend/src/puzzle/cocktail.rs index d0c01bf9..7fc82830 100644 --- a/cspuz_solver_backend/src/puzzle/cocktail.rs +++ b/cspuz_solver_backend/src/puzzle/cocktail.rs @@ -21,8 +21,8 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); - if let Some(is_black) = is_black { - board.add_block_dot_answer(&is_black, "green"); + if let Some(is_black) = &is_black { + board.add_block_dot_answer(is_black, "green"); } let rooms = graph::borders_to_rooms(&borders); diff --git a/cspuz_solver_backend/src/puzzle/crosswall.rs b/cspuz_solver_backend/src/puzzle/crosswall.rs index 92083710..a4e60e97 100644 --- a/cspuz_solver_backend/src/puzzle/crosswall.rs +++ b/cspuz_solver_backend/src/puzzle/crosswall.rs @@ -28,8 +28,8 @@ pub fn solve(url: &str) -> Result { } } - if let Some(is_line) = ans { - board.add_grid_edges(&is_line, "green", ItemKind::Wall, ItemKind::Cross); + if let Some(is_line) = &ans { + board.add_grid_edges(is_line, "green", ItemKind::Wall, ItemKind::Cross); } Ok(board) diff --git a/cspuz_solver_backend/src/puzzle/double_lits.rs b/cspuz_solver_backend/src/puzzle/double_lits.rs index 15286097..4800da6e 100644 --- a/cspuz_solver_backend/src/puzzle/double_lits.rs +++ b/cspuz_solver_backend/src/puzzle/double_lits.rs @@ -21,8 +21,8 @@ pub fn solve(url: &str) -> Result { board.add_borders(&borders, "black"); - if let Some(is_black) = ans { - board.add_block_dot_answer(&is_black, "green"); + if let Some(is_black) = &ans { + board.add_block_dot_answer(is_black, "green"); } Ok(board)