init
This commit is contained in:
commit
9e74d12329
4 changed files with 209 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nonogram"
|
||||||
|
version = "0.1.0"
|
||||||
6
Cargo.toml
Normal file
6
Cargo.toml
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[package]
|
||||||
|
name = "nonogram"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
195
src/main.rs
Normal file
195
src/main.rs
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
use std::{array, env, error::Error, fmt, str::FromStr};
|
||||||
|
|
||||||
|
// TODO: we need <4 bits
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum Clue {
|
||||||
|
C0,
|
||||||
|
C1,
|
||||||
|
C2,
|
||||||
|
C3,
|
||||||
|
C4,
|
||||||
|
C5,
|
||||||
|
C1_1,
|
||||||
|
C1_2,
|
||||||
|
C2_1,
|
||||||
|
C1_3,
|
||||||
|
C3_1,
|
||||||
|
C2_2,
|
||||||
|
C1_1_1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Row> for Clue {
|
||||||
|
fn from(row: Row) -> Self {
|
||||||
|
match row.0 {
|
||||||
|
0b00000 => Clue::C0,
|
||||||
|
0b10000 | 0b01000 | 0b00100 | 0b00010 | 0b00001 => Clue::C1,
|
||||||
|
0b11000 | 0b01100 | 0b00110 | 0b00011 => Clue::C2,
|
||||||
|
0b11100 | 0b01110 | 0b00111 => Clue::C3,
|
||||||
|
0b11110 | 0b01111 => Clue::C4,
|
||||||
|
0b11111 => Clue::C5,
|
||||||
|
0b10100 | 0b10010 | 0b10001 | 0b01010 | 0b01001 | 0b00101 => Clue::C1_1,
|
||||||
|
0b10110 | 0b10011 | 0b01011 => Clue::C1_2,
|
||||||
|
0b11010 | 0b11001 | 0b01101 => Clue::C2_1,
|
||||||
|
0b10111 => Clue::C1_3,
|
||||||
|
0b11101 => Clue::C3_1,
|
||||||
|
0b11011 => Clue::C2_2,
|
||||||
|
0b10101 => Clue::C1_1_1,
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Clue {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
#[allow(clippy::enum_glob_use)]
|
||||||
|
use Clue::*;
|
||||||
|
|
||||||
|
Ok(match s.trim() {
|
||||||
|
"0" => C0,
|
||||||
|
"1" => C1,
|
||||||
|
"2" => C2,
|
||||||
|
"3" => C3,
|
||||||
|
"4" => C4,
|
||||||
|
"5" => C5,
|
||||||
|
"1 1" => C1_1,
|
||||||
|
"1 2" => C1_2,
|
||||||
|
"2 1" => C2_1,
|
||||||
|
"1 3" => C1_3,
|
||||||
|
"3 1" => C3_1,
|
||||||
|
"2 2" => C2_2,
|
||||||
|
"1 1 1" => C1_1_1,
|
||||||
|
_ => return Err(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Clue {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{:>5}",
|
||||||
|
match self {
|
||||||
|
Clue::C0 => "0",
|
||||||
|
Clue::C1 => "1",
|
||||||
|
Clue::C2 => "2",
|
||||||
|
Clue::C3 => "3",
|
||||||
|
Clue::C4 => "4",
|
||||||
|
Clue::C5 => "5",
|
||||||
|
Clue::C1_1 => "1 1",
|
||||||
|
Clue::C1_2 => "1 2",
|
||||||
|
Clue::C2_1 => "2 1",
|
||||||
|
Clue::C1_3 => "1 3",
|
||||||
|
Clue::C3_1 => "3 1",
|
||||||
|
Clue::C2_2 => "2 2",
|
||||||
|
Clue::C1_1_1 => "1 1 1",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct Row(u8);
|
||||||
|
|
||||||
|
impl fmt::Debug for Row {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{:05b}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Row {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for i in (0..5).rev() {
|
||||||
|
write!(f, "{}", if (self.0 >> i) & 1 == 1 { '#' } else { '.' })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct Board(u32);
|
||||||
|
|
||||||
|
impl Board {
|
||||||
|
const fn cardinality() -> u32 {
|
||||||
|
1 << 25
|
||||||
|
}
|
||||||
|
|
||||||
|
fn universe() -> impl Iterator<Item = Self> {
|
||||||
|
(0..Self::cardinality()).map(Self)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rows(self) -> [Row; 5] {
|
||||||
|
array::from_fn(|i| Row((self.0 >> (i * 5) & 0b11111) as u8))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn columns(self) -> [Row; 5] {
|
||||||
|
let [r1, r2, r3, r4, r5] = self.rows();
|
||||||
|
array::from_fn(|i| {
|
||||||
|
let i = 4 - i;
|
||||||
|
Row(((r1.0 >> i) & 1) << 4
|
||||||
|
| ((r2.0 >> i) & 1) << 3
|
||||||
|
| ((r3.0 >> i) & 1) << 2
|
||||||
|
| ((r4.0 >> i) & 1) << 1
|
||||||
|
| ((r5.0 >> i) & 1))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Board {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for row in self.rows() {
|
||||||
|
writeln!(f, "{row:?}")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Board {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for row in self.rows() {
|
||||||
|
writeln!(f, "{}|{}", Clue::from(row), row)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
struct Clues {
|
||||||
|
rows: [Clue; 5],
|
||||||
|
columns: [Clue; 5],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Board> for Clues {
|
||||||
|
fn from(board: Board) -> Self {
|
||||||
|
let rows = board.rows().map(Clue::from);
|
||||||
|
let columns = board.columns().map(Clue::from);
|
||||||
|
Clues { rows, columns }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_clues<'a>(i: impl Iterator<Item = &'a str>) -> Result<[Clue; 5], &'static str> {
|
||||||
|
i.map(str::parse::<Clue>)
|
||||||
|
.collect::<Result<Vec<_>, _>>()
|
||||||
|
.map_err(|()| "bad clue")?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| "five clues please")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_possible_truncation)]
|
||||||
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let rows = parse_clues(env::args().nth(1).ok_or("give me row clues")?.split(','))?;
|
||||||
|
let columns = parse_clues(env::args().nth(2).ok_or("give me column clues")?.split(','))?;
|
||||||
|
let clues = Clues { rows, columns };
|
||||||
|
println!("{clues:#?}");
|
||||||
|
for board in Board::universe() {
|
||||||
|
if Clues::from(board) == clues {
|
||||||
|
println!("{board}");
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err("couldn't solve")?
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue