mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:00:11 +01:00
Add advent of code 2024 day 14 and day 15 part 1 solutions (#6597)
I've had these kicking around for a year but never got around to pushing them. They seem to cover a few things that previous examples didn't, so I think we may as well include them. --------- Co-authored-by: Carbon Infra Bot <carbon-external-infra@google.com>
This commit is contained in:
co-authored by
Carbon Infra Bot
parent
32aa7cb1fa
commit
7f0f402f95
@@ -11,19 +11,19 @@ utils = [
|
||||
|
||||
# A list of examples that should be excluded because they don't build any more.
|
||||
# For example, to exclude day3_part2, use:
|
||||
# excluded = [(3, 2)]
|
||||
# excluded = ["day3_part2.carbon"]
|
||||
excluded = []
|
||||
|
||||
# Produce a binary "dayX_partY" for each matching `.carbon` file.
|
||||
# Produce a binary `dayX_partY` for each matching `.carbon` file. Each binary
|
||||
# depends on `dayX_partY.carbon` and `dayX_common.carbon`.
|
||||
[
|
||||
carbon_binary(
|
||||
name = "day{0}_part{1}".format(day, part),
|
||||
name = carbon_file.removesuffix(".carbon"),
|
||||
srcs = [
|
||||
"day{0}_common.carbon".format(day),
|
||||
"day{0}_part{1}.carbon".format(day, part),
|
||||
carbon_file,
|
||||
carbon_file.rsplit("_", 1)[0] + "_common.carbon",
|
||||
] + utils,
|
||||
)
|
||||
for day in range(1, 14)
|
||||
for part in range(1, 3)
|
||||
if (day, part) not in excluded
|
||||
for carbon_file in glob(["day*_part*.carbon"])
|
||||
if carbon_file not in excluded
|
||||
]
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// https://adventofcode.com/2024/day/14
|
||||
|
||||
library "day14_common";
|
||||
|
||||
import Core library "io";
|
||||
import library "io_utils";
|
||||
|
||||
fn ReadXY(xy: (i32, i32)*) -> bool {
|
||||
return ReadInt(ref xy->0) and ConsumeChar(',') and ReadInt(ref xy->1);
|
||||
}
|
||||
|
||||
fn SkipString(s: str) -> bool {
|
||||
return SkipNChars(s.Size() as i32);
|
||||
}
|
||||
|
||||
fn Mod(a: i32, d: i32) -> i32 {
|
||||
let rem: i32 = a % d;
|
||||
return if rem < 0 then rem + d else rem;
|
||||
}
|
||||
|
||||
class Robot {
|
||||
fn Read() -> Robot {
|
||||
returned var me: Robot;
|
||||
SkipString("p=");
|
||||
ReadXY(&me.p);
|
||||
SkipString(" v=");
|
||||
ReadXY(&me.v);
|
||||
SkipNewline();
|
||||
return var;
|
||||
}
|
||||
|
||||
fn Pos[self: Self](t: i32) -> (i32, i32) {
|
||||
return (Mod((self.p.0 + self.v.0 * Mod(t, 101)), 101),
|
||||
Mod((self.p.1 + self.v.1 * Mod(t, 103)), 103));
|
||||
}
|
||||
|
||||
impl as Core.Copy {
|
||||
fn Op[self: Self]() -> Self {
|
||||
return {.p = self.p, .v = self.v};
|
||||
}
|
||||
}
|
||||
|
||||
var p: (i32, i32);
|
||||
var v: (i32, i32);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// https://adventofcode.com/2024/day/14
|
||||
|
||||
import Core library "io";
|
||||
|
||||
import library "day14_common";
|
||||
import library "io_utils";
|
||||
|
||||
fn Run() {
|
||||
var q: array(array(i32, 3), 3) = ((0,0,0), (0,0,0), (0,0,0));
|
||||
while (PeekChar() != CharOrEOF.EOF()) {
|
||||
var r: Robot = Robot.Read();
|
||||
let xy: (i32, i32) = r.Pos(100);
|
||||
++q[if xy.0 < 50 then 0 else if xy.0 > 50 then 2 else 1]
|
||||
[if xy.1 < 51 then 0 else if xy.1 > 51 then 2 else 1];
|
||||
}
|
||||
Core.Print(q[0][0] * q[0][2] * q[2][0] * q[2][2]);
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// https://adventofcode.com/2024/day/14
|
||||
|
||||
import Core library "io";
|
||||
import Core library "range";
|
||||
|
||||
import library "day14_common";
|
||||
import library "io_utils";
|
||||
|
||||
// Returns m and n so that am + bn = gcd.
|
||||
fn Euclid(a: i32, b: i32) -> {.m: i32, .n: i32, .gcd: i32} {
|
||||
if (a < b) {
|
||||
let reverse: {.m: i32, .n: i32, .gcd: i32} = Euclid(b, a);
|
||||
return {.m = reverse.n, .n = reverse.m, .gcd = reverse.gcd};
|
||||
}
|
||||
if (b == 0) {
|
||||
return {.m = 1, .n = 0, .gcd = a};
|
||||
}
|
||||
let next: {.m: i32, .n: i32, .gcd: i32} = Euclid(b, a % b);
|
||||
return {.m = next.n, .n = next.m - next.n * (a / b), .gcd = next.gcd};
|
||||
}
|
||||
|
||||
// Uses Chinese remainder theorem to find the least positive x that solves
|
||||
// x = a mod p
|
||||
// x = b mod q
|
||||
// modulo pq / gcd(p,q), if one exists (if a = b mod gcd(p,q)).
|
||||
fn CRT(a: i32, b: i32, p: i32, q: i32) -> i32 {
|
||||
let e: {.m: i32, .n: i32, .gcd: i32} = Euclid(p, q);
|
||||
let x: i32 = a * (q / e.gcd) * e.n + b * (p / e.gcd) * e.m;
|
||||
return Mod(x, p * (q / e.gcd));
|
||||
}
|
||||
|
||||
fn PrintState(r: array(Robot, 500), t: i32) {
|
||||
var display: array(array(char, 101), 103);
|
||||
|
||||
for (y: i32 in Core.Range(103)) {
|
||||
for (x: i32 in Core.Range(101)) {
|
||||
display[y][x] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
for (ri: Robot in r) {
|
||||
let xy: (i32, i32) = ri.Pos(t);
|
||||
display[xy.1][xy.0] = '#';
|
||||
}
|
||||
|
||||
for (y: i32 in Core.Range(103)) {
|
||||
for (x: i32 in Core.Range(101)) {
|
||||
Core.PrintChar(display[y][x]);
|
||||
}
|
||||
Core.PrintChar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
fn Run() {
|
||||
var r: array(Robot, 500);
|
||||
for (i: i32 in Core.Range(500)) {
|
||||
r[i] = Robot.Read();
|
||||
}
|
||||
|
||||
let first_match_x: i32 = 28;
|
||||
let first_match_y: i32 = 84;
|
||||
|
||||
var t: i32 = CRT(first_match_x, first_match_y, 101, 103);
|
||||
Core.Print(t);
|
||||
PrintState(r, t);
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// https://adventofcode.com/2024/day/15
|
||||
|
||||
library "day15_common";
|
||||
|
||||
import Core library "io";
|
||||
import library "io_utils";
|
||||
|
||||
// TODO: Use a choice type.
|
||||
class Square {
|
||||
adapt char;
|
||||
|
||||
impl as Core.Copy {
|
||||
fn Op[self: Self]() -> Self {
|
||||
return (self as char).(Core.Copy.Op)() as Self;
|
||||
}
|
||||
}
|
||||
impl as Core.EqWith(Square) {
|
||||
fn Equal[self: Self](other: Self) -> bool {
|
||||
// TODO: Use a `char` comparison when it's supported.
|
||||
return (self as u8) == (other as u8);
|
||||
}
|
||||
fn NotEqual[self: Self](other: Self) -> bool {
|
||||
// TODO: Use a `char` comparison when it's supported.
|
||||
return (self as u8) != (other as u8);
|
||||
}
|
||||
}
|
||||
|
||||
fn Make(c: CharOrEOF) -> Square {
|
||||
// TODO: Use `match`.
|
||||
if (c == '#') { return ('#' as char) as Square; }
|
||||
if (c == 'O') { return ('O' as char) as Square; }
|
||||
if (c == '.') { return ('.' as char) as Square; }
|
||||
if (c == '@') { return ('@' as char) as Square; }
|
||||
return ('!' as char) as Square;
|
||||
}
|
||||
}
|
||||
|
||||
let Wall: Square = ('#' as char) as Square;
|
||||
let Box: Square = ('O' as char) as Square;
|
||||
let Empty: Square = ('.' as char) as Square;
|
||||
let Robot: Square = ('@' as char) as Square;
|
||||
|
||||
class Grid {
|
||||
fn Read() -> Grid {
|
||||
returned var me: Grid;
|
||||
var y: i32 = 0;
|
||||
while (y < 50) {
|
||||
var x: i32 = 0;
|
||||
while (x < 50) {
|
||||
me.data[x][y] = Square.Make(ReadChar());
|
||||
if (me.data[x][y] == Robot) {
|
||||
me.robot = (x, y);
|
||||
}
|
||||
++x;
|
||||
}
|
||||
SkipNewline();
|
||||
++y;
|
||||
}
|
||||
return var;
|
||||
}
|
||||
|
||||
fn Move[ref self: Self](d: (i32, i32)) {
|
||||
var distance: i32 = 1;
|
||||
while (self.data[self.robot.0 + distance * d.0][self.robot.1 + distance * d.1] == Box) {
|
||||
++distance;
|
||||
}
|
||||
if (self.data[self.robot.0 + distance * d.0][self.robot.1 + distance * d.1] == Empty) {
|
||||
self.data[self.robot.0][self.robot.1] = Empty;
|
||||
self.data[self.robot.0 + distance * d.0][self.robot.1 + distance * d.1] = Box;
|
||||
self.data[self.robot.0 + d.0][self.robot.1 + d.1] = Robot;
|
||||
self.robot.0 += d.0;
|
||||
self.robot.1 += d.1;
|
||||
}
|
||||
}
|
||||
|
||||
fn Print[self: Self]() {
|
||||
var y: i32 = 0;
|
||||
while (y < 50) {
|
||||
var x: i32 = 0;
|
||||
while (x < 50) {
|
||||
Core.PrintChar(self.data[x][y] as char);
|
||||
++x;
|
||||
}
|
||||
Core.PrintChar('\n');
|
||||
++y;
|
||||
}
|
||||
Core.PrintChar('\n');
|
||||
}
|
||||
|
||||
fn Signature[self: Self]() -> i32 {
|
||||
var s: i32 = 0;
|
||||
var y: i32 = 0;
|
||||
while (y < 50) {
|
||||
var x: i32 = 0;
|
||||
while (x < 50) {
|
||||
if (self.data[x][y] == Box) {
|
||||
s += y * 100 + x;
|
||||
}
|
||||
++x;
|
||||
}
|
||||
++y;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
var data: array(array(Square, 50), 50);
|
||||
var robot: (i32, i32);
|
||||
}
|
||||
|
||||
fn ReadAndExecuteActions(ref g: Grid) {
|
||||
while (true) {
|
||||
var m: CharOrEOF = ReadChar();
|
||||
// To watch the progress, uncomment the following:
|
||||
// g.Print();
|
||||
// Core.PrintChar(((m as i32) as u8) as char);
|
||||
// Core.PrintChar('\n');
|
||||
// TODO: Use `match` once it's available.
|
||||
if (m == '^') {
|
||||
g.Move((0, -1));
|
||||
} else if (m == '<') {
|
||||
g.Move((-1, 0));
|
||||
} else if (m == '>') {
|
||||
g.Move((1, 0));
|
||||
} else if (m == 'v') {
|
||||
g.Move((0, 1));
|
||||
} else if (m == CharOrEOF.EOF()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
||||
// Exceptions. See /LICENSE for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// https://adventofcode.com/2024/day/15
|
||||
|
||||
import Core library "io";
|
||||
|
||||
import library "day15_common";
|
||||
|
||||
fn Run() {
|
||||
var g: Grid = Grid.Read();
|
||||
ReadAndExecuteActions(ref g);
|
||||
Core.Print(g.Signature());
|
||||
}
|
||||
@@ -90,8 +90,24 @@ fn UnreadChar(c: CharOrEOF) {
|
||||
unread_char = Core.Optional(CharOrEOF).Some(c);
|
||||
}
|
||||
|
||||
fn PeekChar() -> CharOrEOF {
|
||||
var next: CharOrEOF = ReadChar();
|
||||
UnreadChar(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
fn ConsumeChar(c: char) -> bool {
|
||||
var next: CharOrEOF = ReadChar();
|
||||
if (next != c) {
|
||||
UnreadChar(next);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn ReadInt[N:! Core.IntLiteral()](ref p: Core.Int(N)) -> bool {
|
||||
var read_any_digits: bool = false;
|
||||
let negative: bool = ConsumeChar('-');
|
||||
// TODO: `p = 0;` crashes the toolchain, see
|
||||
// https://github.com/carbon-language/carbon-lang/issues/6500.
|
||||
p = (0 as i32) as Core.Int(N);
|
||||
@@ -108,6 +124,12 @@ fn ReadInt[N:! Core.IntLiteral()](ref p: Core.Int(N)) -> bool {
|
||||
p += (c - '0') as Core.Int(N);
|
||||
read_any_digits = true;
|
||||
}
|
||||
if (negative) {
|
||||
p = -p;
|
||||
if (not read_any_digits) {
|
||||
UnreadChar('-');
|
||||
}
|
||||
}
|
||||
return read_any_digits;
|
||||
}
|
||||
|
||||
@@ -135,21 +157,6 @@ fn PrintInt[N:! Core.IntLiteral()](n_val: Core.Int(N)) {
|
||||
Core.PrintChar('\n');
|
||||
}
|
||||
|
||||
fn PeekChar() -> CharOrEOF {
|
||||
var next: CharOrEOF = ReadChar();
|
||||
UnreadChar(next);
|
||||
return next;
|
||||
}
|
||||
|
||||
fn ConsumeChar(c: char) -> bool {
|
||||
var next: CharOrEOF = ReadChar();
|
||||
if (next != c) {
|
||||
UnreadChar(next);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn SkipSpaces() -> bool {
|
||||
var skipped_any_spaces: bool = false;
|
||||
while (ConsumeChar(' ')) {
|
||||
|
||||
Reference in New Issue
Block a user