This commit is contained in:
Cilly Leang 2024-07-16 16:41:01 +10:00
commit 0d84b22fa3
Signed by: cilly
GPG key ID: 6500251E087653C9
8 changed files with 1845 additions and 0 deletions

1
.envrc Normal file
View file

@ -0,0 +1 @@
use flake

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
/ignore

75
Cargo.lock generated Normal file
View file

@ -0,0 +1,75 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "libc"
version = "0.2.155"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
name = "oh-hi-solver"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "ppv-lite86"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"

12
Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "oh-hi-solver"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8"
[profile.release]
debug = true

113
flake.lock generated Normal file
View file

@ -0,0 +1,113 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1705309234,
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1681202837,
"narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "cfacdce06f30d2b68473a46042957675eebb3401",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1717974879,
"narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=",
"path": "/nix/store/rljkm6h18fjvavm6l17jiil8glphc44f-source",
"rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"rust-overlay": "rust-overlay"
}
},
"rust-overlay": {
"inputs": {
"flake-utils": "flake-utils_2",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1705889935,
"narHash": "sha256-77KPBK5e0ACNzIgJDMuptTtEqKvHBxTO3ksqXHHVO+4=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "e36f66bb10b09f5189dc3b1706948eaeb9a1c555",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

28
flake.nix Normal file
View file

@ -0,0 +1,28 @@
{
description = "nix dev environment";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
#nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
rust-overlay.url = "github:oxalica/rust-overlay";
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
};
outputs = { self, nixpkgs, flake-utils, rust-overlay, ... }:
flake-utils.lib.eachDefaultSystem(system:
let
overlays = [ (import rust-overlay) ];
pkgs = import nixpkgs {
inherit system overlays;
};
toolchain = pkgs.rust-bin.fromRustupToolchain { channel = "nightly-2024-01-22"; };
in {
devShell = pkgs.mkShell {
buildInputs = with pkgs; [
pkg-config
openssl
toolchain
];
};
});
}

697
src/gen.rs Normal file
View file

@ -0,0 +1,697 @@
#![feature(iter_intersperse)]
const GRID: &str = r#"
..y..bb.....
.....b.b.bb.
bb..........
b.yb......y.
.....b...b..
.yb...b.....
....y..yy...
...b....y..y
.....yy....y
..yy.....y..
.b..........
b..b.y.b....
"#;
#[derive(Debug)]
pub struct Grid {
pub cells: Vec<Colour>,
dimension: usize
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Colour {
None,
Yellow,
Blue
}
impl Colour {
pub fn map_none<F>(self, mut cb: F) -> Colour
where F: FnMut() -> Colour {
if self == Colour::None {
cb()
} else {
self
}
}
}
impl Grid {
pub fn new(dimension: usize) -> Self {
let cells = vec![Colour::None; dimension * dimension];
Self {
cells,
dimension
}
}
pub fn up(&self, cell: usize) -> Option<usize> {
if cell < self.dimension {
None
} else {
Some(cell - self.dimension)
}
}
pub fn down(&self, cell: usize) -> Option<usize> {
if cell >= self.cells.capacity() - self.dimension {
None
} else {
Some(cell + self.dimension)
}
}
pub fn left(&self, cell: usize) -> Option<usize> {
if cell % self.dimension == 0 {
None
} else {
Some(cell - 1)
}
}
pub fn right(&self, cell: usize) -> Option<usize> {
if (cell + 1) % self.dimension == 0 {
None
} else {
Some(cell + 1)
}
}
pub fn from_pos(&self, x: usize, y: usize) -> Option<usize> {
if x > self.dimension - 1 || y > self.dimension - 1 {
return None;
}
return Some(self.dimension * y + x);
}
pub fn populate_alt(&mut self, input: &str) -> &mut Self {
let mut i = 0;
for ch in input.chars().filter(|c| !c.is_whitespace()) {
if i >= self.cells.len() {
panic!();
}
let colour = match ch {
'0' | 'y' => Colour::Yellow,
'1' | 'b' => Colour::Blue,
_ => Colour::None,
};
self.cells[i] = colour;
i += 1;
}
self
}
pub fn populate(&mut self, cells: &[(usize, usize, usize)]) -> &mut Self {
for (x, y, colour) in cells.into_iter() {
let pos = self.from_pos(*x, *y);
if pos.is_none() {
panic!("OOB");
}
let pos = pos.unwrap();
let colour = match colour {
0 => Colour::Yellow,
1 => Colour::Blue,
_ => panic!("Unknown colour")
};
self.cells[pos] = colour;
}
self
}
pub fn as_rows(&self) -> Vec<&[Colour]> {
let mut vec = Vec::with_capacity(self.dimension);
for row in 0..self.dimension {
let firstcell = self.dimension * row;
let lastbound = firstcell + self.dimension;
vec.push(&self.cells[firstcell..lastbound]);
}
vec
}
pub fn as_cols(&self) -> Vec<Vec<Colour>> {
let mut vec = Vec::with_capacity(self.dimension);
for col in 0..=self.dimension {
let v = self.cells.iter().skip(col).step_by(self.dimension).cloned().collect::<Vec<_>>();
vec.push(v);
}
vec
}
pub fn print(&self) {
let mut i = 0;
for cell in &self.cells {
i += 1;
let res = match cell {
Colour::Yellow => "y",
Colour::Blue => "b",
Colour::None => "?",
};
print!("{}", res);
if i % self.dimension == 0 {
println!();
}
}
}
}
// struct Grid<const LENGTH: usize> {
// cells: [Option<bool>; LENGTH],
// }
fn main() {
let mut grid = Grid::new(12);
grid.populate_alt(GRID);
grid.print();
println!();
let mut oi = 0;
let mut ii = 0;
let mut ui = 0;
let mut uit = 0;
let mut cht = 0;
let mut chl = vec![];
let mut trace = [0u8; 10];
let mut secondary_trace = vec![];
for _ in 0..=grid.cells.len() {
oi += 1;
let mut changed = false;
let mut chi = 0;
for cell in 0..(grid.cells.len()) {
if grid.cells[cell] != Colour::None {
continue;
}
ii += 1;
let colour = test_eqrow(&grid, cell, &mut trace[0], &mut secondary_trace)
.map_none(|| test_eqcol(&grid, cell, &mut trace[1], &mut secondary_trace))
.map_none(|| test_neighbour_hori(&grid, cell, &mut trace[2], &mut secondary_trace))
.map_none(|| test_neighbour_vert(&grid, cell, &mut trace[3], &mut secondary_trace))
.map_none(|| test_double_horileft(&grid, cell, &mut trace[4], &mut secondary_trace))
.map_none(|| test_double_horiright(&grid, cell, &mut trace[5], &mut secondary_trace))
.map_none(|| test_double_vertup(&grid, cell, &mut trace[6], &mut secondary_trace))
.map_none(|| test_double_vertdown(&grid, cell, &mut trace[7], &mut secondary_trace));
if colour != Colour::None {
cht += 1;
chi += 1;
changed = true;
}
grid.cells[cell] = colour;
}
chl.push(chi);
if !changed {
uit += 1;
for cell in 0..(grid.cells.len()) {
if grid.cells[cell] != Colour::None {
continue;
}
let colour = test_matching_row(&grid, cell, &mut trace[8], &mut secondary_trace)
.map_none(|| test_matching_col(&grid, cell, &mut trace[9], &mut secondary_trace));
if colour != Colour::None {
ui += 1;
}
grid.cells[cell] = colour;
}
}
if !grid.cells.contains(&Colour::None) {
break
}
}
println!();
let solved = !grid.cells.contains(&Colour::None);
grid.print();
println!();
println!("{}", if solved { "solved" } else { "unsolved" });
println!("iter: {}/{}", oi, grid.cells.len() + 1);
println!("checked: {}+{}/{}/{}/{}", cht, ui, ii, oi * grid.cells.len(), grid.cells.len() * (grid.cells.len() + 1));
println!("matching check: {}/{}", ui, uit);
println!("chl: {:?}", chl);
println!("- eqrow: {}", trace[0]);
println!("- eqcol: {}", trace[1]);
println!("- neighbour_hori: {}", trace[2]);
println!("- neighbour_vert: {}", trace[3]);
println!("- double_horileft: {}", trace[4]);
println!("- double_horiright: {}", trace[5]);
println!("- double_vertup: {}", trace[6]);
println!("- double_vertdown: {}", trace[7]);
println!("- matching_row: {}", trace[8]);
println!("- matching_col: {}", trace[9]);
let mut bo = false;
println!("seq: {}", secondary_trace
.into_iter()
.map(|u| u.to_string())
.intersperse_with(|| {
bo = !bo;
if bo {
".".to_string()
} else {
"_".to_string()
}
})
.collect::<String>());
}
fn test_eqrow(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let mut yellow = 0;
let mut blue = 0;
let mut nextleft = cell;
loop {
let nextref = grid.left(nextleft);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextleft = nextref;
} else {
break;
}
}
let mut nextright = cell;
loop {
let nextref = grid.right(nextright);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextright = nextref;
} else {
break;
}
}
Colour::None
}
fn test_eqcol(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let mut yellow = 0;
let mut blue = 0;
let mut nextup = cell;
loop {
let nextref = grid.up(nextup);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextup = nextref;
} else {
break;
}
}
let mut nextdown = cell;
loop {
let nextref = grid.down(nextdown);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextdown = nextref;
} else {
break;
}
}
Colour::None
}
fn test_neighbour_vert(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let above = grid.up(cell);
if above.is_none() {
return Colour::None;
}
let above = grid.cells[above.unwrap()];
let below = grid.down(cell);
if below.is_none() {
return Colour::None;
}
let below = grid.cells[below.unwrap()];
if above == below {
if above != Colour::None {
*trace += 1;
secondary_trace.push(2);
secondary_trace.push(cell);
}
return match above {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
Colour::None
}
fn test_neighbour_hori(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let left = grid.left(cell);
if left.is_none() {
return Colour::None;
}
let left = grid.cells[left.unwrap()];
let right = grid.right(cell);
if right.is_none() {
return Colour::None;
}
let right = grid.cells[right.unwrap()];
if left == right {
if left != Colour::None {
*trace += 1;
secondary_trace.push(3);
secondary_trace.push(cell);
}
return match left {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
Colour::None
}
fn test_double_horileft(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
//let target = grid.from_pos(9, 1).unwrap();
let leftref = grid.left(cell);
//if cell == target { println!("a {:?}", leftref) };
if let Some(leftref) = leftref {
let left = grid.cells[leftref];
let lefter = grid.left(leftref).map(|lefterref| grid.cells[lefterref]).unwrap_or(Colour::None);
//if cell == target { println!("{:?}, {:?}", left, lefter) };
if left == lefter {
if left != Colour::None {
*trace += 1;
secondary_trace.push(4);
secondary_trace.push(cell);
}
return match left {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_horiright(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let rightref = grid.right(cell);
//if cell == target { println!("b {:?}", leftref) };
if let Some(rightref) = rightref {
let right = grid.cells[rightref];
let righter = grid.right(rightref).map(|righterref| grid.cells[righterref]).unwrap_or(Colour::None);
//if cell == target { println!("{:?}, {:?}", right, righter) };
if right == righter {
if right != Colour::None {
*trace += 1;
secondary_trace.push(5);
secondary_trace.push(cell);
}
return match right {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_vertup(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let upref = grid.up(cell);
if let Some(upref) = upref {
let up = grid.cells[upref];
let upper = grid.up(upref).map(|upperref| grid.cells[upperref]).unwrap_or(Colour::None);
if up == upper {
if up != Colour::None {
*trace += 1;
secondary_trace.push(6);
secondary_trace.push(cell);
}
return match up {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_vertdown(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let downref = grid.down(cell);
if let Some(downref) = downref {
let down = grid.cells[downref];
let downer = grid.down(downref).map(|downerref| grid.cells[downerref]).unwrap_or(Colour::None);
if down == downer {
if down != Colour::None {
*trace += 1;
secondary_trace.push(7);
secondary_trace.push(cell);
}
return match down {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_matching_row(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let rows = grid.as_rows();
let cellrow = rows[cell / grid.dimension];
let ncount = cellrow.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for row in rows {
if std::ptr::eq(row, cellrow) {
continue;
}
for i in 0..grid.dimension {
let current = cellrow[i];
let against = row[i];
if current != Colour::None && current != against {
continue 'outer;
}
}
let first_none = cellrow.iter().position(|e| *e == Colour::None).unwrap();
*trace += 1;
secondary_trace.push(8);
secondary_trace.push(cell);
return match row[first_none] {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => unreachable!(),
};
}
Colour::None
}
fn test_matching_col(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let cols = grid.as_cols();
let cellcol = &cols[cell % grid.dimension];
let ncount = cellcol.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for col in &cols {
if col == cellcol {
continue;
}
for i in 0..grid.dimension {
let current = cellcol[i];
let against = col[i];
if against == Colour::None {
continue 'outer;
}
if current != Colour::None && current != against {
continue 'outer;
}
}
let first_none = cellcol.iter().position(|e| *e == Colour::None).unwrap();
*trace += 1;
secondary_trace.push(9);
secondary_trace.push(cell);
return match col[first_none] {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => unreachable!(),
};
}
Colour::None
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
struct Solution;
impl Solution {
pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut res = vec![];
let mut p1 = l1;
let mut p2 = l2;
let mut rollover = false;
loop {
if p1.is_none() && p2.is_none() {
if rollover {
res.push(1);
}
break;
}
let v1;
if let Some(p1u) = p1 {
v1 = p1u.val;
p1 = p1u.next;
} else {
v1 = 0;
}
let v2;
if let Some(p2u) = p2 {
v2 = p2u.val;
p2 = p2u.next;
} else {
v2 = 0;
}
let mut nw = v1 + v2;
if rollover {
nw += 1;
rollover = false;
}
if nw > 9 {
nw -= 10;
rollover = true;
}
res.push(nw);
// if res.val == -1 {
// res = Box::new(npr);
// last = &npr;
// } else {
// # let mut o = Box::new(ListNode::new(nextp));
// # last.next = Some(o);
// # last = &mut o;
//}
}
let mut prev: Option<Box<ListNode>> = None;
for i in res.into_iter().rev() {
let mut np = ListNode::new(i);
np.next = prev;
prev = Some(Box::new(np));
}
return prev;
}
}

917
src/main.rs Normal file
View file

@ -0,0 +1,917 @@
#![feature(iter_intersperse)]
use std::io::Write;
use std::ptr::null;
use rand::Rng;
// Array.from(document.getElementById("grid").children[0].children).map(i => Array.from(i.children).map(l => l.children[0].classList[1] === "tile-" ? "." : (l.children[0].classList[1] === "tile-1" ? "b" : "y"))).flat().join("")
const GRID: &str = r#"
..y..bb.....
.....b.b.bb.
bb..........
b.yb......y.
.....b...b..
.yb...b.....
....y..yy...
...b....y..y
.....yy....y
..yy.....y..
.b..........
b..b.y.b....
"#;
const SOLVED: &str = r#"
ybybybbybyyb
yybybbybybby
bbyybybybyby
byybybyybbyb
ybbybbybybyy
yybybybybybb
bbybyybyybyb
yybbybybybby
bybybyybbyby
bbyybybybyyb
ybybybybybyb
bybbyybbyyby
"#;
#[derive(Clone, Debug)]
pub struct Grid {
pub cells: Vec<Colour>,
dimension: usize,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Colour {
None,
Yellow,
Blue
}
impl Colour {
pub fn map_none<F>(self, mut cb: F) -> Colour
where F: FnMut() -> Colour {
if self == Colour::None {
cb()
} else {
self
}
}
pub fn as_i8(&self) -> i8 {
match self {
Colour::None => 0,
Colour::Yellow => 1,
Colour::Blue => 2,
}
}
}
impl Grid {
pub fn new(dimension: usize) -> Self {
let cells = vec![Colour::None; dimension * dimension];
Self {
cells,
dimension
}
}
pub fn up(&self, cell: usize) -> Option<usize> {
if cell < self.dimension {
None
} else {
Some(cell - self.dimension)
}
}
pub fn down(&self, cell: usize) -> Option<usize> {
if cell >= self.cells.capacity() - self.dimension {
None
} else {
Some(cell + self.dimension)
}
}
pub fn left(&self, cell: usize) -> Option<usize> {
if cell % self.dimension == 0 {
None
} else {
Some(cell - 1)
}
}
pub fn right(&self, cell: usize) -> Option<usize> {
if (cell + 1) % self.dimension == 0 {
None
} else {
Some(cell + 1)
}
}
pub fn from_pos(&self, x: usize, y: usize) -> Option<usize> {
if x > self.dimension - 1 || y > self.dimension - 1 {
return None;
}
return Some(self.dimension * y + x);
}
pub fn populate_alt(&mut self, input: &str) -> &mut Self {
let mut i = 0;
for ch in input.chars().filter(|c| !c.is_whitespace()) {
if i >= self.cells.len() {
panic!();
}
let colour = match ch {
'0' | 'y' => Colour::Yellow,
'1' | 'b' => Colour::Blue,
_ => Colour::None,
};
self.cells[i] = colour;
i += 1;
}
self
}
pub fn populate(&mut self, cells: &[(usize, usize, usize)]) -> &mut Self {
for (x, y, colour) in cells.into_iter() {
let pos = self.from_pos(*x, *y);
if pos.is_none() {
panic!("OOB");
}
let pos = pos.unwrap();
let colour = match colour {
0 => Colour::Yellow,
1 => Colour::Blue,
_ => panic!("Unknown colour")
};
self.cells[pos] = colour;
}
self
}
pub fn as_rows(&self) -> Vec<&[Colour]> {
let mut vec = Vec::with_capacity(self.dimension);
for row in 0..self.dimension {
let firstcell = self.dimension * row;
let lastbound = firstcell + self.dimension;
vec.push(&self.cells[firstcell..lastbound]);
}
vec
}
/**pub fn as_cols(&self) -> Vec<Vec<&Colour>> {
if let Some(c) = self.cols {
return c;
}
let mut vec = vec![vec![]; self.dimension];
let mut i = 0;
for cell in &self.cells {
let oi = i / self.dimension;
let ii = i % self.dimension;
vec[oi].push(cell);
i += 1;
}
vec
}
pub fn __as_cols(&self) -> Vec<Vec<Colour>> {
let mut vec = vec![vec![Colour::None; self.dimension]; self.dimension];
let mut i = 0;
for cell in &self.cells {
let oi = i / self.dimension;
let ii = i % self.dimension;
vec[oi][ii] = *cell;
i += 1;
}
vec
}*/
pub fn as_cols(&self) -> Vec<Vec<Colour>> {
let mut vec = Vec::with_capacity(self.dimension);
for col in 0..self.dimension {
let v = self.cells.iter().skip(col).step_by(self.dimension).cloned().collect::<Vec<_>>();
vec.push(v);
}
vec
}
pub fn print(&self) {
let mut i = 0;
for cell in &self.cells {
i += 1;
let res = match cell {
Colour::Yellow => "y",
Colour::Blue => "b",
Colour::None => "?",
};
print!("{}", res);
if i % self.dimension == 0 {
println!();
}
}
}
}
// struct Grid<const LENGTH: usize> {
// cells: [Option<bool>; LENGTH],
// }
fn main()
{
let args = std::env::args().collect::<Vec<String>>();
let raw = args.into_iter().skip(1).next().unwrap_or(GRID.to_string());
println!("{}", raw);
sd(&raw);
}
fn _main()
{
let mut g: Grid = Grid::new(12);
let mut prev = 150;
for _ in 0..1 {
let (counter, last_len, grid) = gen();
if last_len < prev {
prev = last_len;
g = grid;
}
println!("it {}, ln {}", counter, last_len);
/*
println!();
println!();
println!("iterations: {}", counter);
println!("filled: {}/{}", last_len, 12 * 12);
*/
}
g.print();
}
fn gen() -> (usize, i32, Grid) {
let mut grid = Grid::new(12);
grid.populate_alt(SOLVED);
let mut chq: Vec<usize> = vec![0; 12*12];
let mut counter = 0;
chq.fill_with(|| { let a = counter; counter += 1; a });
counter = 0;
let mut last_len = 12 * 12;
loop {
counter += 1;
if chq.len() == 0 {
break;
}
//let i = rand::thread_rng().gen_range(0..chq.len());
let i = 0;
let mut clone = grid.clone();
clone.cells[chq[i]] = Colour::None;
chq.swap_remove(i);
let (solved, _) = solve(&mut clone.clone());
if solved {
last_len -= 1;
grid = clone;
chq = vec![];
for (i, col) in grid.cells.iter().enumerate() {
if *col != Colour::None {
chq.push(i);
}
}
}
// print!(".");
// let _ = std::io::stdout().flush();
}
return (counter, last_len, grid);
}
fn sd(raw: &str) {
let mut grid = Grid::new(12);
grid.populate_alt(raw);
let ogrid = grid.clone();
grid.print();
println!();
let (solved, (oi, ii, ui, uit, cht, chl, trace, secondary_trace)) = solve(&mut grid);
grid.print();
println!();
println!("{}", if solved { "solved" } else { "unsolved" });
println!("iter: {}/{}", oi, grid.cells.len() + 1);
println!("checked: {}+{}/{}/{}/{}", cht, ui, ii, oi * grid.cells.len() as i32, grid.cells.len() * (grid.cells.len() + 1));
println!("matching check: {}/{}", ui, uit);
println!("chl: {:?}", chl);
println!("- eqrow: {}", trace[0]);
println!("- eqcol: {}", trace[1]);
println!("- neighbour_hori: {}", trace[2]);
println!("- neighbour_vert: {}", trace[3]);
println!("- double_horileft: {}", trace[4]);
println!("- double_horiright: {}", trace[5]);
println!("- double_vertup: {}", trace[6]);
println!("- double_vertdown: {}", trace[7]);
println!("- matching_row: {}", trace[8]);
println!("- matching_col: {}", trace[9]);
let mut bo = false;
println!("seq: {}", secondary_trace
.into_iter()
.map(|u| u.to_string())
.intersperse_with(|| {
bo = !bo;
if bo {
".".to_string()
} else {
"_".to_string()
}
})
.collect::<String>());
println!("{}", diff(&ogrid, &grid));
}
fn diff(grid1: &Grid, grid2: &Grid) -> String {
let mut str = String::with_capacity(grid1.dimension * grid1.dimension);
for i in 0..(grid1.dimension * grid1.dimension) {
let c1 = grid1.cells[i].as_i8();
let c2 = grid2.cells[i].as_i8();
let mut diff = c2 - c1;
if diff < 0 {
diff += 2;
}
str += &diff.to_string();
}
str
}
fn solve(grid: &mut Grid) -> (bool, (i32, i32, i32, i32, i32, Vec<i32>, [u8; 10], Vec<usize>)) {
let mut oi = 0;
let mut ii = 0;
let mut ui = 0;
let mut uit = 0;
let mut cht = 0;
let mut chl = vec![];
let mut trace = [0u8; 10];
let mut secondary_trace = vec![];
for _ in 0..=grid.cells.len() {
oi += 1;
let mut changed = false;
let mut chi = 0;
for cell in 0..(grid.cells.len()) {
if grid.cells[cell] != Colour::None {
continue;
}
ii += 1;
let colour = test_eqrow(&grid, cell, &mut trace[0], &mut secondary_trace)
.map_none(|| test_eqcol(&grid, cell, &mut trace[1], &mut secondary_trace))
.map_none(|| test_neighbour_hori(&grid, cell, &mut trace[2], &mut secondary_trace))
.map_none(|| test_neighbour_vert(&grid, cell, &mut trace[3], &mut secondary_trace))
.map_none(|| test_double_horileft(&grid, cell, &mut trace[4], &mut secondary_trace))
.map_none(|| test_double_horiright(&grid, cell, &mut trace[5], &mut secondary_trace))
.map_none(|| test_double_vertup(&grid, cell, &mut trace[6], &mut secondary_trace))
.map_none(|| test_double_vertdown(&grid, cell, &mut trace[7], &mut secondary_trace));
if colour != Colour::None {
cht += 1;
chi += 1;
changed = true;
}
grid.cells[cell] = colour;
}
chl.push(chi);
if !changed {
uit += 1;
for cell in 0..(grid.cells.len()) {
if grid.cells[cell] != Colour::None {
continue;
}
let colour = test_matching_row(&grid, cell, &mut trace[8], &mut secondary_trace)
.map_none(|| test_matching_col(&grid, cell, &mut trace[9], &mut secondary_trace));
if colour != Colour::None {
ui += 1;
}
grid.cells[cell] = colour;
}
}
if !grid.cells.contains(&Colour::None) {
break
}
}
let solved = !grid.cells.contains(&Colour::None);
return (solved, (oi, ii, ui, uit, cht, chl, trace, secondary_trace));
}
fn test_eqrow(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let mut yellow = 0;
let mut blue = 0;
let mut nextleft = cell;
loop {
let nextref = grid.left(nextleft);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextleft = nextref;
} else {
break;
}
}
let mut nextright = cell;
loop {
let nextref = grid.right(nextright);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(0);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextright = nextref;
} else {
break;
}
}
Colour::None
}
fn test_eqcol(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let mut yellow = 0;
let mut blue = 0;
let mut nextup = cell;
loop {
let nextref = grid.up(nextup);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextup = nextref;
} else {
break;
}
}
let mut nextdown = cell;
loop {
let nextref = grid.down(nextdown);
if let Some(nextref) = nextref {
let colour = grid.cells[nextref];
match colour {
Colour::Yellow => yellow += 1,
Colour::Blue => blue += 1,
Colour::None => (),
};
if yellow == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Blue;
}
if blue == grid.dimension / 2 {
*trace += 1;
secondary_trace.push(1);
secondary_trace.push(cell);
return Colour::Yellow;
}
nextdown = nextref;
} else {
break;
}
}
Colour::None
}
fn test_neighbour_vert(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let above = grid.up(cell);
if above.is_none() {
return Colour::None;
}
let above = grid.cells[above.unwrap()];
let below = grid.down(cell);
if below.is_none() {
return Colour::None;
}
let below = grid.cells[below.unwrap()];
if above == below {
if above != Colour::None {
*trace += 1;
secondary_trace.push(2);
secondary_trace.push(cell);
}
return match above {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
Colour::None
}
fn test_neighbour_hori(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let left = grid.left(cell);
if left.is_none() {
return Colour::None;
}
let left = grid.cells[left.unwrap()];
let right = grid.right(cell);
if right.is_none() {
return Colour::None;
}
let right = grid.cells[right.unwrap()];
if left == right {
if left != Colour::None {
*trace += 1;
secondary_trace.push(3);
secondary_trace.push(cell);
}
return match left {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
Colour::None
}
fn test_double_horileft(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
//let target = grid.from_pos(9, 1).unwrap();
let leftref = grid.left(cell);
//if cell == target { println!("a {:?}", leftref) };
if let Some(leftref) = leftref {
let left = grid.cells[leftref];
let lefter = grid.left(leftref).map(|lefterref| grid.cells[lefterref]).unwrap_or(Colour::None);
//if cell == target { println!("{:?}, {:?}", left, lefter) };
if left == lefter {
if left != Colour::None {
*trace += 1;
secondary_trace.push(4);
secondary_trace.push(cell);
}
return match left {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_horiright(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let rightref = grid.right(cell);
//if cell == target { println!("b {:?}", leftref) };
if let Some(rightref) = rightref {
let right = grid.cells[rightref];
let righter = grid.right(rightref).map(|righterref| grid.cells[righterref]).unwrap_or(Colour::None);
//if cell == target { println!("{:?}, {:?}", right, righter) };
if right == righter {
if right != Colour::None {
*trace += 1;
secondary_trace.push(5);
secondary_trace.push(cell);
}
return match right {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_vertup(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let upref = grid.up(cell);
if let Some(upref) = upref {
let up = grid.cells[upref];
let upper = grid.up(upref).map(|upperref| grid.cells[upperref]).unwrap_or(Colour::None);
if up == upper {
if up != Colour::None {
*trace += 1;
secondary_trace.push(6);
secondary_trace.push(cell);
}
return match up {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
fn test_double_vertdown(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let downref = grid.down(cell);
if let Some(downref) = downref {
let down = grid.cells[downref];
let downer = grid.down(downref).map(|downerref| grid.cells[downerref]).unwrap_or(Colour::None);
if down == downer {
if down != Colour::None {
*trace += 1;
secondary_trace.push(7);
secondary_trace.push(cell);
}
return match down {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => Colour::None,
}
}
}
Colour::None
}
/**
*
let cellrow = rows[cell / grid.dimension];
let ncount = cellrow.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for row in rows {
if std::ptr::eq(row, cellrow) {
continue;
* */
/**
*
let cindex = cell / grid.dimension;
let cellrow = rows[cindex];
let ncount = cellrow.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for (i, row) in rows.iter().enumerate() {
if i == cindex {
*/
fn test_matching_row(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let rows = grid.as_rows();
let cellrow = &rows[cell / grid.dimension];
let ncount = cellrow.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for row in &rows {
if row == cellrow {
continue;
}
for i in 0..grid.dimension {
let current = cellrow[i];
let against = row[i];
if current != Colour::None && current != against {
continue 'outer;
}
}
let first_none = cellrow.iter().position(|e| *e == Colour::None).unwrap();
*trace += 1;
secondary_trace.push(8);
secondary_trace.push(cell);
return match row[first_none] {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => { println!("{:?}", row); println!("{:?}", cellrow); println!("{}", first_none); unreachable!()},
};
}
Colour::None
}
fn test_matching_col(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let cols = grid.as_cols();
let cellcol = &cols[cell % grid.dimension];
let ncount = cellcol.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for col in &cols {
if col == cellcol {
continue;
}
for i in 0..grid.dimension {
let current = cellcol[i];
let against = col[i];
if against == Colour::None {
continue 'outer;
}
if current != Colour::None && current != against {
continue 'outer;
}
}
let first_none = cellcol.iter().position(|e| *e == Colour::None).unwrap();
*trace += 1;
secondary_trace.push(9);
secondary_trace.push(cell);
return match col[first_none] {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => unreachable!(),
};
}
Colour::None
}
/**fn test_matching_col(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec<usize>) -> Colour {
let cellcol = grid.cells.iter().skip(col).step_by(grid.dimension).collect::<Vec<_>>();
let ncount = cellcol.iter().filter(|e| **e == Colour::None).count();
if ncount != 2 {
return Colour::None;
}
'outer: for col in 0..grid.dimension {
if col == cellcol {
continue;
}
for (idx, i) in grid.cells.iter().skip(col).step_by(grid.dimension).enumerate() {
let against = i;
if *against == Colour::None {
continue 'outer;
}
let current = cellcol[i];
if current != Colour::None && current != against {
continue 'outer;
}
}
let first_none = cellcol.iter().position(|e| *e == Colour::None).unwrap();
*trace += 1;
secondary_trace.push(9);
secondary_trace.push(cell);
return match col[first_none] {
Colour::Yellow => Colour::Blue,
Colour::Blue => Colour::Yellow,
Colour::None => unreachable!(),
};
}
Colour::None
}*/
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
impl ListNode {
#[inline]
fn new(val: i32) -> Self {
ListNode {
next: None,
val
}
}
}
struct Solution;
impl Solution {
pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut res = vec![];
let mut p1 = l1;
let mut p2 = l2;
let mut rollover = false;
loop {
if p1.is_none() && p2.is_none() {
if rollover {
res.push(1);
}
break;
}
let v1;
if let Some(p1u) = p1 {
v1 = p1u.val;
p1 = p1u.next;
} else {
v1 = 0;
}
let v2;
if let Some(p2u) = p2 {
v2 = p2u.val;
p2 = p2u.next;
} else {
v2 = 0;
}
let mut nw = v1 + v2;
if rollover {
nw += 1;
rollover = false;
}
if nw > 9 {
nw -= 10;
rollover = true;
}
res.push(nw);
// if res.val == -1 {
// res = Box::new(npr);
// last = &npr;
// } else {
// # let mut o = Box::new(ListNode::new(nextp));
// # last.next = Some(o);
// # last = &mut o;
//}
}
let mut prev: Option<Box<ListNode>> = None;
for i in res.into_iter().rev() {
let mut np = ListNode::new(i);
np.next = prev;
prev = Some(Box::new(np));
}
return prev;
}
}