summaryrefslogtreecommitdiffstats
path: root/day10/src/main.rs
blob: 8674c8f7b1e793fe0b2e65498097446f320ac891 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use std::env;
use std::io::BufReader;
use std::io::BufRead;
use std::fs::File;
use std::process;
use std::io::{stdin,stdout,Write};

#[macro_use] extern crate text_io;

struct Point {
  x: i64,
  y: i64,
  vx: i64,
  vy: i64
}

struct BoundingBox {
  x: i64,
  y: i64,
  w: i64,
  h: i64
}

static WIDTH: i64 = 200;
static HEIGHT: i64 = 20;

fn visualize(points: &Vec<Point>, bb: &BoundingBox) {
  let mut grid: Vec<Vec<char>> = vec![vec!['.'; bb.w as usize]; bb.h as usize];
  for point in points {
    let (xi, yi) = transform(point, bb);
    grid[yi][xi] = '#';
  }

  for row in &grid {
    for elem in row {
      print!("{}", elem);
    }
    print!("\n");
  }
}

fn state(points: &Vec<Point>, time: i64) -> Vec<Point> {
  points.iter().map(|p| Point {
    x: p.x + time * p.vx,
    y: p.y + time * p.vy,
    vx: p.vx,
    vy: p.vy
  }).collect()
}

fn transform(point: &Point, bb: &BoundingBox) -> (usize, usize) {
  let x = point.x - bb.x;
  let y = point.y - bb.y;

  (x as usize, y as usize)
}

fn calc_bounding_box(points: &Vec<Point>) -> BoundingBox {
  let px_min = points.iter().min_by(|&a, &b| a.x.cmp(&b.x)).unwrap().x;
  let px_max = points.iter().max_by(|&a, &b| a.x.cmp(&b.x)).unwrap().x;
  let py_min = points.iter().min_by(|&a, &b| a.y.cmp(&b.y)).unwrap().y;
  let py_max = points.iter().max_by(|&a, &b| a.y.cmp(&b.y)).unwrap().y;

  let pw = px_max - px_min + 1;
  let ph = py_max - py_min + 1;

  let bb = BoundingBox {
    x: px_min,
    y: py_min,
    w: pw,
    h: ph
  };

  bb
}

fn main() {
  let args: Vec<String> = env::args().collect();
  if args.len() != 2 {
    println!("Wrong number of arguments. Provide a file name and worker count.");
    process::exit(1);
  }
  let filename = &args[1];

  println!("Using file {} as input.", filename);
  let f = match File::open(filename) {
    Ok(file) => file,
    Err(e) => {
      println!("Failed to open file {}. {:?}", filename, e);
      process::exit(1);
    }
  };
  let file = BufReader::new(&f);
  let lines: Vec<String> = file.lines()
    .map(|line| line.expect("Could not parse line."))
    .collect();

  let mut init_points: Vec<Point> = Vec::new();
  for line in &lines {
    let ln = line
      .replace("< ", "<")
      .replace("  ", " ");
    let (x, y): (i64, i64);
    let (vx, vy): (i64, i64);
    scan!(ln.bytes() => "position=<{}, {}> velocity=<{}, {}>", x, y, vx, vy);
    init_points.push(Point { x, y, vx, vy });
  }

  let mut time = 0;
  let step = 1;
  // println!("Time: {} s, step: {} s", time, step);
  while time < 20000 {
    let points = state(&init_points, time);
    let bb = calc_bounding_box(&points);
    if bb.w <= WIDTH && bb.h <= HEIGHT {
      println!("Time: {} s", time);
      visualize(&points, &bb);
    }
    time += step;
  }
}