Initial commit
This commit is contained in:
commit
f0ba450ecf
5 changed files with 462 additions and 0 deletions
179
src/main.rs
Normal file
179
src/main.rs
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use std::str::FromStr;
|
||||
use std::{env, fmt};
|
||||
use std::fmt::Display;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use rand::seq::IteratorRandom;
|
||||
|
||||
const WIDTH: usize = 20;
|
||||
const HEIGHT: usize = 32;
|
||||
const MAX_MATCHES: usize = 2256;
|
||||
|
||||
const STRING: &str = "COW";
|
||||
const SOURCE_CHARS: &str = STRING;
|
||||
// const CHARS: [char; 3] = ['C', 'O', 'W'];
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct Grid(Vec<Vec<char>>);
|
||||
|
||||
impl Display for Grid {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for row in &self.0 {
|
||||
for &ch in row {
|
||||
write!(f, "{} ", ch)?; // Print each character with a space
|
||||
}
|
||||
writeln!(f)?; // Newline after each row
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
struct ParseError;
|
||||
|
||||
impl FromStr for Grid {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Grid(s.split('\n').map(|s|s.chars().collect()).collect()))
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_grid() -> Grid {
|
||||
Grid((0..HEIGHT).map(
|
||||
|_| (0..WIDTH).map(|_| SOURCE_CHARS.chars().choose(&mut rand::rng()).unwrap().clone()).collect()
|
||||
).collect())
|
||||
}
|
||||
|
||||
fn count_matches(grid: &Grid) -> usize {
|
||||
let len = STRING.len() - 1;
|
||||
let mut count = 0;
|
||||
// horizontal
|
||||
for row in 0..grid.0.len() {
|
||||
for col in 0..grid.0[0].len() - len {
|
||||
if STRING.chars().enumerate().all(|(i,c)| grid.0[row][col+i] == c) {
|
||||
count += 1;
|
||||
} else if STRING.chars().rev().enumerate().all(|(i,c)| grid.0[row][col+i] == c) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// vertical
|
||||
for row in 0..grid.0.len() - len {
|
||||
for col in 0..grid.0[0].len() {
|
||||
if STRING.chars().enumerate().all(|(i,c)| grid.0[row+i][col] == c) {
|
||||
count += 1;
|
||||
} else if STRING.chars().rev().enumerate().all(|(i,c)| grid.0[row+i][col] == c) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// y = x diagonal
|
||||
for row in len..grid.0.len() {
|
||||
for col in 0..grid.0[0].len() - len {
|
||||
if STRING.chars().enumerate().all(|(i,c)| grid.0[row-i][col+i] == c) {
|
||||
count += 1;
|
||||
} else if STRING.chars().rev().enumerate().all(|(i,c)| grid.0[row-i][col+i] == c) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// y = -x diagonal
|
||||
for row in 0..grid.0.len() - len {
|
||||
for col in 0..grid.0[0].len() - len {
|
||||
if STRING.chars().enumerate().all(|(i,c)| grid.0[row+i][col+i] == c) {
|
||||
count += 1;
|
||||
} else if STRING.chars().rev().enumerate().all(|(i,c)| grid.0[row+i][col+i] == c) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
count
|
||||
}
|
||||
|
||||
fn stats(iters: usize) {
|
||||
let mut counts = [0; MAX_MATCHES];
|
||||
for _ in 0..iters {
|
||||
let matches = count_matches(&generate_grid());
|
||||
counts[matches] += 1;
|
||||
}
|
||||
for i in 0..counts.len() {
|
||||
println!("{}", counts[i]);
|
||||
if i > 250 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
eprintln!("{} <n>: TODO calculate cows in puzzle <n> times and show stats", env::args().nth(0).unwrap())
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
let args: Vec<String> = env::args().collect();
|
||||
match args.len() {
|
||||
3 => match &args[1][..] {
|
||||
"stats" => match args[2].parse() {
|
||||
Ok(iters) => {
|
||||
stats(iters);
|
||||
ExitCode::SUCCESS
|
||||
},
|
||||
Err(_) => {
|
||||
eprintln!("Unable to parse iterations");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
eprintln!("Unknown command {}", args[1]);
|
||||
show_help();
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
},
|
||||
2 => match &args[1][..] {
|
||||
"--help" | "-h" => {
|
||||
show_help();
|
||||
ExitCode::SUCCESS
|
||||
},
|
||||
_ => {
|
||||
show_help();
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
},
|
||||
_ => {
|
||||
println!("{}", generate_grid());
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use test::Bencher;
|
||||
|
||||
#[test]
|
||||
fn test_count_matches() {
|
||||
let v: Vec<(&str, usize)> = vec![
|
||||
("WCCCCCCWWWWOOOOCOCOCO\nOWOOOOOOOOWCWWWOCOWCW\nOWWOWWOCCCCCWWWOWOWCO\nWOCWCWOOCOCCOCWOOCCWO\nOOOOWOOCOCOWWWOOOCCWC\nCWWOOOWCWOWOOCCWWWCCO\nCWCCOOOOCCOOOWOOOOCWW\nOWCWOCWCCCOOOWOWOOOCC\nOWCOCWWWCCWWOOOWWWWCW\nOOWWWCCCCWCCWOCWWWOCC\nCCWCWWCCWCCWWCWWCWOOW\nWCOOOWWWWOCCCWOWWOWWO\nOOWOOOWWWWWOOCOCWWWWW\nWOCWOCCOCOWWOOWOOCWWO\nWCOCOOOOCOCOWWWCCWCOW\nCOCCWCCOWCWWCCOOCCWOO\nWWCWWWOCOWWWOOCCCCOCC\nCWWOWWCWCOOOOWCOCCCWC\nWWWWOOWOCCWWOOCCCWWCO\nOOWCWOWOCCWWCWWOOOCOO\nOWCOWOWCWOCOCCWCCWCWW\nWOOOWCOWWWOOOCWWWCCCC\nOCWWCOOCOOWCWWWWOWWWO\nCCCWWWCCCCOWOWWOWOWCO\nWOWWOWWWOWCOOCOOOOOWO\nWWCOCCOCOWWCWCOCCCWWC\nOWWWCCOCCWWWWWWCWCOWW\nCWCCOCWCWWWOWCWWCWOWW\nCOCOCWWWCWCWCWCCCOOWO\nCCOCCWCWCWWWWOOWCWOOO\nCWWOWOOWCCOOCOOCOWWWC\nCOOCCCOOOOWCCOWWOOWOO\nOWWCCCOWCOOWCOOWWWCWO", 165),
|
||||
("COCCOOOOOCCCCWCOCWOWO\nWOWWOWWCOWOOCWOCOWWCC\nOWOWCWOOOCOCOWOCOCWCC\nCOOWOCWWOOOCOCCCOWCCW\nCOCOWWCCWCOOCOWOWCWWC\nWWOCOOCOCWOWOCCCWWOCC\nWCOWCWWOOOWOOCCCCWOOC\nOCOCOOOWWOCWCOCCOOWWO\nOCWOOOWWCOCOCWWOWOCCW\nOOCOCOOWCCWCWCOOWOWOW\nWOWOWCCCOWCCOCCCWCWCO\nCOCWOCCOOCWCOOCCWCWWW\nCOCOCOCOWOOOCCOOCOOOO\nOOWCWWOOCOOOWOOCOCWWC\nWCWOOWOWOOCCWOWCOCCOC\nOOOOCOCCOCOOCCOWWWWWO\nCOWWCWCCOCWOOCOOCCWOO\nOCCOOOOWOWOWWOCWWWOCO\nWCOCWWWWOCOWCCCOCOWCO\nWCCOCCOWCCCOWWWWOOOWC\nWOCCWWWOWCWWOCWCWWCCW\nOWWOOOCCCCCWWOCOCOCCO\nOWWWCOCCOOOCCCOCOCOCW\nOOWCCCWCWOWOOOCWCWCCW\nWCCWWCOWOCCOCWOWCWWWW\nCOOOWCOOOWCCWOCWWOCOO\nCWOOWWWCCWWOWWWOOOCOC\nCOCWOCWWWWOWOWWOWWCWC\nCCOCWCCWCCCOOWCWOCCCO\nWWCCWCCWOCCWWCOWWCCCC\nWOCOWCCWCWOOOOOCWCOWW\nCOWCCCWWCOCOOOWOCCCOC\nCWWWOOOOOCOOWWCWWCCWC", 177),
|
||||
("WCOOOCCCOWOWWCOOWCWOC\nCOWCCWCCOCOOCOWCCOCOO\nWWWCWCCCWOCOOCCWCOOCW\nCOOWCWCOCCOOCCOOWCCCO\nOWCOWWOWWWOOOWOWOWOOC\nOWWCCOOWWWOOCCCCWCWOW\nCWWOWCWOWOCCWWCWCOWCW\nOCCOOOWWOOOCWOWWWOWWW\nOCWCWCCOCCWCOOCOOCCCC\nCWOWOWOCCWCWWWCOWWWCC\nWCCOCWWOCOWCWWWCCCWCW\nOWWOOWWWCOCWCCOOOWWCW\nOOWCWWCOCCOCWWWCOWCOW\nCCWWWWWWOCCCCWOOCCWWC\nWWOOWWOOWWWCCOCWOWOOW\nWOCCWOWWWCCOOCOOWWWCC\nCCOOCWWWCOOOCCCCCOWWW\nCOOWWCWWCCOCCOCWWWOCO\nOWWCCOCWOWOOOWWOCWCWC\nOWCCOOCWCOWCWCCWWWWCW\nCCWOCOOWCOOWOCCCWWOOC\nCWOWWCCWWWWWCWWWOCOWW\nCOOOWCCCOCWOCOCWOOWWC\nWWOCWCOOCCOWOOOOCCCCO\nOCOWCCOCWCCWOCWCWCCCW\nCOOWCWWOCOWCCCOWOOCCC\nOWOWCWOWCWWOWCOOWWCOW\nWCOOOOWCWCOCOCOCWCWWC\nOOOOOWCWCWWWWWOCOCWOW\nOOCWWCCWOWWOOOCOOWOWW\nCWWCOCOOCCWOCCWOWCOCO\nCCWOWOCOOCWOWWWCWCCWO\nOOWWOOWCWWOWCWWOWWCCC", 173)
|
||||
];
|
||||
for (s, n) in v {
|
||||
assert_eq!(count_matches(&s.parse().unwrap()), n)
|
||||
}
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_generate_grid(b: &mut Bencher) {
|
||||
b.iter(|| generate_grid())
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_count_matches(b: &mut Bencher) {
|
||||
let grid = generate_grid();
|
||||
b.iter(|| count_matches(&grid))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue