Skip to content

Commit 9552a90

Browse files
committed
Improves art facing heuristic
Refines the heuristic for determining the preferred facing direction of ASCII art. Uses a weighted score based on multiple cues, including arrow counts, substring patterns, and line-based indicators, to reduce instances of incorrectly mirrored art. Defaults to right-facing when the score is balanced for stability.
1 parent c72ce38 commit 9552a90

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

src/widgets/asciiquarium.rs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,19 +317,55 @@ fn mirror_ascii_line(s: &str) -> String {
317317
s.chars().rev().map(mirror_char).collect()
318318
}
319319

320-
/// Heuristic: decide if the art prefers facing right (more '>' than '<').
321-
/// If equal, default to right-facing.
320+
/// Heuristic: decide if the art prefers facing right.
321+
/// Uses a weighted score with multiple cues to reduce false “backwards” cases:
322+
/// - Count of '>' vs '<'
323+
/// - Right/left-facing substring cues (e.g., \"('>\", \"o>\", \"<')\", \"<o\")
324+
/// - Line-based cues (line ends with '>' or starts with '<')
325+
/// Defaults to right-facing when balanced.
322326
fn art_prefers_right(art: &str) -> bool {
323-
let mut gt = 0usize;
324-
let mut lt = 0usize;
327+
// 1) Base score from arrow counts
328+
let mut gt = 0i32;
329+
let mut lt = 0i32;
325330
for ch in art.chars() {
326-
if ch == '>' {
327-
gt += 1;
328-
} else if ch == '<' {
329-
lt += 1;
331+
match ch {
332+
'>' => gt += 1,
333+
'<' => lt += 1,
334+
_ => {}
330335
}
331336
}
332-
gt >= lt
337+
let mut score = gt - lt;
338+
339+
// 2) Substring cues (weighted)
340+
const RIGHT_CUES: [&str; 8] = ["('>", "o>", "0>", "))>", "]>", "}>", " )>", "/>"];
341+
const LEFT_CUES: [&str; 8] = ["<')", "<o", "<0", "<((", "<[", "<{", "<) ", "<\\"];
342+
343+
let s = art;
344+
for cue in RIGHT_CUES {
345+
// weight +2 per match
346+
score += 2 * s.matches(cue).count() as i32;
347+
}
348+
for cue in LEFT_CUES {
349+
// weight -2 per match
350+
score -= 2 * s.matches(cue).count() as i32;
351+
}
352+
353+
// 3) Line-based cues: line ends with '>' => right, starts with '<' => left
354+
for line in art.lines() {
355+
let t = line.trim();
356+
if t.is_empty() {
357+
continue;
358+
}
359+
if t.ends_with('>') {
360+
score += 1;
361+
}
362+
if t.starts_with('<') {
363+
score -= 1;
364+
}
365+
}
366+
367+
// Default to right on tie for stability
368+
score >= 0
333369
}
334370

335371
fn ensure_environment_initialized(state: &mut AquariumState) {

0 commit comments

Comments
 (0)