-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathday13.rs
More file actions
124 lines (107 loc) · 3.61 KB
/
day13.rs
File metadata and controls
124 lines (107 loc) · 3.61 KB
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
122
123
124
//! # Care Package
//!
//! Keeps track of the `x` position of both the ball and paddle then uses the [`signum`] function
//! to provide input to the joystick that tracks the ball.
//!
//! Just for fun this solution will play an animated game in the console if
//! "--features frivolity" is enabled.
//!
//! [`signum`]: i64::signum
use super::intcode::*;
use crate::util::parse::*;
pub fn parse(input: &str) -> Vec<i64> {
input.iter_signed().collect()
}
pub fn part1(input: &[i64]) -> usize {
let mut computer = Computer::new(input);
let mut blocks = 0;
while let [_, _, State::Output(t)] = [computer.run(), computer.run(), computer.run()] {
if t == 2 {
blocks += 1;
}
}
blocks
}
pub fn part2(input: &[i64]) -> i64 {
let mut modified = input.to_vec();
modified[0] = 2;
let mut computer = Computer::new(&modified);
let mut tiles = Vec::with_capacity(1_000);
let mut stride = 0;
let mut score = 0;
let mut blocks = score;
let mut ball: i64 = 0;
let mut paddle: i64 = 0;
loop {
let x = match computer.run() {
State::Input => {
// Always track the ball.
let delta = (ball - paddle).signum();
computer.input(delta);
continue;
}
State::Output(x) => x,
State::Halted => unreachable!(),
};
let State::Output(y) = computer.run() else { unreachable!() };
let State::Output(t) = computer.run() else { unreachable!() };
if x < 0 {
score = t;
if blocks == 0 {
break score;
}
} else {
stride = stride.max(x + 1);
let index = (stride * y + x) as usize;
if index >= tiles.len() {
tiles.resize(index + 1, 0);
}
match t {
0 if tiles[index] == 2 => blocks -= 1,
2 if tiles[index] != 2 => blocks += 1,
3 => paddle = x,
4 => ball = x,
_ => (),
}
tiles[index] = t;
}
// Non-essential but hilarious. Enable "frivolity" feature then run program in a
// command line console to observe an animated game of breakout.
draw(&tiles, stride, score, blocks);
}
}
#[cfg(not(feature = "frivolity"))]
fn draw(_tiles: &[i64], _stride: i64, _score: i64, _blocks: i64) {}
#[cfg(feature = "frivolity")]
fn draw(tiles: &[i64], stride: i64, score: i64, blocks: i64) {
use crate::util::ansi::*;
use std::fmt::Write as _;
use std::thread::sleep;
use std::time::Duration;
// Wait until the initial screen is complete.
let paddle = tiles.iter().rposition(|&t| t == 3).unwrap_or(tiles.len());
if tiles[paddle..].iter().filter(|&&t| t == 1).count() < 3 {
return;
}
let s = &mut String::new();
let _ = writeln!(s, "{WHITE}{BOLD}Blocks: {blocks}\tScore: {score} {RESET}");
let mut y = 0;
while stride * y < tiles.len() as i64 {
for x in 0..stride {
let index = (stride * y + x) as usize;
let _unused = match tiles[index] {
0 => write!(s, " "),
1 if y == 0 => write!(s, "{GREEN}_{RESET}"),
1 => write!(s, "{GREEN}|{RESET}"),
2 => write!(s, "{BLUE}#{RESET}"),
3 => write!(s, "{WHITE}{BOLD}={RESET}"),
4 => write!(s, "{YELLOW}{BOLD}o{RESET}"),
_ => unreachable!(),
};
}
s.push('\n');
y += 1;
}
println!("{HOME}{CLEAR}{s}");
sleep(Duration::from_millis(20));
}