-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
12b3a6b
commit 05460f7
Showing
4 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Day 4 - Ceres Search | ||
|
||
## Part 1 | ||
|
||
"Looks like the Chief's not here. Next!" One of The Historians pulls out a device and pushes the only button on it. After a brief flash, you recognize the interior of the Ceres monitoring station! | ||
|
||
As the search for the Chief continues, a small Elf who lives on the station tugs on your shirt; she'd like to know if you could help her with her word search (your puzzle input). She only has to find one word: XMAS. | ||
|
||
This word search allows words to be horizontal, vertical, diagonal, written backwards, or even overlapping other words. It's a little unusual, though, as you don't merely need to find one instance of XMAS - you need to find all of them. Here are a few ways XMAS might appear, where irrelevant characters have been replaced with .: | ||
|
||
``` | ||
..X... | ||
.SAMX. | ||
.A..A. | ||
XMAS.S | ||
.X.... | ||
``` | ||
|
||
The actual word search will be full of letters instead. For example: | ||
|
||
``` | ||
MMMSXXMASM | ||
MSAMXMSMSA | ||
AMXSXMAAMM | ||
MSAMASMSMX | ||
XMASAMXAMM | ||
XXAMMXXAMA | ||
SMSMSASXSS | ||
SAXAMASAAA | ||
MAMMMXMMMM | ||
MXMXAXMASX | ||
``` | ||
|
||
In this word search, XMAS occurs a total of 18 times; here's the same word search again, but where letters not involved in any XMAS have been replaced with .: | ||
|
||
``` | ||
....XXMAS. | ||
.SAMXMS... | ||
...S..A... | ||
..A.A.MS.X | ||
XMASAMX.MM | ||
X.....XA.A | ||
S.S.S.S.SS | ||
.A.A.A.A.A | ||
..M.M.M.MM | ||
.X.X.XMASX | ||
``` | ||
|
||
Take a look at the little Elf's word search. How many times does XMAS appear? | ||
|
||
## Part 2 | ||
|
||
The Elf looks quizzically at you. Did you misunderstand the assignment? | ||
|
||
Looking for the instructions, you flip over the word search to find that this isn't actually an XMAS puzzle; it's an X-MAS puzzle in which you're supposed to find two MAS in the shape of an X. One way to achieve that is like this: | ||
|
||
``` | ||
M.S | ||
.A. | ||
M.S | ||
``` | ||
|
||
Irrelevant characters have again been replaced with . in the above diagram. Within the X, each MAS can be written forwards or backwards. | ||
|
||
Here's the same example from before, but this time all of the X-MASes have been kept instead: | ||
|
||
``` | ||
.M.S...... | ||
..A..MSMS. | ||
.M.S.MAA.. | ||
..A.ASMSM. | ||
.M.S.M.... | ||
.......... | ||
S.S.S.S.S. | ||
.A.A.A.A.. | ||
M.M.M.M.M. | ||
.......... | ||
``` | ||
|
||
In this example, an X-MAS appears 9 times. | ||
|
||
Flip the word search from the instructions back over to the word search side and try again. How many times does an X-MAS appear? |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package main | ||
|
||
import ( | ||
_ "embed" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"strings" | ||
|
||
file "github.com/shaunburdick/advent-of-code-2024/lib" | ||
) | ||
|
||
var input string | ||
|
||
func init() { | ||
// do this in init (not main) so test file has same input | ||
inputFile, err := file.LoadRelativeFile("input.txt") | ||
if err != nil { | ||
log.Println(err) | ||
} | ||
|
||
input = strings.TrimRight(inputFile, "\n") | ||
} | ||
|
||
func main() { | ||
var part int | ||
flag.IntVar(&part, "part", 1, "part 1 or 2") | ||
flag.Parse() | ||
fmt.Println("Running part", part) | ||
|
||
if part == 1 { | ||
ans := part1(input) | ||
fmt.Println("Output:", ans) | ||
} else { | ||
ans := part2(input) | ||
fmt.Println("Output:", ans) | ||
} | ||
} | ||
|
||
const MAS = "MAS" | ||
const XMAS = "X" + MAS | ||
|
||
func part1(input string) int { | ||
parsed := parseInput(input) | ||
foundWords := 0 | ||
// start traversing the grid | ||
for y, row := range parsed { | ||
for x := range row { | ||
coord := Coords{x, y} | ||
foundWords += xmasSearch(parsed, "", coord, AllDirections) | ||
} | ||
} | ||
|
||
return foundWords | ||
} | ||
|
||
func part2(input string) int { | ||
parsed := parseInput(input) | ||
grid := Grid{parsed} | ||
foundMas := 0 | ||
// start traversing the grid | ||
for y, row := range grid.Data { | ||
if y == 0 || y == len(grid.Data)-1 { | ||
// skip edges | ||
continue | ||
} | ||
|
||
for x, char := range row { | ||
if x == 0 || x == len(row)-1 { | ||
// skip edges | ||
continue | ||
} | ||
if char == 'A' { | ||
coord := Coords{x, y} | ||
wing1 := string(grid.CharAt(coord.Direction(NorthWest))) + "A" + string(grid.CharAt(coord.Direction(SouthEast))) | ||
wing2 := string(grid.CharAt(coord.Direction(NorthEast))) + "A" + string(grid.CharAt(coord.Direction(SouthWest))) | ||
|
||
if (wing1 == "MAS" || wing1 == "SAM") && (wing2 == "MAS" || wing2 == "SAM") { | ||
foundMas += 1 | ||
} | ||
} | ||
} | ||
} | ||
|
||
return foundMas | ||
} | ||
|
||
type Grid struct { | ||
Data []string | ||
} | ||
|
||
func (g Grid) CharAt(c Coords) rune { | ||
return rune(g.Data[c.y][c.x]) | ||
} | ||
|
||
type Coords struct { | ||
x int | ||
y int | ||
} | ||
|
||
type Direction int | ||
|
||
const ( | ||
NorthWest Direction = iota | ||
North | ||
NorthEast | ||
West | ||
East | ||
SouthWest | ||
South | ||
SouthEast | ||
) | ||
|
||
var AllDirections []Direction = []Direction{ | ||
NorthWest, | ||
North, | ||
NorthEast, | ||
West, | ||
East, | ||
SouthWest, | ||
South, | ||
SouthEast, | ||
} | ||
|
||
// Generate a list of valid coordinates from the existing one | ||
// Will only return valid positive values | ||
func (c Coords) Directions() []Coords { | ||
directions := []Coords{} | ||
|
||
for _, dir := range AllDirections { | ||
newCoord := c.Direction(dir) | ||
// check for bounds | ||
if newCoord.x >= 0 && newCoord.y >= 0 { | ||
directions = append(directions, newCoord) | ||
} | ||
} | ||
|
||
return directions | ||
} | ||
|
||
func (c Coords) Direction(d Direction) Coords { | ||
switch d { | ||
case NorthWest: | ||
return Coords{x: c.x - 1, y: c.y - 1} | ||
case North: | ||
return Coords{x: c.x, y: c.y - 1} | ||
case NorthEast: | ||
return Coords{x: c.x + 1, y: c.y - 1} | ||
case West: | ||
return Coords{x: c.x - 1, y: c.y} | ||
case East: | ||
return Coords{x: c.x + 1, y: c.y} | ||
case SouthWest: | ||
return Coords{x: c.x - 1, y: c.y + 1} | ||
case South: | ||
return Coords{x: c.x, y: c.y + 1} | ||
case SouthEast: | ||
return Coords{x: c.x + 1, y: c.y + 1} | ||
default: | ||
return c | ||
} | ||
} | ||
|
||
func xmasSearch(grid []string, currentWord string, coords Coords, directions []Direction) int { | ||
foundWords := 0 | ||
newWord := currentWord + string(grid[coords.y][coords.x]) | ||
if newWord == XMAS { | ||
// we match! | ||
return 1 | ||
} else if len(newWord) >= len(XMAS) || !strings.HasPrefix(XMAS, newWord) { | ||
// we don't match! | ||
return 0 | ||
} else { | ||
// we partially match, keep looking! | ||
for _, direction := range directions { | ||
newCoord := coords.Direction(direction) | ||
// check for bounds | ||
if newCoord.x >= 0 && newCoord.y >= 0 && newCoord.y < len(grid) && newCoord.x < len(grid[newCoord.y]) { | ||
foundWords += xmasSearch(grid, newWord, newCoord, []Direction{direction}) | ||
} | ||
} | ||
} | ||
|
||
return foundWords | ||
} | ||
|
||
func parseInput(input string) (ans []string) { | ||
return strings.Split(input, "\n") | ||
} |
Oops, something went wrong.