commit 0d84b22fa3c2f1dbb31b5c0872c56cfb615eba96 Author: Cilly Leang Date: Tue Jul 16 16:41:01 2024 +1000 init diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a0f8b31 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/ignore diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..a1754c8 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..464062c --- /dev/null +++ b/Cargo.toml @@ -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 diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..0069dca --- /dev/null +++ b/flake.lock @@ -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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3025629 --- /dev/null +++ b/flake.nix @@ -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 + ]; + }; + }); +} diff --git a/src/gen.rs b/src/gen.rs new file mode 100644 index 0000000..657aad4 --- /dev/null +++ b/src/gen.rs @@ -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, + dimension: usize +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Colour { + None, + Yellow, + Blue +} + +impl Colour { + pub fn map_none(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 { + if cell < self.dimension { + None + } else { + Some(cell - self.dimension) + } + } + + pub fn down(&self, cell: usize) -> Option { + if cell >= self.cells.capacity() - self.dimension { + None + } else { + Some(cell + self.dimension) + } + } + + pub fn left(&self, cell: usize) -> Option { + if cell % self.dimension == 0 { + None + } else { + Some(cell - 1) + } + } + + pub fn right(&self, cell: usize) -> Option { + if (cell + 1) % self.dimension == 0 { + None + } else { + Some(cell + 1) + } + } + + pub fn from_pos(&self, x: usize, y: usize) -> Option { + 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> { + 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.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 { +// cells: [Option; 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::()); +} + +fn test_eqrow(grid: &Grid, cell: usize, trace: &mut u8, secondary_trace: &mut Vec) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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> +} + +impl ListNode { + #[inline] + fn new(val: i32) -> Self { + ListNode { + next: None, + val + } + } +} +struct Solution; +impl Solution { + pub fn add_two_numbers(l1: Option>, l2: Option>) -> Option> { + 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 = ⊀ + // } else { + // # let mut o = Box::new(ListNode::new(nextp)); + // # last.next = Some(o); + // # last = &mut o; + //} + } + let mut prev: Option> = None; + for i in res.into_iter().rev() { + let mut np = ListNode::new(i); + np.next = prev; + prev = Some(Box::new(np)); + } + return prev; + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..b5c4a8c --- /dev/null +++ b/src/main.rs @@ -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, + dimension: usize, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum Colour { + None, + Yellow, + Blue +} + +impl Colour { + pub fn map_none(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 { + if cell < self.dimension { + None + } else { + Some(cell - self.dimension) + } + } + + pub fn down(&self, cell: usize) -> Option { + if cell >= self.cells.capacity() - self.dimension { + None + } else { + Some(cell + self.dimension) + } + } + + pub fn left(&self, cell: usize) -> Option { + if cell % self.dimension == 0 { + None + } else { + Some(cell - 1) + } + } + + pub fn right(&self, cell: usize) -> Option { + if (cell + 1) % self.dimension == 0 { + None + } else { + Some(cell + 1) + } + } + + pub fn from_pos(&self, x: usize, y: usize) -> Option { + 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> { + 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> { + 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> { + 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.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 { +// cells: [Option; LENGTH], +// } + +fn main() +{ + let args = std::env::args().collect::>(); + 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 = 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::()); + + 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, [u8; 10], Vec)) { + 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> 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) -> Colour { + let cellcol = grid.cells.iter().skip(col).step_by(grid.dimension).collect::>(); + 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> +} + +impl ListNode { + #[inline] + fn new(val: i32) -> Self { + ListNode { + next: None, + val + } + } +} +struct Solution; +impl Solution { + pub fn add_two_numbers(l1: Option>, l2: Option>) -> Option> { + 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 = ⊀ + // } else { + // # let mut o = Box::new(ListNode::new(nextp)); + // # last.next = Some(o); + // # last = &mut o; + //} + } + let mut prev: Option> = None; + for i in res.into_iter().rev() { + let mut np = ListNode::new(i); + np.next = prev; + prev = Some(Box::new(np)); + } + return prev; + } +}