Add comments after bind indexes, board indexes

This commit is contained in:
2026-01-24 01:23:29 -08:00
parent a05805b30c
commit 0419de7ec8
+71 -17
View File
@@ -45,6 +45,27 @@ macro_rules! kv_str {
}; };
} }
/// Get board title comment string for a board index.
fn board_title_comment(boards: &[Board], index: u8) -> String {
boards
.get(index as usize)
.map(|b| format!(" # {}", b.name))
.unwrap_or_default()
}
/// Get bind target comment string (first line if it starts with @).
fn bind_target_comment(stats: &[Stat], index: u16) -> String {
stats
.get(index as usize)
.and_then(|s| match &s.program {
Program::Own(code) if code.starts_with('@') => {
code.lines().next().map(|line| format!(" # {}", line))
}
_ => None,
})
.unwrap_or_default()
}
/// Convert a World to its text representation. /// Convert a World to its text representation.
pub fn world_to_text(world: &World) -> String { pub fn world_to_text(world: &World) -> String {
let mut output = String::new(); let mut output = String::new();
@@ -52,7 +73,7 @@ pub fn world_to_text(world: &World) -> String {
for (i, board) in world.boards.iter().enumerate() { for (i, board) in world.boards.iter().enumerate() {
output.push_str("\n\n"); output.push_str("\n\n");
write_board(&mut output, Some(i), board); write_board(&mut output, Some(i), board, Some(&world.boards));
} }
output output
@@ -61,7 +82,7 @@ pub fn world_to_text(world: &World) -> String {
/// Convert a standalone Board to its text representation. /// Convert a standalone Board to its text representation.
pub fn board_to_text(board: &Board) -> String { pub fn board_to_text(board: &Board) -> String {
let mut output = String::new(); let mut output = String::new();
write_board(&mut output, None, board); write_board(&mut output, None, board, None);
output output
} }
@@ -80,7 +101,10 @@ fn write_world_header(output: &mut String, world: &World) {
writeln!(output, "keys = [{}]", key_arr.join(", ")).unwrap(); writeln!(output, "keys = [{}]", key_arr.join(", ")).unwrap();
} }
kv!(output, "starting_board", world.starting_board, 0); if world.starting_board != 0 {
let comment = board_title_comment(&world.boards, world.starting_board as u8);
writeln!(output, "starting_board = {}{}", world.starting_board, comment).unwrap();
}
kv_bool!(output, "saved_game", world.locked); kv_bool!(output, "saved_game", world.locked);
// Print flags until we've printed all the non-empty ones. // Print flags until we've printed all the non-empty ones.
@@ -113,7 +137,7 @@ fn keys_to_array(keys: &[bool; 7]) -> Vec<&'static str> {
.collect() .collect()
} }
fn write_board(output: &mut String, index: Option<usize>, board: &Board) { fn write_board(output: &mut String, index: Option<usize>, board: &Board, boards: Option<&[Board]>) {
// Header cluster (always present) // Header cluster (always present)
match index { match index {
Some(i) => writeln!(output, "[board {}]", i).unwrap(), Some(i) => writeln!(output, "[board {}]", i).unwrap(),
@@ -127,20 +151,20 @@ fn write_board(output: &mut String, index: Option<usize>, board: &Board) {
// Board properties cluster (may be empty) // Board properties cluster (may be empty)
let mut props = String::new(); let mut props = String::new();
write_board_properties(&mut props, board); write_board_properties(&mut props, board, boards);
// Stats cluster (may be empty) // Stats cluster (may be empty)
let mut stats = String::new(); let mut stats_output = String::new();
for (i, stat) in board.stats.iter().enumerate() { for (i, stat) in board.stats.iter().enumerate() {
if i > 0 { if i > 0 {
stats.push('\n'); // blank between stats stats_output.push('\n'); // blank between stats
} }
let element = get_element_at(board, stat.x, stat.y); let element = get_element_at(board, stat.x, stat.y);
write_stat(&mut stats, i, stat, element); write_stat(&mut stats_output, i, stat, element, &board.stats, boards);
} }
// Join non-empty clusters with single blank lines // Join non-empty clusters with single blank lines
for cluster in [props, stats] { for cluster in [props, stats_output] {
if !cluster.is_empty() { if !cluster.is_empty() {
output.push('\n'); output.push('\n');
output.push_str(&cluster); output.push_str(&cluster);
@@ -148,13 +172,25 @@ fn write_board(output: &mut String, index: Option<usize>, board: &Board) {
} }
} }
fn write_board_properties(output: &mut String, board: &Board) { fn write_board_properties(output: &mut String, board: &Board, boards: Option<&[Board]>) {
kv!(output, "shots", board.max_shots, 255); kv!(output, "shots", board.max_shots, 255);
kv_bool!(output, "dark", board.is_dark); kv_bool!(output, "dark", board.is_dark);
kv!(output, "exit_n", board.exit_north, 0);
kv!(output, "exit_s", board.exit_south, 0); // Helper to write exit with optional board title comment
kv!(output, "exit_e", board.exit_east, 0); fn write_exit(output: &mut String, name: &str, index: u8, boards: Option<&[Board]>) {
kv!(output, "exit_w", board.exit_west, 0); if index != 0 {
let comment = boards
.map(|b| board_title_comment(b, index))
.unwrap_or_default();
writeln!(output, "{} = {}{}", name, index, comment).unwrap();
}
}
write_exit(output, "exit_n", board.exit_north, boards);
write_exit(output, "exit_s", board.exit_south, boards);
write_exit(output, "exit_e", board.exit_east, boards);
write_exit(output, "exit_w", board.exit_west, boards);
kv_bool!(output, "reenter", board.restart_on_zap); kv_bool!(output, "reenter", board.restart_on_zap);
kv!(output, "time_limit", board.time_limit, 0); kv!(output, "time_limit", board.time_limit, 0);
if board.enter_x != 1 || board.enter_y != 1 { if board.enter_x != 1 || board.enter_y != 1 {
@@ -193,7 +229,14 @@ fn get_element_at(board: &Board, x: u8, y: u8) -> Option<u8> {
board.tiles.get(index).map(|t| t.element) board.tiles.get(index).map(|t| t.element)
} }
fn write_stat(output: &mut String, index: usize, stat: &Stat, element: Option<u8>) { fn write_stat(
output: &mut String,
index: usize,
stat: &Stat,
element: Option<u8>,
stats: &[Stat],
boards: Option<&[Board]>,
) {
// Stat header with element type comment // Stat header with element type comment
let element_comment = match element { let element_comment = match element {
Some(id) => element_name(id), Some(id) => element_name(id),
@@ -229,7 +272,17 @@ fn write_stat(output: &mut String, index: usize, stat: &Stat, element: Option<u8
let elem = element.and_then(Element::from_u8); let elem = element.and_then(Element::from_u8);
write_param(output, stat.p1, "p1", elem.and_then(|e| e.p1_alias())); write_param(output, stat.p1, "p1", elem.and_then(|e| e.p1_alias()));
write_param(output, stat.p2, "p2", elem.and_then(|e| e.p2_alias())); write_param(output, stat.p2, "p2", elem.and_then(|e| e.p2_alias()));
write_param(output, stat.p3, "p3", elem.and_then(|e| e.p3_alias()));
// Special case for Passage destination (p3) - always output with board title comment
// (p3=0 means "go to title screen" for passages, which is a valid destination)
if element == Some(Element::Passage as u8) {
let comment = boards
.map(|b| board_title_comment(b, stat.p3))
.unwrap_or_default();
writeln!(output, "destination = {}{}", stat.p3, comment).unwrap();
} else {
write_param(output, stat.p3, "p3", elem.and_then(|e| e.p3_alias()));
}
// Program/code // Program/code
match &stat.program { match &stat.program {
@@ -242,7 +295,8 @@ fn write_stat(output: &mut String, index: usize, stat: &Stat, element: Option<u8
output.push_str("\"\"\"\n"); output.push_str("\"\"\"\n");
} }
Program::Bound(idx) => { Program::Bound(idx) => {
writeln!(output, "bind = {}", idx).unwrap(); let comment = bind_target_comment(stats, *idx);
writeln!(output, "bind = {}{}", idx, comment).unwrap();
} }
_ => {} _ => {}
} }