Skip to content
Permalink
Browse files

Refactoring to modules

  • Loading branch information...
ichyo committed Jun 22, 2019
1 parent a558980 commit 82502bad2e6994e73a655dfc35ada97150fd6e9d
Showing with 452 additions and 651 deletions.
  1. +4 −0 Cargo.toml
  2. +19 −264 src/bin/score.rs
  3. +3 −0 src/lib.rs
  4. +15 −387 src/main.rs
  5. +152 −0 src/models.rs
  6. +165 −0 src/parse.rs
  7. +94 −0 src/solve.rs
@@ -9,3 +9,7 @@ clap = "2.33.0"
glob = "0.3.0"
rand = "0.6.5"
rayon = "1.1.0"

[lib]
name = "icfpc"
path = "src/lib.rs"
@@ -1,252 +1,8 @@
use clap::{App, Arg};
use glob::glob;
use std::cmp;
use std::collections::{HashMap, VecDeque};
use icfpc::models::*;
use icfpc::parse::read_all_inputs;
use std::fs::File;
use std::io::Read;
use std::iter::Peekable;
use std::str::Chars;

fn find_files(input_root: &str) -> Vec<String> {
glob(&format!("{}/prob-*.desc", input_root))
.expect("glob pattern")
.map(|p| {
p.unwrap()
.file_name()
.unwrap()
.to_str()
.unwrap()
.to_string()
})
.collect::<Vec<String>>()
}

fn output_file_name(file_name: &str) -> String {
format!("prob-{}.sol", &file_name[5..8])
}
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
struct Point {
x: usize,
y: usize,
}
impl Point {
fn new(x: usize, y: usize) -> Point {
Point { x, y }
}

fn move_with(&self, command: Command) -> Option<Point> {
let (x, y) = (self.x, self.y);
match command {
Command::MoveUp => Some(Point::new(x, y + 1)),
Command::MoveDown => match self.y {
0 => None,
_ => Some(Point::new(x, y - 1)),
},
Command::MoveRight => Some(Point::new(x + 1, y)),
Command::MoveLeft => match self.x {
0 => None,
_ => Some(Point::new(x - 1, y)),
},
_ => Some(*self),
}
}
}

#[derive(Debug, Clone)]
enum BoosterType {
NewHand,
FastMove,
Drill,
Teleports,
Unknown,
}

type Booster = (BoosterType, Point);

#[derive(Debug, Clone)]
struct Map(Vec<Point>);

enum Direction {
Verticle,
Horizontal,
}

impl Map {
fn iter_lines(&self) -> Vec<(Direction, Point, Point)> {
let mut iter = self.0.iter().cloned().cycle().peekable();
let mut res = Vec::new();
for _ in 0..self.0.len() {
let cur = iter.next().unwrap();
let next = *iter.peek().unwrap();
if cur.x == next.x {
res.push((Direction::Verticle, cur, next));
} else if cur.y == next.y {
res.push((Direction::Horizontal, cur, next));
} else {
unreachable!();
}
}
res
}

fn enumerate_points(&self) -> Vec<Point> {
let g_min_x = self.0.iter().map(|p| p.x).min().unwrap();
let g_max_x = self.0.iter().map(|p| p.x).max().unwrap();
let mut cross_y_map = HashMap::new();
for (dir, p, q) in self.iter_lines() {
if let Horizontal = dir {
let min_x = cmp::min(p.x, q.x);
let max_x = cmp::max(p.x, q.x);
for x in min_x..max_x {
cross_y_map.entry(x).or_insert_with(|| Vec::new()).push(p.y);
}
}
}
let mut res = Vec::new();
for x in g_min_x..g_max_x {
let v = cross_y_map.get_mut(&x).unwrap();
assert!(v.len() % 2 == 0);
v.sort();
let mut iter = v.iter();
while let Some(lb) = iter.next() {
let ub = iter.next().unwrap();
for y in *lb..*ub {
res.push(Point::new(x, y));
}
}
}
res
}
}

#[derive(Debug, Clone)]
struct Input {
map: Map,
initial: Point,
obstacles: Vec<Map>,
boosters: Vec<Booster>,
}

#[derive(Debug, Clone, Copy)]
enum Command {
MoveUp,
MoveDown,
MoveLeft,
MoveRight,
Noop,
TurnRight,
TurnLeft,
}

fn skip(iter: &mut Peekable<Chars>, expected: char) {
let c = iter.next().unwrap();
assert!(c == expected);
}

fn skip_or_empty(iter: &mut Peekable<Chars>, expected: char) {
if let Some(c) = iter.next() {
assert!(c == expected);
}
}

