From a536dbd8d9ea8521489085cbafd19c4d9d58a2ed Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Thu, 19 Dec 2024 10:23:50 -0800 Subject: [PATCH] Solution for advent of code day 3. (#4713) --- examples/advent2024/BUILD | 16 +++++++++ examples/advent2024/day3_common.carbon | 45 ++++++++++++++++++++++++++ examples/advent2024/day3_part1.carbon | 24 ++++++++++++++ examples/advent2024/day3_part2.carbon | 31 ++++++++++++++++++ examples/advent2024/io_utils.carbon | 35 +++++++++++--------- 5 files changed, 135 insertions(+), 16 deletions(-) create mode 100644 examples/advent2024/day3_common.carbon create mode 100644 examples/advent2024/day3_part1.carbon create mode 100644 examples/advent2024/day3_part2.carbon diff --git a/examples/advent2024/BUILD b/examples/advent2024/BUILD index b1edc7021fa7..6e709b913042 100644 --- a/examples/advent2024/BUILD +++ b/examples/advent2024/BUILD @@ -40,3 +40,19 @@ carbon_binary( "day2_part2.carbon", ] + utils, ) + +carbon_binary( + name = "day3_part1", + srcs = [ + "day3_common.carbon", + "day3_part1.carbon", + ] + utils, +) + +carbon_binary( + name = "day3_part2", + srcs = [ + "day3_common.carbon", + "day3_part2.carbon", + ] + utils, +) diff --git a/examples/advent2024/day3_common.carbon b/examples/advent2024/day3_common.carbon new file mode 100644 index 000000000000..9d54ba54137d --- /dev/null +++ b/examples/advent2024/day3_common.carbon @@ -0,0 +1,45 @@ +// 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 + +library "day3_common"; + +import library "io_utils"; + +// Reads "mul(a,b)", and returns (true, a, b). +// On error, stops before the first invalid character and returns (false, 0, 0). +// TODO: -> Optional((i32, i32)) +fn ReadMul() -> (bool, i32, i32) { + var a: i32; + var b: i32; + if (ConsumeChar(0x6D) and ConsumeChar(0x75) and ConsumeChar(0x6C) and + ConsumeChar(0x28) and ReadInt(&a) and ConsumeChar(0x2C) and + ReadInt(&b) and ConsumeChar(0x29)) { + return (true, a, b); + } + return (false, 0, 0); +} + +// Reads "do()" or "don't()", and returns (true, was_do). +// On error, stops before the first invalid character and returns (false, false). +fn ReadDoOrDont() -> (bool, bool) { + // "do" + if (not ConsumeChar(0x64) or not ConsumeChar(0x6F)) { + return (false, false); + } + + var do: bool = true; + // "n't" + if (ConsumeChar(0x6E)) { + if (not ConsumeChar(0x27) or not ConsumeChar(0x74)) { + return (false, false); + } + do = false; + } + + // "()" + if (not ConsumeChar(0x28) or not ConsumeChar(0x29)) { + return (false, false); + } + return (true, do); +} diff --git a/examples/advent2024/day3_part1.carbon b/examples/advent2024/day3_part1.carbon new file mode 100644 index 000000000000..c6b9dda6188d --- /dev/null +++ b/examples/advent2024/day3_part1.carbon @@ -0,0 +1,24 @@ +// 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 + +import Core library "io"; + +import library "day3_common"; +import library "io_utils"; + +fn Run() { + var total: i32 = 0; + while (PeekChar() != Core.EOF()) { + if (PeekChar() == 0x6D) { + // TODO: Use `if let` when available. + let result: (bool, i32, i32) = ReadMul(); + if (result.0) { + total += result.1 * result.2; + } + } else { + ReadChar(); + } + } + Core.Print(total); +} diff --git a/examples/advent2024/day3_part2.carbon b/examples/advent2024/day3_part2.carbon new file mode 100644 index 000000000000..fd837667d1e9 --- /dev/null +++ b/examples/advent2024/day3_part2.carbon @@ -0,0 +1,31 @@ +// 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 + +import Core library "io"; + +import library "day3_common"; +import library "io_utils"; + +fn Run() { + var total: i32 = 0; + var enabled: bool = true; + while (PeekChar() != Core.EOF()) { + if (PeekChar() == 0x6D) { + // TODO: Use `if let` when available. + let result: (bool, i32, i32) = ReadMul(); + if (result.0 and enabled) { + total += result.1 * result.2; + } + } else if (PeekChar() == 0x64) { + // TODO: Use `if let` when available. + let result: (bool, bool) = ReadDoOrDont(); + if (result.0) { + enabled = result.1; + } + } else { + ReadChar(); + } + } + Core.Print(total); +} diff --git a/examples/advent2024/io_utils.carbon b/examples/advent2024/io_utils.carbon index e8cfe371a9be..0a84d10aa872 100644 --- a/examples/advent2024/io_utils.carbon +++ b/examples/advent2024/io_utils.carbon @@ -44,30 +44,33 @@ fn ReadInt(p: i32*) -> bool { return read_any_digits; } +fn PeekChar() -> i32 { + var next: i32 = ReadChar(); + UnreadChar(next); + return next; +} + +fn ConsumeChar(c: i32) -> bool { + var next: i32 = ReadChar(); + if (next != c) { + UnreadChar(next); + return false; + } + return true; +} + fn SkipSpaces() -> bool { var skipped_any_spaces: bool = false; - while (true) { - var c: i32 = ReadChar(); - if (c != 0x20) { - UnreadChar(c); - break; - } + while (ConsumeChar(0x20)) { skipped_any_spaces = true; } return skipped_any_spaces; } fn SkipNewline() -> bool { - var c: i32 = ReadChar(); // Optional carriage return. - if (c == 0x0D) { - c = ReadChar(); - } + ConsumeChar(0x0D); // Newline. - if (c == 0x0A) { - return true; - } - // TODO: Unread the CR? - UnreadChar(c); - return false; + // TODO: Unread the CR if it was present? + return ConsumeChar(0x0A); }