Commit dc8a345
Changed files (14)
2023/go/03/main.go
@@ -2,6 +2,8 @@ package main
import (
"advent2023/internal/aoc"
+ "advent2023/internal/grid"
+
"strconv"
"strings"
"unicode"
@@ -9,13 +11,9 @@ import (
"github.com/google/uuid"
)
-type cord struct {
- x int
- y int
-}
type board struct {
- grid map[cord]uuid.UUID
+ grid map[grid.Coord]uuid.UUID
parts map[uuid.UUID]part
included map[uuid.UUID]part
symbols []symbol
@@ -28,8 +26,8 @@ type part struct {
}
type symbol struct {
+ grid.Coord
repr string
- cord cord
}
type gear struct {
@@ -40,7 +38,7 @@ type gear struct {
func parseBoard(input []string) (b board) {
b = board{
- grid: map[cord]uuid.UUID{},
+ grid: map[grid.Coord]uuid.UUID{},
parts: map[uuid.UUID]part{},
included: map[uuid.UUID]part{},
symbols: []symbol{},
@@ -54,7 +52,7 @@ func parseBoard(input []string) (b board) {
if unicode.IsDigit(col) {
partSB.WriteRune(col)
- b.grid[cord{x, y}] = partID
+ b.grid[grid.Coord{X:x, Y:y}] = partID
// only continue if not at end of row
if x < len(row)-1 {
continue
@@ -78,13 +76,19 @@ func parseBoard(input []string) (b board) {
}
// symbol remaning, store it
- b.symbols = append(b.symbols, symbol{repr: string(col), cord: cord{x, y}})
+ s := symbol{
+ repr: string(col),
+ Coord: grid.Coord{X:x, Y:y},
+ }
+ b.symbols = append(b.symbols, s)
}
}
- for _, s := range b.symbols {
+ // find included numbers via symbols
+ // find gears via "*" symbols
+ for _, s := range b.symbols {
neighbors := map[uuid.UUID]part{}
- for _, c := range s.cord.neighbors() {
+ for _, c := range s.Coord.Neighbors() {
if id, ok := b.grid[c]; ok {
b.included[id] = b.parts[id]
neighbors[id] = b.parts[id]
@@ -104,20 +108,6 @@ func parseBoard(input []string) (b board) {
return b
}
-func (c cord) neighbors() (cords []cord) {
- cords = []cord{
- {c.x - 1, c.y - 1},
- {c.x - 1, c.y},
- {c.x - 1, c.y + 1},
- {c.x, c.y - 1},
- {c.x, c.y + 1},
- {c.x + 1, c.y - 1},
- {c.x + 1, c.y},
- {c.x + 1, c.y + 1},
- }
- return cords
-}
-
func solvePart1(input []string) (solution int) {
b := parseBoard(input)
solution = 0
2023/go/04/main.go
@@ -0,0 +1,21 @@
+package main
+
+import (
+ "advent2023/internal/aoc"
+)
+
+func solvePart1(input []string) (solution int) {
+ return 0
+}
+
+func solvePart2(input []string) (solution int) {
+ return 0
+}
+
+func main() {
+ day := 3
+ aoc.SolveExample(day, aoc.Part1, solvePart1, 0)
+ aoc.SolvePuzzle(day, aoc.Part1, solvePart1, aoc.UnknownExpected)
+ aoc.SolveExample(day, aoc.Part2, solvePart2, 0)
+ aoc.SolvePuzzle(day, aoc.Part2, solvePart2, aoc.UnknownExpected)
+}
2023/go/internal/aoc/aoc.go
@@ -5,11 +5,12 @@ import (
"fmt"
"log"
"os"
+ "time"
)
const (
- example = "e"
- puzzle = "p"
+ Example = InputType("e")
+ Puzzle = InputType("p")
Part1 = Part(1)
Part2 = Part(2)
@@ -47,18 +48,30 @@ type InputType string
type Day int
type Part int
-type solve func([]string) int
+type Solve func([]string) int
+
+type ProblemId struct {
+ Day Day
+ Part Part
+}
type Input struct {
- Day Day
- Part Part
+ ProblemId
+ Solve
Type InputType
- Solve solve
Expected int
}
-func (i Input) Calculate() (err error) {
+func (i Input) String() string {
+ var t string = "Example"
+ if i.Type == Puzzle {
+ t = "Puzzle"
+ }
+ return fmt.Sprintf("Day %02d, Part %d %7s: ", i.Day, i.Part, t)
+}
+
+func (i Input) Calculate() (err error) {
inputFilename := fmt.Sprintf("../input/%02d-%s%d.txt", i.Day, i.Type, i.Part)
input := []string{}
file, err := os.Open(inputFilename)
@@ -88,12 +101,37 @@ func (i Input) Calculate() (err error) {
return nil
}
-func SolveExample(day Day, part Part, fn solve, expected int) {
- fmt.Printf("Day %02d, Part %d Example: ", day, part)
+func EventDay(year int) (day int) {
+
+ start := time.Date(year, time.December, 1, 0, 0, 0, 0, time.UTC)
+ now := time.Now()
+ end := time.Date(year, time.December, 25, 0, 0, 0, 0, time.UTC)
+
+ if now.After(end) {
+ return 25
+ }
+ if now.Before(start) {
+ return 0
+ }
+ return now.Day()
+}
+
+func ReleasedDays(year int) (days []Day) {
+ today := EventDay(year)
+ days = []Day{}
+ for d := 1; d <= today; d++ {
+ days = append(days, Day(d))
+ }
+ return days
+}
+
+func SolveExample(day Day, part Part, fn Solve, expected int) {
i := Input{
- Day: day,
- Part: part,
- Type: example,
+ ProblemId: ProblemId{
+ Day: day,
+ Part: part,
+ },
+ Type: Example,
Solve: fn,
Expected: expected,
}
@@ -103,12 +141,13 @@ func SolveExample(day Day, part Part, fn solve, expected int) {
}
}
-func SolvePuzzle(day Day, part Part, fn solve, expected int) {
- fmt.Printf("Day %02d, Part %d Puzzle: ", day, part)
+func SolvePuzzle(day Day, part Part, fn Solve, expected int) {
i := Input{
- Day: day,
- Part: part,
- Type: puzzle,
+ ProblemId: ProblemId{
+ Day: day,
+ Part: part,
+ },
+ Type: Puzzle,
Solve: fn,
Expected: expected,
}
2023/go/internal/grid/grid.go
@@ -0,0 +1,27 @@
+package grid
+
+// Cartesian
+type Coord struct {
+ X int
+ Y int
+}
+
+// Cartesian coordinates of all adjacent Neighbors
+// Does not take into consideration edges, maximum
+// .....
+// .nnn.
+// .ncn.
+// .nnn.
+// .....
+func (c Coord) Neighbors() []Coord {
+ return []Coord{
+ {X: c.X - 1, Y: c.Y - 1},
+ {X: c.X - 1, Y: c.Y},
+ {X: c.X - 1, Y: c.Y + 1},
+ {X: c.X, Y: c.Y - 1},
+ {X: c.X, Y: c.Y + 1},
+ {X: c.X + 1, Y: c.Y - 1},
+ {X: c.X + 1, Y: c.Y},
+ {X: c.X + 1, Y: c.Y + 1},
+ }
+}
2023/go/internal/solutions/01.go
@@ -0,0 +1,78 @@
+package solutions
+
+import (
+ //"advent2023/internal/aoc"
+ "log"
+ "strconv"
+ "strings"
+)
+
+func Day1Part1(input []string) (solution int) {
+ sum := 0
+ for _, line := range input {
+ first := ""
+ last := ""
+ for _, c := range line {
+ if _, err := strconv.Atoi(string(c)); err == nil {
+ if first == "" {
+ first = string(c)
+ }
+ last = string(c)
+ }
+ }
+ value, err := strconv.Atoi(strings.Join([]string{first, last}, ""))
+ if err != nil {
+ log.Fatal(err)
+ }
+ sum = sum + value
+ }
+ return sum
+}
+
+var digits map[string]string = map[string]string{
+ "one": "1",
+ "1": "1",
+ "two": "2",
+ "2": "2",
+ "three": "3",
+ "3": "3",
+ "four": "4",
+ "4": "4",
+ "five": "5",
+ "5": "5",
+ "six": "6",
+ "6": "6",
+ "seven": "7",
+ "7": "7",
+ "eight": "8",
+ "8": "8",
+ "nine": "9",
+ "9": "9",
+}
+
+type digitIndex struct {
+ digit string
+ index int
+}
+
+func Day1Part2(input []string) (solution int) {
+ sum := 0
+ for _, line := range input {
+ first := digitIndex{digit: "", index: 5000}
+ last := digitIndex{digit: "", index: -1}
+ for k := range digits {
+ f := strings.Index(line, k)
+ if f != -1 && f < first.index {
+ first = digitIndex{digit: k, index: f}
+ }
+ l := strings.LastIndex(line, k)
+ if l != -1 && l > last.index {
+ last = digitIndex{digit: k, index: l}
+ }
+ }
+ joinedDigits := strings.Join([]string{digits[first.digit], digits[last.digit]}, "")
+ value, _ := strconv.Atoi(joinedDigits)
+ sum = sum + value
+ }
+ return sum
+}
2023/go/internal/solutions/main.go
@@ -0,0 +1,11 @@
+package solutions
+
+import "advent2023/internal/aoc"
+
+var Fn map[aoc.ProblemId]aoc.Solve
+
+func init() {
+ Fn = map[aoc.ProblemId]aoc.Solve{}
+ Fn[aoc.ProblemId{Day: aoc.Day1, Part: aoc.Part1}] = Day1Part1
+ Fn[aoc.ProblemId{Day: aoc.Day1, Part: aoc.Part2}] = Day1Part2
+}
2023/go/template/main.go
@@ -13,7 +13,7 @@ func solvePart2(input []string) (solution int) {
}
func main() {
- day := 3
+ day := aoc.Day1
aoc.SolveExample(day, aoc.Part1, solvePart1, 0)
aoc.SolvePuzzle(day, aoc.Part1, solvePart1, aoc.UnknownExpected)
aoc.SolveExample(day, aoc.Part2, solvePart2, 0)
2023/go/Justfile
@@ -14,6 +14,9 @@ run-all: clean build-all
bin/02
bin/03
+template day:
+ cp -r template {{day}}
+
build day:
go build -o bin/{{day}} {{day}}/main.go
2023/go/main.go
@@ -0,0 +1,37 @@
+package main
+
+import (
+ "advent2023/internal/aoc"
+ "advent2023/internal/solutions"
+ "fmt"
+)
+
+func main() {
+ for _, d := range aoc.ReleasedDays(2023) {
+
+ parts := []aoc.Part{aoc.Part1, aoc.Part2}
+ types := []aoc.InputType{aoc.Example, aoc.Puzzle}
+
+ for _, p := range parts {
+ for _, t := range types {
+ id := aoc.ProblemId{
+ Day: d,
+ Part: p,
+ }
+ i := aoc.Input{
+ ProblemId: id,
+ Type: t,
+ //Expected: expected,
+ }
+ var ok bool
+ i.Solve, ok = solutions.Fn[id]
+ if !ok {
+ fmt.Printf("%s Not implemented\n", i)
+ continue
+ }
+ fmt.Printf("%s", i)
+ _ = i.Calculate()
+ }
+ }
+ }
+}
2023/go/README.md
@@ -0,0 +1,14 @@
+# 2023 Advent of Code - Golang
+
+Run all:
+
+```bash
+just
+```
+
+Run a specific day:
+```bash
+just run 01
+```
+
+
2023/zig/src/01.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+
+pub fn main() !void {
+ const stdout_file = std.io.getStdOut().writer();
+ var bw = std.io.bufferedWriter(stdout_file);
+ const stdout = bw.writer();
+
+ var file = try std.fs.cwd().openFile("../input/01-e1.txt", .{});
+ defer file.close();
+
+ var buf_reader = std.io.bufferedReader(file.reader());
+ var in_stream = buf_reader.reader();
+
+ var buf: [1024]u8 = undefined;
+ while (try in_stream.readUntilDelimiterOrEof(&buf, '\n')) |line| {
+ try stdout.print("{s}\n", .{line});
+ }
+ try bw.flush();
+}
2023/zig/src/buf-iter.zig
@@ -0,0 +1,43 @@
+const std = @import("std");
+
+const ReaderType = std.fs.File.Reader;
+const BufReaderType = std.io.BufferedReader(4096, ReaderType);
+const BufReaderReaderType = BufReaderType.Reader;
+
+pub const ReadByLineIterator = struct {
+ file: std.fs.File,
+ reader: ReaderType,
+ buf_reader: BufReaderType,
+ stream: ?BufReaderReaderType,
+ buf: [4096]u8,
+
+ pub fn next(self: *@This()) !?[]u8 {
+ if (self.stream == null) {
+ self.stream = self.buf_reader.reader();
+ }
+ if (self.stream) |stream| {
+ return stream.readUntilDelimiterOrEof(&self.buf, '\n');
+ }
+ unreachable;
+ }
+
+ pub fn deinit(self: *@This()) void {
+ self.file.close();
+ }
+};
+
+// Iterate over the lines in the file using a buffered reader.
+// Caller is responsible for calling deinit() on returned iterator when done.
+pub fn iterLines(filename: []const u8) !ReadByLineIterator {
+ var file = try std.fs.cwd().openFile(filename, .{});
+ var reader = file.reader();
+ var buf_reader = std.io.bufferedReader(reader);
+
+ return ReadByLineIterator{
+ .file = file,
+ .reader = reader,
+ .buf_reader = buf_reader,
+ .stream = null,
+ .buf = undefined,
+ };
+}
2023/zig/build.zig
@@ -0,0 +1,91 @@
+const std = @import("std");
+
+// Although this function looks imperative, note that its job is to
+// declaratively construct a build graph that will be executed by an external
+// runner.
+pub fn build(b: *std.Build) void {
+ // Standard target options allows the person running `zig build` to choose
+ // what target to build for. Here we do not override the defaults, which
+ // means any target is allowed, and the default is native. Other options
+ // for restricting supported target set are available.
+ const target = b.standardTargetOptions(.{});
+
+ // Standard optimization options allow the person running `zig build` to select
+ // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not
+ // set a preferred release mode, allowing the user to decide how to optimize.
+ const optimize = b.standardOptimizeOption(.{});
+
+ const lib = b.addStaticLibrary(.{
+ .name = "zig-hello",
+ // In this case the main source file is merely a path, however, in more
+ // complicated build scripts, this could be a generated file.
+ .root_source_file = .{ .path = "src/root.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ // This declares intent for the library to be installed into the standard
+ // location when the user invokes the "install" step (the default step when
+ // running `zig build`).
+ b.installArtifact(lib);
+
+ const exe = b.addExecutable(.{
+ .name = "01",
+ .root_source_file = .{ .path = "src/01.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ // This declares intent for the executable to be installed into the
+ // standard location when the user invokes the "install" step (the default
+ // step when running `zig build`).
+ b.installArtifact(exe);
+
+ // This *creates* a Run step in the build graph, to be executed when another
+ // step is evaluated that depends on it. The next line below will establish
+ // such a dependency.
+ const run_cmd = b.addRunArtifact(exe);
+
+ // By making the run step depend on the install step, it will be run from the
+ // installation directory rather than directly from within the cache directory.
+ // This is not necessary, however, if the application depends on other installed
+ // files, this ensures they will be present and in the expected location.
+ run_cmd.step.dependOn(b.getInstallStep());
+
+ // This allows the user to pass arguments to the application in the build
+ // command itself, like this: `zig build run -- arg1 arg2 etc`
+ if (b.args) |args| {
+ run_cmd.addArgs(args);
+ }
+
+ // This creates a build step. It will be visible in the `zig build --help` menu,
+ // and can be selected like this: `zig build run`
+ // This will evaluate the `run` step rather than the default, which is "install".
+ const run_step = b.step("run", "Run the app");
+ run_step.dependOn(&run_cmd.step);
+
+ // Creates a step for unit testing. This only builds the test executable
+ // but does not run it.
+ const lib_unit_tests = b.addTest(.{
+ .root_source_file = .{ .path = "src/root.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);
+
+ const exe_unit_tests = b.addTest(.{
+ .root_source_file = .{ .path = "src/main.zig" },
+ .target = target,
+ .optimize = optimize,
+ });
+
+ const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
+
+ // Similar to creating the run step earlier, this exposes a `test` step to
+ // the `zig build --help` menu, providing a way for the user to request
+ // running the unit tests.
+ const test_step = b.step("test", "Run unit tests");
+ test_step.dependOn(&run_lib_unit_tests.step);
+ test_step.dependOn(&run_exe_unit_tests.step);
+}
2023/zig/build.zig.zon
@@ -0,0 +1,62 @@
+.{
+ .name = "zig-hello",
+ // This is a [Semantic Version](https://semver.org/).
+ // In a future version of Zig it will be used for package deduplication.
+ .version = "0.0.0",
+
+ // This field is optional.
+ // This is currently advisory only; Zig does not yet do anything
+ // with this value.
+ //.minimum_zig_version = "0.11.0",
+
+ // This field is optional.
+ // Each dependency must either provide a `url` and `hash`, or a `path`.
+ // `zig build --fetch` can be used to fetch all dependencies of a package, recursively.
+ // Once all dependencies are fetched, `zig build` no longer requires
+ // Internet connectivity.
+ .dependencies = .{
+ // See `zig fetch --save <url>` for a command-line interface for adding dependencies.
+ //.example = .{
+ // // When updating this field to a new URL, be sure to delete the corresponding
+ // // `hash`, otherwise you are communicating that you expect to find the old hash at
+ // // the new URL.
+ // .url = "https://example.com/foo.tar.gz",
+ //
+ // // This is computed from the file contents of the directory of files that is
+ // // obtained after fetching `url` and applying the inclusion rules given by
+ // // `paths`.
+ // //
+ // // This field is the source of truth; packages do not come from an `url`; they
+ // // come from a `hash`. `url` is just one of many possible mirrors for how to
+ // // obtain a package matching this `hash`.
+ // //
+ // // Uses the [multihash](https://multiformats.io/multihash/) format.
+ // .hash = "...",
+ //
+ // // When this is provided, the package is found in a directory relative to the
+ // // build root. In this case the package's hash is irrelevant and therefore not
+ // // computed. This field and `url` are mutually exclusive.
+ // .path = "foo",
+ //},
+ },
+
+ // Specifies the set of files and directories that are included in this package.
+ // Only files and directories listed here are included in the `hash` that
+ // is computed for this package.
+ // Paths are relative to the build root. Use the empty string (`""`) to refer to
+ // the build root itself.
+ // A directory listed here means that all files within, recursively, are included.
+ .paths = .{
+ // This makes *all* files, recursively, included in this package. It is generally
+ // better to explicitly list the files and directories instead, to insure that
+ // fetching from tarballs, file system paths, and version control all result
+ // in the same contents hash.
+ "",
+ // For example...
+ //"build.zig",
+ //"build.zig.zon",
+ //"src",
+ //"LICENSE",
+ //"README.md",
+ },
+}