fn read_point(iter: &mut Peekable<Chars>) -> Point {
skip(iter, '(');
let mut x = 0;
loop {
let c = iter.next().unwrap();
if c.is_digit(10) {
x = x * 10 + (c as u8 - '0' as u8);
} else {
assert!(c == ',');
break;
}
}
let mut y = 0;
loop {
let c = iter.next().unwrap();
if c.is_digit(10) {
y = y * 10 + (c as u8 - '0' as u8);
} else {
assert!(c == ')');
break;
}
}
Point::new(x as usize, y as usize)
}

fn read_map_internal(mut iter: &mut Peekable<Chars>) -> (Map, char) {
let mut points = Vec::new();
points.push(read_point(&mut iter));
loop {
let c = iter.next().unwrap();
if c != ',' {
return (Map(points), c);
}
points.push(read_point(&mut iter));
}
}

fn read_map(mut iter: &mut Peekable<Chars>) -> Map {
let (m, c) = read_map_internal(&mut iter);
assert!(c == '#');
m
}

fn read_initial(mut iter: &mut Peekable<Chars>) -> Point {
let p = read_point(&mut iter);
skip(iter, '#');
p
}

fn read_obstacles(mut iter: &mut Peekable<Chars>) -> Vec<Map> {
let mut res = Vec::new();
if *iter.peek().unwrap() == '#' {
iter.next();
return res;
}

loop {
let (m, c) = read_map_internal(&mut iter);
res.push(m);
if c == '#' {
break;
}
assert!(c == ';');
}
res
}

fn read_boosters(mut iter: &mut Peekable<Chars>) -> Vec<Booster> {
let mut res = Vec::new();
while let Some(c) = iter.next() {
let booster_type = match c {
'B' => BoosterType::NewHand,
'F' => BoosterType::FastMove,
'L' => BoosterType::Drill,
'X' => BoosterType::Unknown,
'R' => BoosterType::Teleports,
_ => panic!("unknown type {}", c),
};
let point = read_point(&mut iter);
res.push((booster_type, point));
skip_or_empty(&mut iter, ';');
}
res
}

fn read_input(s: &str) -> Input {
let mut iter = s.chars().peekable();
let map = read_map(&mut iter);
let initial = read_initial(&mut iter);
let obstacles = read_obstacles(&mut iter);
let boosters = read_boosters(&mut iter);
Input {
map,
initial,
obstacles,
boosters,
}
}

struct ScoreInfo {
width: usize,
@@ -267,10 +23,11 @@ impl ScoreInfo {

fn debug(&self) -> String {
format!(
"1000.0 * {:5.2} * {:4.2} = {:8.2}",
"1000.0 * {:5.2} * {:4.2} = {:8.2} ({:6} steps)",
self.log_wh(),
self.ratio(),
self.score()
self.score(),
self.team_time
)
}

@@ -279,8 +36,8 @@ impl ScoreInfo {
}
}

fn score_small(input: Input, output_len: usize) -> ScoreInfo {
let map_points = input.map.enumerate_points();
fn score_small(task: Task, output_len: usize) -> ScoreInfo {
let map_points = task.map.enumerate_points();

let width = map_points.iter().map(|p| p.x).max().unwrap() + 1;
let height = map_points.iter().map(|p| p.y).max().unwrap() + 1;
@@ -294,7 +51,7 @@ fn score_small(input: Input, output_len: usize) -> ScoreInfo {
remaining += 1;
}

for o in &input.obstacles {
for o in &task.obstacles {
for p in o.enumerate_points().iter() {
if p.y < height && p.x < width && valid[p.y][p.x] {
valid[p.y][p.x] = false;
@@ -330,21 +87,19 @@ fn main() {
.get_matches();
let input_root = matches.value_of("input").expect("no input specified");
let output_root = matches.value_of("output").expect("no output specified");
let files = find_files(&input_root);
let inputs = read_all_inputs(input_root);

let mut sum_scores = 0.0;
for f in files.iter() {
let input_path = format!("{}/{}", input_root, f);
let mut input_file = File::open(&input_path).unwrap();
let output_path = format!("{}/{}", output_root, output_file_name(&f));
let mut output_file = File::open(&output_path).unwrap();
let mut input_str = String::new();
input_file.read_to_string(&mut input_str);
let mut output_str = String::new();
output_file.read_to_string(&mut output_str);
let output_len = output_str.trim_end().len();
let score_info = score_small(read_input(&input_str), output_len);
eprintln!("{}: {}", f, score_info.debug());
for input in inputs {
let output_len = {
let output_path = format!("{}/{}", output_root, input.output_file_name());
let mut output_file = File::open(&output_path).unwrap();
let mut output_str = String::new();
output_file.read_to_string(&mut output_str).unwrap();
output_str.trim_end().len()
};
let score_info = score_small(input.task, output_len);
eprintln!("{}: {}", input.id, score_info.debug());
sum_scores += score_info.score();
}
println!("output: {}", output_root);
@@ -0,0 +1,3 @@
pub mod models;
pub mod parse;
pub mod solve;

0 comments on commit 82502ba

Please sign in to comment.
You can’t perform that action at this time.