Compare commits
59 Commits
gitea-acti
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| fb896a8d20 | |||
| 5bebd71c4e | |||
| 6d24500c69 | |||
| d17308873e | |||
| c6150871a3 | |||
| ec4a4243ca | |||
| 64de63ddbe | |||
| a17153662e | |||
| 852a805114 | |||
| 574fdf38a4 | |||
| a879d3bb88 | |||
| f48bae3bc3 | |||
| 745d95771c | |||
| c9df0e8fb8 | |||
| a692b4da4b | |||
| 62d8af2d1b | |||
| c159403427 | |||
| d900defb9b | |||
| 7ec430c8b5 | |||
| 255f39620e | |||
| 75ec54c0d2 | |||
| 32a84c2f3c | |||
| 2778e38f8b | |||
| 8a2afac023 | |||
| c16d3362fd | |||
| ad945bd41e | |||
| a2b9dfbcbe | |||
| 8c6d00683e | |||
| be12e11f5e | |||
| 4b51738c60 | |||
| 6946c978c6 | |||
| 3fc767f046 | |||
| 35dc086519 | |||
| 7686ffd788 | |||
| 96b4441bfc | |||
| 36b2f6feb3 | |||
| 8871be0bc9 | |||
| 76da133e30 | |||
| 7a8c20acc6 | |||
| c45c84ba8b | |||
| d11426e518 | |||
| 1c2e835ebc | |||
| a609bf72a9 | |||
| 8c6b9b3dfe | |||
| 9925c227a4 | |||
| e5c255d759 | |||
| 1ca62d7dbc | |||
| e4f381df4b | |||
| 923e0331f7 | |||
| a4ee3fde16 | |||
| 8a91af0713 | |||
| 7a92f12c01 | |||
| 5ad191354c | |||
| d386fc7d10 | |||
| 134cb7aad1 | |||
| 00815609cb | |||
| 14928230b8 | |||
| d2ce81647b | |||
| 2e0faf87eb |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -17,6 +17,8 @@ jobs:
|
|||||||
run: go build -v ./day01/*.go
|
run: go build -v ./day01/*.go
|
||||||
- name: Build day two
|
- name: Build day two
|
||||||
run: go build -v ./day02/*.go
|
run: go build -v ./day02/*.go
|
||||||
|
- name: Run day one
|
||||||
|
run: go run -v ./day01/*.go
|
||||||
- name: Display Go version
|
- name: Display Go version
|
||||||
run: go version
|
run: go version
|
||||||
- name: List files in the repository
|
- name: List files in the repository
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,3 +22,4 @@ go.work
|
|||||||
|
|
||||||
# Problem data
|
# Problem data
|
||||||
input*.txt
|
input*.txt
|
||||||
|
inputs/
|
||||||
|
|||||||
16
README.md
Normal file
16
README.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
# Advent of Code 2023
|
||||||
|
|
||||||
|
An attempt to start programming again.
|
||||||
|
|
||||||
|
- [Day 1](./day01/trebuchet.go)
|
||||||
|
- [Day 2](./day02/lottacubes.go)
|
||||||
|
- [Day 3](./day03/engine-schema.go)
|
||||||
|
- [Day 4](./day04/scratchcards.go)
|
||||||
|
- [Day 5](./day05/seeds.go)
|
||||||
|
- [Day 6](./day06/race.go)
|
||||||
|
- [Day 7](./day07/cards.go)
|
||||||
|
- [Day 8](./day08/charpath.go)
|
||||||
|
- [Day 9](./day09/oasis.go)
|
||||||
|
|
||||||
|
|
||||||
|
This repo gets automatically mirrored to [Github](https://github.com/Doddophonique/aoc2023).
|
||||||
24
UNLICENSE
Normal file
24
UNLICENSE
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This is free and unencumbered software released into the public domain.
|
||||||
|
|
||||||
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||||
|
distribute this software, either in source code form or as a compiled
|
||||||
|
binary, for any purpose, commercial or non-commercial, and by any
|
||||||
|
means.
|
||||||
|
|
||||||
|
In jurisdictions that recognize copyright laws, the author or authors
|
||||||
|
of this software dedicate any and all copyright interest in the
|
||||||
|
software to the public domain. We make this dedication for the benefit
|
||||||
|
of the public at large and to the detriment of our heirs and
|
||||||
|
successors. We intend this dedication to be an overt act of
|
||||||
|
relinquishment in perpetuity of all present and future rights to this
|
||||||
|
software under copyright law.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||||
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||||
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
For more information, please refer to <http://unlicense.org/>
|
||||||
1000
day01/input
1000
day01/input
File diff suppressed because it is too large
Load Diff
1
day01/inputs
Symbolic link
1
day01/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
@ -109,7 +109,7 @@ func CombineIndexes(s string) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
file, err := os.Open("input")
|
file, err := os.Open("./inputs/day01_input")
|
||||||
check(err)
|
check(err)
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
|
|||||||
1
day02/inputs
Symbolic link
1
day02/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
175
day02/lottacubes.go
Normal file
175
day02/lottacubes.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var requiredCubes = map[string]int {
|
||||||
|
"red": 12,
|
||||||
|
"green": 13,
|
||||||
|
"blue": 14,
|
||||||
|
}
|
||||||
|
|
||||||
|
type possibleGame struct {
|
||||||
|
redIsPossible bool
|
||||||
|
greenIsPossible bool
|
||||||
|
blueIsPossible bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type minimumSet struct {
|
||||||
|
red int
|
||||||
|
green int
|
||||||
|
blue int
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitSets (s string) ([]string, int) {
|
||||||
|
// Every set is divided by ;
|
||||||
|
sets := strings.SplitN(s, ";", -1)
|
||||||
|
// Number of sets can vary, we need to have that info
|
||||||
|
numSets := len(sets)
|
||||||
|
|
||||||
|
return sets, numSets
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGameSet(s string) map[string]int {
|
||||||
|
m := make(map[string]int)
|
||||||
|
|
||||||
|
tempNumColor := strings.SplitN(s, ",", -1)
|
||||||
|
|
||||||
|
for i := 0; i < len(tempNumColor); i++ {
|
||||||
|
TrimmedNumColor := strings.Trim(tempNumColor[i], " ")
|
||||||
|
NumColor := strings.SplitN(TrimmedNumColor, " ", -1)
|
||||||
|
|
||||||
|
m[NumColor[1]], _ = strconv.Atoi(NumColor[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
func CheckGame(mySet map[string]int, p *possibleGame) {
|
||||||
|
|
||||||
|
if (mySet["red"] > requiredCubes["red"]) {
|
||||||
|
p.redIsPossible = false
|
||||||
|
}
|
||||||
|
if (mySet["green"] > requiredCubes["green"]) {
|
||||||
|
p.greenIsPossible = false
|
||||||
|
}
|
||||||
|
if (mySet["blue"] > requiredCubes["blue"]) {
|
||||||
|
p.blueIsPossible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findMinimumSet(mySet map[string]int, m *minimumSet) {
|
||||||
|
if (mySet["red"] > m.red) {
|
||||||
|
m.red = mySet["red"]
|
||||||
|
}
|
||||||
|
if (mySet["green"] > m.green) {
|
||||||
|
m.green = mySet["green"]
|
||||||
|
}
|
||||||
|
if (mySet["blue"] > m.blue) {
|
||||||
|
m.blue = mySet["blue"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PossibleGamesSum(s string, gn int, gt *int) {
|
||||||
|
// Initialize everything to true. If everything was set to false,
|
||||||
|
// we would have to check in both directions for every pass
|
||||||
|
isPossible := possibleGame{redIsPossible: true,
|
||||||
|
greenIsPossible: true,
|
||||||
|
blueIsPossible: true}
|
||||||
|
// We will pass a pointer so we can go one map at a time and
|
||||||
|
// still maintain the results
|
||||||
|
var isPossiblePoint *possibleGame
|
||||||
|
isPossiblePoint = &isPossible
|
||||||
|
// We receive a string with the sets, not split
|
||||||
|
// We proceed to split
|
||||||
|
sets, numSets := splitSets(s)
|
||||||
|
// We received a []string with sets and the number of sets
|
||||||
|
// Now it's time to create a map
|
||||||
|
var mySet map[string]int
|
||||||
|
// For every set we have in the current game
|
||||||
|
for i := 0; i < numSets; i++ {
|
||||||
|
// We create a map
|
||||||
|
mySet = newGameSet(sets[i])
|
||||||
|
// We check if the game is possible
|
||||||
|
CheckGame(mySet, isPossiblePoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPossible.redIsPossible == true) &&
|
||||||
|
(isPossible.greenIsPossible == true) &&
|
||||||
|
(isPossible.blueIsPossible == true) {
|
||||||
|
*gt += gn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PowerSetsSum(s string, pt *int) {
|
||||||
|
// In this case, we need an array of integers
|
||||||
|
minSet := minimumSet{red: 0, green: 0, blue: 0}
|
||||||
|
|
||||||
|
var minSetPoint *minimumSet
|
||||||
|
minSetPoint = &minSet
|
||||||
|
|
||||||
|
// We receive a string with the sets, not split
|
||||||
|
// We proceed to split
|
||||||
|
sets, numSets := splitSets(s)
|
||||||
|
// We received a []string with sets and the number of sets
|
||||||
|
// Now it's time to create a map
|
||||||
|
var mySet map[string]int
|
||||||
|
// For every set we have in the current game
|
||||||
|
for i := 0; i < numSets; i++ {
|
||||||
|
// We create a map
|
||||||
|
mySet = newGameSet(sets[i])
|
||||||
|
// We find the minimum set
|
||||||
|
findMinimumSet(mySet, minSetPoint)
|
||||||
|
}
|
||||||
|
*pt += (minSet.red * minSet.green * minSet.blue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait[T any](x T) {
|
||||||
|
fmt.Print(x)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open("./inputs/day02_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// This variable will hold the game number
|
||||||
|
var gameNum int = 0
|
||||||
|
// This variable will hold the pointer of the sum of possible games
|
||||||
|
var gameSumPoint *int
|
||||||
|
gameSum := 0
|
||||||
|
gameSumPoint = &gameSum
|
||||||
|
|
||||||
|
// Variable for the sum of the power of the sets
|
||||||
|
var power int = 0
|
||||||
|
// Pointer to power, nice variable name
|
||||||
|
var powerPoint *int = &power
|
||||||
|
|
||||||
|
_ = gameNum
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
// Split the string in "Game N" and "cubes color"
|
||||||
|
gameAndCubes := strings.Split(line, ":")
|
||||||
|
// At this point, gameAndCubes[0] has "Game N"
|
||||||
|
// We convert the number that remains after replacing "Game " with ""
|
||||||
|
gameNum, _ = strconv.Atoi(strings.Replace(gameAndCubes[0], "Game ", "", 1))
|
||||||
|
// Now, for every game, split the sets
|
||||||
|
PossibleGamesSum(gameAndCubes[1], gameNum, gameSumPoint)
|
||||||
|
PowerSetsSum(gameAndCubes[1], powerPoint)
|
||||||
|
}
|
||||||
|
fmt.Printf("The sum of possible games is: %d\n", gameSum)
|
||||||
|
fmt.Printf("The sum of the power of sets is: %d\n", power)
|
||||||
|
}
|
||||||
220
day03/engine-schema.go
Normal file
220
day03/engine-schema.go
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
// "strings"
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
func MatchNumbers(lines []string, index int, ast []int, total *int) {
|
||||||
|
// Regex that finds the numbers in a row
|
||||||
|
renum := regexp.MustCompile("[0-9]+")
|
||||||
|
// Gather numbers in prev line
|
||||||
|
prevLine := renum.FindAllStringIndex(lines[index-1], -1)
|
||||||
|
// Gather numbers in this line
|
||||||
|
thisLine := renum.FindAllStringIndex(lines[index], -1)
|
||||||
|
// Gather numbers in next line
|
||||||
|
nextLine := renum.FindAllStringIndex(lines[index+1], -1)
|
||||||
|
// Calculate the number of numbers in three lines
|
||||||
|
totalNumbers := len(prevLine) + len(thisLine) + len(nextLine)
|
||||||
|
|
||||||
|
// Now we create a big array with all the indexes
|
||||||
|
allIndexes := prevLine
|
||||||
|
for i := range thisLine {
|
||||||
|
allIndexes = append(allIndexes, thisLine[i])
|
||||||
|
}
|
||||||
|
for i := range nextLine {
|
||||||
|
allIndexes = append(allIndexes, nextLine[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we create a big array with all the numbers
|
||||||
|
// We start from the previous line
|
||||||
|
allNumbers := renum.FindAllString(lines[index-1], -1)
|
||||||
|
thisNums := renum.FindAllString(lines[index], -1)
|
||||||
|
for i := range thisNums {
|
||||||
|
allNumbers = append(allNumbers, thisNums[i])
|
||||||
|
}
|
||||||
|
nextNums := renum.FindAllString(lines[index+1], -1)
|
||||||
|
for i := range nextNums {
|
||||||
|
allNumbers = append(allNumbers, nextNums[i])
|
||||||
|
}
|
||||||
|
// When we start, we have zero matches
|
||||||
|
matches := 0
|
||||||
|
// We will stop when we encounter two numbers
|
||||||
|
twoNums := [2]int{0, 0}
|
||||||
|
_ = twoNums
|
||||||
|
// Cycling through all numbers, but stopping at two matches
|
||||||
|
for i := 0; i < totalNumbers && matches < 2; i++ {
|
||||||
|
if (ast[0] >= allIndexes[i][0] - 1 && ast[0] <= allIndexes[i][1]) {
|
||||||
|
matches += 1
|
||||||
|
num, _ := strconv.Atoi(allNumbers[i])
|
||||||
|
twoNums[matches - 1] = num
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(matches == 2) {
|
||||||
|
tempGears := twoNums[0] * twoNums[1]
|
||||||
|
*total += tempGears
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckGears(lines []string) {
|
||||||
|
total := 0
|
||||||
|
totalPoint := &total
|
||||||
|
// Regex that finds the numbers in a row
|
||||||
|
//renum := regexp.MustCompile("[0-9]+")
|
||||||
|
// Regex that finds the asterisks in a row
|
||||||
|
resym := regexp.MustCompile("[*]")
|
||||||
|
// For every line starting from the second
|
||||||
|
for i := 0; i < len(lines) - 1; i++ {
|
||||||
|
// Take the index of the asterisks
|
||||||
|
asteriskIndex := resym.FindAllStringIndex(lines[i], - 1)
|
||||||
|
// For every index we get
|
||||||
|
for j := range asteriskIndex {
|
||||||
|
MatchNumbers(lines, i, asteriskIndex[j], totalPoint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// firstLineNums := renum.FindAllStringIndex(lines[index], -1)
|
||||||
|
// firstLineSymbolsIndex := resym.FindAllStringIndex(lines[index], -1)
|
||||||
|
// secondLineSymbolsIndex := resym.FindAllStringIndex(lines[index + 1], -1)
|
||||||
|
// For every *number index range*, check if in the same line there is a
|
||||||
|
// symbol on (first - 1) or (last + 1), check in other lines if there is
|
||||||
|
// a symbol in a specific interval of numbers. If you find a match, you
|
||||||
|
// can break as you just need one symbol
|
||||||
|
fmt.Printf("Total of gears is: %d\n", total)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open("./inputs/day03_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// This regex find the numbers inside strings
|
||||||
|
renum := regexp.MustCompile("[0-9]+")
|
||||||
|
resym := regexp.MustCompile("[^0-9.]+")
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
var lines []string
|
||||||
|
var totalSum int = 0
|
||||||
|
|
||||||
|
// Read the whole file into an array of strings
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
numLines := len(lines)
|
||||||
|
numbers := make([][]int, numLines)
|
||||||
|
|
||||||
|
// The 2D array of numbers will hold all the numbers to easily
|
||||||
|
// match them with corresponding strings in the file using the index
|
||||||
|
// For every line in the file, create an array of numbers
|
||||||
|
for i := 0; i < numLines; i++ {
|
||||||
|
tempNums := renum.FindAllString(lines[i], -1)
|
||||||
|
for j := 0; j < len(tempNums); j++ {
|
||||||
|
num, _ := strconv.Atoi(tempNums[j])
|
||||||
|
numbers[i] = append(numbers[i], num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Line [0] needs to check only line 1 for symbols.
|
||||||
|
Similarly, the last line needs to check only
|
||||||
|
(last line index - 1) for symbols.
|
||||||
|
So we first check the line [0], then start a loop
|
||||||
|
from 1 to (last line index - 1)
|
||||||
|
*/
|
||||||
|
firstLineNums := renum.FindAllStringIndex(lines[0], -1)
|
||||||
|
firstLineSymbolsIndex := resym.FindAllStringIndex(lines[0], -1)
|
||||||
|
secondLineSymbolsIndex := resym.FindAllStringIndex(lines[1], -1)
|
||||||
|
// For every *number index range*, check if in the same line there is a
|
||||||
|
// symbol on (first - 1) or (last + 1), check in other lines if there is
|
||||||
|
// a symbol in a specific interval of numbers. If you find a match, you
|
||||||
|
// can break as you just need one symbol
|
||||||
|
for i := range firstLineNums {
|
||||||
|
for j := range firstLineSymbolsIndex {
|
||||||
|
if firstLineSymbolsIndex[j][0] >= firstLineNums[i][0] - 1 &&
|
||||||
|
(firstLineSymbolsIndex[j][0] <= firstLineNums[i][1]) {
|
||||||
|
totalSum += numbers[0][i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j := range secondLineSymbolsIndex {
|
||||||
|
if (secondLineSymbolsIndex[j][0] >= firstLineNums[i][0] - 1) &&
|
||||||
|
(secondLineSymbolsIndex[j][0] <= firstLineNums[i][1]) {
|
||||||
|
totalSum += numbers[0][i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now we loop from 1 to (last index - i)
|
||||||
|
for i := 1; i < len(lines) - 1; i++ {
|
||||||
|
// We need to check the current line against an interval of three lines
|
||||||
|
// breaking the loop for a single number as soon as we find a match
|
||||||
|
// (we don't want duplicate matches)
|
||||||
|
currentLineNums := renum.FindAllStringIndex(lines[i], -1)
|
||||||
|
previousLineIndex := resym.FindAllStringIndex(lines[i - 1], -1)
|
||||||
|
currentLineIndex := resym.FindAllStringIndex(lines[i], -1)
|
||||||
|
nextLineIndex := resym.FindAllStringIndex(lines[i + 1], -1)
|
||||||
|
OuterLoop:
|
||||||
|
for k := range currentLineNums {
|
||||||
|
for j := range previousLineIndex {
|
||||||
|
if previousLineIndex[j][0] >= currentLineNums[k][0] - 1 &&
|
||||||
|
previousLineIndex[j][0] <= currentLineNums[k][1] {
|
||||||
|
totalSum += numbers[i][k]
|
||||||
|
continue OuterLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j := range currentLineIndex {
|
||||||
|
if currentLineIndex[j][0] >= currentLineNums[k][0] - 1 &&
|
||||||
|
currentLineIndex[j][0] <= currentLineNums[k][1] {
|
||||||
|
totalSum += numbers[i][k]
|
||||||
|
continue OuterLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j := range nextLineIndex {
|
||||||
|
if nextLineIndex[j][0] >= currentLineNums[k][0] - 1 &&
|
||||||
|
nextLineIndex[j][0] <= currentLineNums[k][1] {
|
||||||
|
totalSum += numbers[i][k]
|
||||||
|
continue OuterLoop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now we need to loop the last line and confront it with previous
|
||||||
|
// and itself
|
||||||
|
lastLineNums := renum.FindAllStringIndex(lines[len(lines) - 1], -1)
|
||||||
|
lastLineSymbolsIndex := resym.FindAllStringIndex(lines[len(lines) - 1], -1)
|
||||||
|
notLastLineSymbolsIndex := resym.FindAllStringIndex(lines[len(lines) - 2], -1)
|
||||||
|
// For every *number index range*, check if in the same line there is a
|
||||||
|
// symbol on (last - 1) or (last + 1), check in other lines if there is
|
||||||
|
// a symbol in a specific interval of numbers. If you find a match, you
|
||||||
|
// can break as you just need one symbol
|
||||||
|
for i := range lastLineNums {
|
||||||
|
for j := range lastLineSymbolsIndex {
|
||||||
|
if lastLineSymbolsIndex[j][0] >= lastLineNums[i][0] - 1 &&
|
||||||
|
(lastLineSymbolsIndex[j][0] <= lastLineNums[i][1]) {
|
||||||
|
totalSum += numbers[len(lines) - 1][i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for j := range notLastLineSymbolsIndex {
|
||||||
|
if (notLastLineSymbolsIndex[j][0] >= lastLineNums[i][0] - 1) &&
|
||||||
|
(notLastLineSymbolsIndex[j][0] <= lastLineNums[i][1]) {
|
||||||
|
totalSum += numbers[len(lines) - 1][i]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("The total sum is: %d\n", totalSum)
|
||||||
|
CheckGears(lines)
|
||||||
|
}
|
||||||
1
day03/inputs
Symbolic link
1
day03/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
1
day04/inputs
Symbolic link
1
day04/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
115
day04/scratchcards.go
Normal file
115
day04/scratchcards.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
// "strconv"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SplitSets(s []string) ([]string, []string) {
|
||||||
|
|
||||||
|
// Split the two sets into winning and my numbers
|
||||||
|
tempwinningNumbers := s[0]
|
||||||
|
tempMyNumbers := s[1]
|
||||||
|
// Regex to populate a string with numbers
|
||||||
|
renum := regexp.MustCompile("[0-9]+")
|
||||||
|
myNumbers := renum.FindAllString(tempMyNumbers, -1)
|
||||||
|
winningNumbers := renum.FindAllString(tempwinningNumbers, -1)
|
||||||
|
|
||||||
|
return myNumbers, winningNumbers
|
||||||
|
}
|
||||||
|
|
||||||
|
func FindMatches(myNum []string, winNum []string) int {
|
||||||
|
matches := 0
|
||||||
|
for i := range myNum {
|
||||||
|
for j := range winNum {
|
||||||
|
if (myNum[i] == winNum[j]) {
|
||||||
|
matches += 1
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matches
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalcTickets(s []string, index int, tpr []int ) {
|
||||||
|
|
||||||
|
myNumbers, winningNumbers := SplitSets(s)
|
||||||
|
matches := FindMatches(myNumbers, winningNumbers)
|
||||||
|
if (matches > 0) {
|
||||||
|
for j := 0; j < tpr[index]; j++ {
|
||||||
|
for i := index; i < index + matches; i++ {
|
||||||
|
tpr[i+1] += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CalcScore (s []string, t *int) {
|
||||||
|
|
||||||
|
myNumbers, winningNumbers := SplitSets(s)
|
||||||
|
matches := FindMatches(myNumbers, winningNumbers)
|
||||||
|
if(matches > 0) {
|
||||||
|
tempTotal := 1
|
||||||
|
for i := 0; i < matches - 1; i++ {
|
||||||
|
tempTotal *= 2
|
||||||
|
}
|
||||||
|
*t += tempTotal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open("./inputs/day04_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// The total is a simple sum
|
||||||
|
var total int = 0
|
||||||
|
var totalPoint *int = &total
|
||||||
|
// To keep track of the amount of tickets, an array as long
|
||||||
|
// as the number of lines
|
||||||
|
var lines []string
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
ticketsPerRow := make([]int, len(lines))
|
||||||
|
tprPoint := ticketsPerRow[0:len(lines)]
|
||||||
|
|
||||||
|
for i := range ticketsPerRow {
|
||||||
|
ticketsPerRow[i] = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan every line
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
// e.g.: Card 1: 41 48 83 86 17 | 83 86 6 31 17 9 48 53
|
||||||
|
cardAndNumbers := strings.Split(lines[i], ":")
|
||||||
|
// At this point, cardAndNumbers has "Card N"
|
||||||
|
// We don't need this information (yet?)
|
||||||
|
allNumbers := strings.Split(cardAndNumbers[1], "|")
|
||||||
|
CalcScore(allNumbers, totalPoint)
|
||||||
|
CalcTickets(allNumbers, i, tprPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
numTickets := 0
|
||||||
|
for i := range ticketsPerRow {
|
||||||
|
numTickets += ticketsPerRow[i]
|
||||||
|
}
|
||||||
|
fmt.Printf("The scratchcards are worth %d points.\n", total)
|
||||||
|
fmt.Printf("In total, I have %d scratchcards.", numTickets)
|
||||||
|
}
|
||||||
1
day05/inputs
Symbolic link
1
day05/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
158
day05/seeds.go
Normal file
158
day05/seeds.go
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
// "strings"
|
||||||
|
"bufio"
|
||||||
|
"math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Minimum struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
minimum int
|
||||||
|
}
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetMaps(scanner *bufio.Scanner, re *regexp.Regexp) [][]int {
|
||||||
|
// Scan until there is an empty line
|
||||||
|
var tempNums int = 0
|
||||||
|
tempArray := make([][]int, 0)
|
||||||
|
for i := 0; scanner.Scan() && scanner.Text() != ""; i++ {
|
||||||
|
tempString := re.FindAllString(scanner.Text(), -1)
|
||||||
|
temp := make([]int, 0)
|
||||||
|
for j := range tempString {
|
||||||
|
tempNums, _ = strconv.Atoi(tempString[j])
|
||||||
|
temp = append(temp, tempNums)
|
||||||
|
}
|
||||||
|
tempArray = append(tempArray, temp)
|
||||||
|
}
|
||||||
|
// Prepare for next line
|
||||||
|
scanner.Scan()
|
||||||
|
return tempArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func (min *Minimum) ParallelMinimum(start, finish int, atrocity [][][]int, wg *sync.WaitGroup) {
|
||||||
|
// We check the array one by one, need a temp array because
|
||||||
|
// SeedToLocation wants it
|
||||||
|
tempNum := make([]int, 1)
|
||||||
|
tempMin := []int{0}
|
||||||
|
_ = tempMin
|
||||||
|
for i := 0; i < finish; i++ {
|
||||||
|
tempNum[0] = start + i
|
||||||
|
tempMin := SeedToLocation(tempNum, atrocity)
|
||||||
|
// Need to modify a shared variable, lock
|
||||||
|
min.mu.Lock()
|
||||||
|
if tempMin[0] < min.minimum {
|
||||||
|
min.minimum = tempMin[0]
|
||||||
|
}
|
||||||
|
min.mu.Unlock()
|
||||||
|
}
|
||||||
|
// We finished with the Goroutine
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SeedToLocation(seeds []int, atrocity [][][]int) []int {
|
||||||
|
tempRes := seeds
|
||||||
|
for i := range atrocity {
|
||||||
|
tempRes = NextResource(tempRes, atrocity[i])
|
||||||
|
}
|
||||||
|
return tempRes
|
||||||
|
}
|
||||||
|
|
||||||
|
func NextResource(previous []int, resource [][]int) []int {
|
||||||
|
tempRes := make([]int, 0)
|
||||||
|
// [0] is dest, [1] is source, [2] is range
|
||||||
|
for i := range previous {
|
||||||
|
for j := range resource {
|
||||||
|
if previous[i] >= resource[j][1] &&
|
||||||
|
previous[i] <= (resource[j][1] + resource[j][2] - 1) {
|
||||||
|
tempRes = append(tempRes, previous[i] + (resource[j][0] - resource[j][1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we didn't add an element to the array
|
||||||
|
if len(tempRes) == i {
|
||||||
|
tempRes = append(tempRes, previous[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempRes
|
||||||
|
}
|
||||||
|
func main () {
|
||||||
|
file, err := os.Open("./inputs/day05_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
min := Minimum{
|
||||||
|
minimum: math.MaxInt,
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Regex that finds the numbers in a row
|
||||||
|
renum := regexp.MustCompile("[0-9]+")
|
||||||
|
|
||||||
|
var seeds []int
|
||||||
|
var soils, fertilizers, waters, lights, temperatures,
|
||||||
|
humidities, locations [][]int
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
// We know that the seeds only have one row
|
||||||
|
scanner.Scan()
|
||||||
|
// Put all the numbers in an array of strings
|
||||||
|
seedsNums := renum.FindAllString(scanner.Text(), -1)
|
||||||
|
// Extract every number from the string
|
||||||
|
for i := 0; i < len(seedsNums); i++ {
|
||||||
|
num, _ := strconv.Atoi(seedsNums[i])
|
||||||
|
seeds = append(seeds, num)
|
||||||
|
}
|
||||||
|
// We know we have an empty string and just a title, skip them
|
||||||
|
scanner.Scan()
|
||||||
|
scanner.Scan()
|
||||||
|
// Should be possible to just pass the scanner
|
||||||
|
soils = GetMaps(scanner, renum)
|
||||||
|
fertilizers = GetMaps(scanner, renum)
|
||||||
|
waters = GetMaps(scanner, renum)
|
||||||
|
lights = GetMaps(scanner, renum)
|
||||||
|
temperatures = GetMaps(scanner, renum)
|
||||||
|
humidities = GetMaps(scanner, renum)
|
||||||
|
locations = GetMaps(scanner, renum)
|
||||||
|
|
||||||
|
tempRes := make([]int, 0)
|
||||||
|
// Actually insane behaviour
|
||||||
|
monster := [][][]int{
|
||||||
|
soils, fertilizers, waters,
|
||||||
|
lights, temperatures, humidities,
|
||||||
|
locations,
|
||||||
|
}
|
||||||
|
// Send the seeds, receive
|
||||||
|
tempRes = SeedToLocation(seeds, monster)
|
||||||
|
|
||||||
|
minimum := math.MaxInt
|
||||||
|
for i := range tempRes {
|
||||||
|
if tempRes[i] < minimum {
|
||||||
|
minimum = tempRes[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Minimum of first part: %d\n", minimum)
|
||||||
|
|
||||||
|
// Actual madness
|
||||||
|
for i := 0; i < len(seeds); i += 2 {
|
||||||
|
wg.Add(1)
|
||||||
|
go min.ParallelMinimum(seeds[i], seeds[i+1], monster, &wg)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
//tempRes = SeedToLocation(allSeeds, monster)
|
||||||
|
fmt.Printf("Minimum of second part: %d\n", min.minimum)
|
||||||
|
}
|
||||||
1
day06/inputs
Symbolic link
1
day06/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
126
day06/race.go
Normal file
126
day06/race.go
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
// "strings"
|
||||||
|
"bufio"
|
||||||
|
// "math"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Race struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
total int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Race) WeRaceBoys(time, distance int, wg *sync.WaitGroup) {
|
||||||
|
// As we just need to find the minimum necessary and then subtract it from
|
||||||
|
// the maximum, probably a good idea starting form the middle
|
||||||
|
tempTime := 0
|
||||||
|
for i := int(time/2); i > 0; i-- {
|
||||||
|
tempDist := i * (time - i)
|
||||||
|
if tempDist <= distance {
|
||||||
|
tempTime = i + 1
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If the minimum is tempTime, then the maximum is time - tempTime
|
||||||
|
// time - 2*tempTime is the number of possible victories
|
||||||
|
r.mu.Lock()
|
||||||
|
r.total *= (time - (2 * tempTime - 1))
|
||||||
|
r.mu.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func MultRaceDist(time, dist []string) ([]int, []int){
|
||||||
|
tempT, tempD := make([]int, 0), make([]int, 0)
|
||||||
|
for i := range time {
|
||||||
|
num, _ := strconv.Atoi(time[i])
|
||||||
|
tempT = append(tempT, num)
|
||||||
|
num, _ = strconv.Atoi(dist[i])
|
||||||
|
tempD = append(tempD, num)
|
||||||
|
}
|
||||||
|
return tempT, tempD
|
||||||
|
}
|
||||||
|
|
||||||
|
func SingleRaceDist(time, dist []string) (int, int) {
|
||||||
|
strT, strD := "", ""
|
||||||
|
numT, numD := 0, 0
|
||||||
|
// Create two big strings
|
||||||
|
for i := range time {
|
||||||
|
strT += time[i]
|
||||||
|
strD += dist[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
numT, _ = strconv.Atoi(strT)
|
||||||
|
numD, _ = strconv.Atoi(strD)
|
||||||
|
|
||||||
|
return numT, numD
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
file, err := os.Open("./inputs/day06_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Struct for multiple races
|
||||||
|
rMult := Race{
|
||||||
|
total: 1,
|
||||||
|
}
|
||||||
|
// Struct for a single race
|
||||||
|
rSing := Race{
|
||||||
|
total: 1,
|
||||||
|
}
|
||||||
|
_ = &rSing
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
// Regex that finds the numbers in a row
|
||||||
|
renum := regexp.MustCompile("[0-9]+")
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
time, distance := make([]int, 0), make([]int, 0)
|
||||||
|
tempStrings := make([]string, 0)
|
||||||
|
// Generic, would work for more rows
|
||||||
|
for scanner.Scan() {
|
||||||
|
tempStrings = append(tempStrings, scanner.Text())
|
||||||
|
}
|
||||||
|
// Now populate time and distance
|
||||||
|
timeStr := renum.FindAllString(tempStrings[0], - 1)
|
||||||
|
distStr := renum.FindAllString(tempStrings[1], - 1)
|
||||||
|
|
||||||
|
time, distance = MultRaceDist(timeStr, distStr)
|
||||||
|
|
||||||
|
// E.g.: if I hold the button for 1ms and then release it, it will travel at
|
||||||
|
// 1mm/ms fo the remaining amount of seconds.
|
||||||
|
// We can skip the holding down 0 and tMAX ms.
|
||||||
|
// Once we find the MIN amount of ms necessary to win, the limit is
|
||||||
|
// MAX - MIN
|
||||||
|
wg.Add(len(time))
|
||||||
|
for i := 0; i < len(time); i++ {
|
||||||
|
go rMult.WeRaceBoys(time[i], distance[i], &wg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Silly implementation of the single race
|
||||||
|
singT, singD := SingleRaceDist(timeStr, distStr)
|
||||||
|
wg.Add(1)
|
||||||
|
go rSing.WeRaceBoys(singT, singD, &wg)
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
fmt.Printf("Multiple races result: %d.\n", rMult.total)
|
||||||
|
fmt.Printf("Single race result: %d.\n", rSing.total)
|
||||||
|
}
|
||||||
366
day07/cards.go
Normal file
366
day07/cards.go
Normal file
@ -0,0 +1,366 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var mapSeedsFirst = map[string]int{
|
||||||
|
"A": 12,
|
||||||
|
"K": 11,
|
||||||
|
"Q": 10,
|
||||||
|
"J": 9,
|
||||||
|
"T": 8,
|
||||||
|
"9": 7,
|
||||||
|
"8": 6,
|
||||||
|
"7": 5,
|
||||||
|
"6": 4,
|
||||||
|
"5": 3,
|
||||||
|
"4": 2,
|
||||||
|
"3": 1,
|
||||||
|
"2": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
var mapSeedsSecond = map[string]int{
|
||||||
|
"A": 12,
|
||||||
|
"K": 11,
|
||||||
|
"Q": 10,
|
||||||
|
"T": 9,
|
||||||
|
"9": 8,
|
||||||
|
"8": 7,
|
||||||
|
"7": 6,
|
||||||
|
"6": 5,
|
||||||
|
"5": 4,
|
||||||
|
"4": 3,
|
||||||
|
"3": 2,
|
||||||
|
"2": 1,
|
||||||
|
"J": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
ranks []int
|
||||||
|
// 0: High card, 1: One pair, 2: Two pair, 3: Three of a kind
|
||||||
|
// 4: Full house, 5: Four of a kind, 6: Five of a kind
|
||||||
|
typeOfHand [7][]string
|
||||||
|
indexOfHand [7][]int
|
||||||
|
baseThirteen [7][]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) ChangeBase(hType, index int, mapSeeds map[string]int, wg *sync.WaitGroup) {
|
||||||
|
// Starting from the first char [0], we create the base13 num
|
||||||
|
chars := len(g.typeOfHand[hType][index])
|
||||||
|
baseTN := g.typeOfHand[hType][index]
|
||||||
|
decNum := 0
|
||||||
|
for i := 0; i < chars; i++ {
|
||||||
|
// This should be refactored to be a bit more legible
|
||||||
|
// It just computes N * 13^i and adds it over
|
||||||
|
decNum += int(float64(mapSeeds[string(baseTN[i])]) * math.Pow(13, float64(chars-i)))
|
||||||
|
}
|
||||||
|
g.baseThirteen[hType][index] = decNum
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) AnalyzeMap(cards string, index, mapSize, offset int) {
|
||||||
|
// The offset defaults to 0 for the regular game
|
||||||
|
// it is +1 for a game with Jokers\
|
||||||
|
mapSeed := mapSeedsFirst
|
||||||
|
if offset != 0 {
|
||||||
|
mapSeed = mapSeedsSecond
|
||||||
|
}
|
||||||
|
switch mapSize {
|
||||||
|
// Five of a kind
|
||||||
|
case 1:
|
||||||
|
g.mu.Lock()
|
||||||
|
g.typeOfHand[6] = append(g.typeOfHand[6], cards)
|
||||||
|
g.indexOfHand[6] = append(g.indexOfHand[6], index)
|
||||||
|
g.mu.Unlock()
|
||||||
|
// Four of a kind || Full House
|
||||||
|
case 2:
|
||||||
|
i := FullOrFour(cards, offset, mapSeed)
|
||||||
|
g.mu.Lock()
|
||||||
|
g.typeOfHand[i] = append(g.typeOfHand[i], cards)
|
||||||
|
g.indexOfHand[i] = append(g.indexOfHand[i], index)
|
||||||
|
g.mu.Unlock()
|
||||||
|
// Three of a kind || Two pair
|
||||||
|
case 3:
|
||||||
|
i := ThreeOrTwo(cards, offset, mapSeed)
|
||||||
|
g.mu.Lock()
|
||||||
|
g.typeOfHand[i] = append(g.typeOfHand[i], cards)
|
||||||
|
g.indexOfHand[i] = append(g.indexOfHand[i], index)
|
||||||
|
g.mu.Unlock()
|
||||||
|
// One pair
|
||||||
|
case 4:
|
||||||
|
g.mu.Lock()
|
||||||
|
g.typeOfHand[1] = append(g.typeOfHand[1], cards)
|
||||||
|
g.indexOfHand[1] = append(g.indexOfHand[1], index)
|
||||||
|
g.mu.Unlock()
|
||||||
|
// High card
|
||||||
|
case 5:
|
||||||
|
g.mu.Lock()
|
||||||
|
g.typeOfHand[0] = append(g.typeOfHand[0], cards)
|
||||||
|
g.indexOfHand[0] = append(g.indexOfHand[0], index)
|
||||||
|
g.mu.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) DetermineType(cards string, index int, wg *sync.WaitGroup) {
|
||||||
|
// We create a map and we check the length. Depending on the length, we
|
||||||
|
// insert the string in a specific type
|
||||||
|
m := make(map[string]int)
|
||||||
|
for i := 0; i < len(cards); i++ {
|
||||||
|
key := string(cards[i])
|
||||||
|
m[key] = mapSeedsFirst[key]
|
||||||
|
}
|
||||||
|
// Now, depending on the number of elements in the map, we can assign
|
||||||
|
// append cards to a specific rank
|
||||||
|
mapSize := len(m)
|
||||||
|
g.AnalyzeMap(cards, index, mapSize, 0)
|
||||||
|
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) SecondGame(cards string, index int, wg *sync.WaitGroup) {
|
||||||
|
// If I don't have Js, run the standard DetermineType
|
||||||
|
m := make(map[string]int)
|
||||||
|
n := make(map[string]int)
|
||||||
|
for i := 0; i < len(cards); i++ {
|
||||||
|
key := string(cards[i])
|
||||||
|
// We need to track the number of Js
|
||||||
|
m[key] += 1
|
||||||
|
// This is to track the type of hand, knowing the number of Js
|
||||||
|
n[key] = mapSeedsSecond[key]
|
||||||
|
}
|
||||||
|
mapSize := len(n)
|
||||||
|
switch m["J"] {
|
||||||
|
case 0:
|
||||||
|
// We have a hand without Js
|
||||||
|
wg.Add(1)
|
||||||
|
g.DetermineType(cards, index, wg)
|
||||||
|
case 1:
|
||||||
|
// If there is a J, J can be use is not adding information, therefore -1
|
||||||
|
g.AnalyzeMap(cards, index, (mapSize - 1), 1)
|
||||||
|
case 2:
|
||||||
|
g.AnalyzeMap(cards, index, (mapSize - 1), 2)
|
||||||
|
case 3:
|
||||||
|
g.AnalyzeMap(cards, index, (mapSize - 1), 3)
|
||||||
|
case 4:
|
||||||
|
g.AnalyzeMap(cards, index, (mapSize - 1), 4)
|
||||||
|
case 5:
|
||||||
|
wg.Add(1)
|
||||||
|
g.DetermineType(cards, index, wg)
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ThreeOrTwo(cards string, offset int, mapSeed map[string]int) int {
|
||||||
|
m := make(map[string]int)
|
||||||
|
for i := 0; i < len(cards); i++ {
|
||||||
|
key := string(cards[i])
|
||||||
|
m[key] += 1
|
||||||
|
}
|
||||||
|
// If we are in the second game, remove J
|
||||||
|
if mapSeed["J"] == 0 {
|
||||||
|
m["J"] = 0
|
||||||
|
}
|
||||||
|
// m[i] returns 0 if the element is not in the map. I take advantage
|
||||||
|
// of that
|
||||||
|
tempNum := 0
|
||||||
|
for i := range mapSeed {
|
||||||
|
if m[i] > tempNum {
|
||||||
|
tempNum = m[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If an element has 3 values, we have a three of a kind
|
||||||
|
if tempNum+offset == 3 {
|
||||||
|
return 3
|
||||||
|
/// If an element has 2 values, we have a two pair
|
||||||
|
} else if tempNum+offset == 2 {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
PrintAndWait("This has run for ", cards)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
func FullOrFour(cards string, offset int, mapSeed map[string]int) int {
|
||||||
|
m := make(map[string]int)
|
||||||
|
for i := 0; i < len(cards); i++ {
|
||||||
|
key := string(cards[i])
|
||||||
|
m[key] += 1
|
||||||
|
}
|
||||||
|
// If we are in the second game, remove J
|
||||||
|
if mapSeed["J"] == 0 {
|
||||||
|
m["J"] = 0
|
||||||
|
}
|
||||||
|
// m[i] returns 0 if the element is not in the map. I take advantage
|
||||||
|
// of that
|
||||||
|
// Better to save the maximum number
|
||||||
|
tempNum := 0
|
||||||
|
for i := range mapSeed {
|
||||||
|
if m[i] > tempNum {
|
||||||
|
tempNum = m[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If an element has four values, we have a Four of a kind
|
||||||
|
if tempNum+offset == 4 {
|
||||||
|
return 5
|
||||||
|
/// If an element has 3 values, we have a Full House
|
||||||
|
} else if tempNum+offset == 3 {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://www.golangprograms.com/golang-program-for-implementation-of-quick-sort.html
|
||||||
|
// I need to learn how this shing works
|
||||||
|
func quicksort(a, h []int, hType int) []int {
|
||||||
|
if len(a) < 2 {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
left, right := 0, len(a)-1
|
||||||
|
|
||||||
|
pivot := 0
|
||||||
|
|
||||||
|
a[pivot], a[right] = a[right], a[pivot]
|
||||||
|
h[pivot], h[right] = h[right], h[pivot]
|
||||||
|
|
||||||
|
for i, _ := range a {
|
||||||
|
if a[i] < a[right] {
|
||||||
|
a[left], a[i] = a[i], a[left]
|
||||||
|
h[left], h[i] = h[i], h[left]
|
||||||
|
left++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a[left], a[right] = a[right], a[left]
|
||||||
|
h[left], h[right] = h[right], h[left]
|
||||||
|
|
||||||
|
quicksort(a[:left], h[:left], hType)
|
||||||
|
quicksort(a[left+1:], h[left+1:], hType)
|
||||||
|
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
file, err := os.Open("./inputs/day07_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
// Struct for regular game
|
||||||
|
g := Game{}
|
||||||
|
// Struct for the Joker game
|
||||||
|
jo := Game{}
|
||||||
|
|
||||||
|
// Variable where we store every line in the file
|
||||||
|
lines := make([]string, 0)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
// Array of strings, set of cards
|
||||||
|
var cards []string
|
||||||
|
// Array of int, bet
|
||||||
|
var bet []int
|
||||||
|
// Now, split the lines
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
tempString := strings.Split(lines[i], " ")
|
||||||
|
cards = append(cards, tempString[0])
|
||||||
|
tempNum, _ := strconv.Atoi(tempString[1])
|
||||||
|
bet = append(bet, tempNum)
|
||||||
|
}
|
||||||
|
// Rank will be from 1 to len(lines)
|
||||||
|
g.ranks = make([]int, len(lines))
|
||||||
|
jo.ranks = make([]int, len(lines))
|
||||||
|
// What do we know for sure? 5 identical seeds are the highest ranks,
|
||||||
|
// 5 completely different seeds are the lowest ranks.
|
||||||
|
// We can iterate for every set of cards, and do different things
|
||||||
|
// if the map we build has one element, five elements or the worst
|
||||||
|
// case (two, three or four elements).
|
||||||
|
//
|
||||||
|
// Two identical: 4oK or FH
|
||||||
|
// Three identical: 3oK or 22
|
||||||
|
// Four identical: 12
|
||||||
|
//
|
||||||
|
// With this, I put every typeOfHand in a different array
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(2 * len(lines))
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
g.DetermineType(cards[i], i, &wg)
|
||||||
|
jo.SecondGame(cards[i], i, &wg)
|
||||||
|
}
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
// Now that g.typeOfHand has every type of hand separated, the rank
|
||||||
|
// is determined by the first card(s). I can convert every number
|
||||||
|
// to a base 13 representation and sort.
|
||||||
|
// In g.indexOfHand I have the index of the corresponding type.
|
||||||
|
|
||||||
|
// For every type of hand
|
||||||
|
for i := range g.typeOfHand {
|
||||||
|
// As many wait groups as the element we will iterate
|
||||||
|
wg.Add(len(g.typeOfHand[i]))
|
||||||
|
wg.Add(len(jo.typeOfHand[i]))
|
||||||
|
// We also need to initialize the array g.baseThirteen so we can
|
||||||
|
// keep the same index
|
||||||
|
g.baseThirteen[i] = make([]int, len(g.typeOfHand[i]))
|
||||||
|
jo.baseThirteen[i] = make([]int, len(jo.typeOfHand[i]))
|
||||||
|
// For every element in a single type of hand
|
||||||
|
for j := range g.typeOfHand[i] {
|
||||||
|
g.ChangeBase(i, j, mapSeedsFirst, &wg)
|
||||||
|
}
|
||||||
|
for j := range jo.typeOfHand[i] {
|
||||||
|
jo.ChangeBase(i, j, mapSeedsSecond, &wg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
// A sort of some kind. Important is to also move the index with the number as
|
||||||
|
// well.
|
||||||
|
for i := range g.baseThirteen {
|
||||||
|
quicksort(g.baseThirteen[i], g.indexOfHand[i], i)
|
||||||
|
quicksort(jo.baseThirteen[i], jo.indexOfHand[i], i)
|
||||||
|
}
|
||||||
|
|
||||||
|
curRank := 1
|
||||||
|
rank := 0
|
||||||
|
// Iter every array
|
||||||
|
for i := range g.typeOfHand {
|
||||||
|
for j := range g.typeOfHand[i] {
|
||||||
|
index := g.indexOfHand[i][j]
|
||||||
|
rank += curRank * bet[index]
|
||||||
|
curRank++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Rank: %d\n", rank)
|
||||||
|
|
||||||
|
curRank = 1
|
||||||
|
rank = 0
|
||||||
|
// Iter every array
|
||||||
|
for i := range jo.typeOfHand {
|
||||||
|
for j := range jo.typeOfHand[i] {
|
||||||
|
index := jo.indexOfHand[i][j]
|
||||||
|
rank += curRank * bet[index]
|
||||||
|
curRank++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("Rank: %d\n", rank)
|
||||||
|
|
||||||
|
}
|
||||||
1
day07/inputs
Symbolic link
1
day07/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
233
day08/charpath.go
Normal file
233
day08/charpath.go
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const LEFT = 'L'
|
||||||
|
|
||||||
|
type Nodes struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
commands []int32
|
||||||
|
singleN []int32
|
||||||
|
leftN []int32
|
||||||
|
rightN []int32
|
||||||
|
index int
|
||||||
|
steps uint64
|
||||||
|
allSteps []int
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://siongui.github.io/2017/06/03/go-find-lcm-by-gcd/
|
||||||
|
// greatest common divisor (GCD) via Euclidean algorithm
|
||||||
|
func GCD(a, b int) int {
|
||||||
|
for b != 0 {
|
||||||
|
t := b
|
||||||
|
b = a % b
|
||||||
|
a = t
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// find Least Common Multiple (LCM) via GCD
|
||||||
|
func LCM(a, b int, integers ...int) int {
|
||||||
|
result := a * b / GCD(a, b)
|
||||||
|
|
||||||
|
for i := 0; i < len(integers); i++ {
|
||||||
|
result = LCM(result, integers[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) toByteSingle(s string) {
|
||||||
|
// I've just received something like AAA
|
||||||
|
var temp int32
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
a := int32(s[i])
|
||||||
|
temp += a << ((len(s) - 1 - i) * 8)
|
||||||
|
}
|
||||||
|
n.singleN = append(n.singleN, temp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) toByteDuet(s, r string) {
|
||||||
|
// I've just received something like AAA BBB
|
||||||
|
var tempL, tempR int32
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
tempL += int32(s[i]) << ((len(s) - 1 - i) * 8)
|
||||||
|
tempR += int32(r[i]) << ((len(s) - 1 - i) * 8)
|
||||||
|
}
|
||||||
|
n.leftN = append(n.leftN, tempL)
|
||||||
|
n.rightN = append(n.rightN, tempR)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) findNext(myN int32) int {
|
||||||
|
//var wg sync.WaitGroup
|
||||||
|
ind := 0
|
||||||
|
for i := 0; i < len(n.singleN); i++ {
|
||||||
|
if myN^n.singleN[i] == 0 {
|
||||||
|
n.mu.Lock()
|
||||||
|
n.index = i
|
||||||
|
n.mu.Unlock()
|
||||||
|
ind = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ind
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Nodes) findAll(ind int, sp []int, wg *sync.WaitGroup) {
|
||||||
|
index := 0
|
||||||
|
// We only go from the start
|
||||||
|
matching := n.rightN[sp[ind]]
|
||||||
|
if n.commands[0]^LEFT == 0 {
|
||||||
|
matching = n.leftN[sp[ind]]
|
||||||
|
}
|
||||||
|
index = n.findNext(matching)
|
||||||
|
n.allSteps[ind]++
|
||||||
|
i := 0
|
||||||
|
for {
|
||||||
|
// Every step is in a single direction. For every step, we may need to
|
||||||
|
// scan len(n.singleN) elements.
|
||||||
|
// Circular loop
|
||||||
|
index = n.findNext(matching)
|
||||||
|
// Increment i after finding the match
|
||||||
|
i++
|
||||||
|
i = i % len(n.commands)
|
||||||
|
// By default, we will assume we are on the right
|
||||||
|
matching = n.rightN[index]
|
||||||
|
//PrintAndWait()
|
||||||
|
// If we are not, we are in the left
|
||||||
|
if n.commands[i]^LEFT == 0 {
|
||||||
|
matching = n.leftN[index]
|
||||||
|
}
|
||||||
|
n.allSteps[ind]++
|
||||||
|
// If we find XXZ, end
|
||||||
|
temp := matching & 255
|
||||||
|
if temp ^ 'Z' == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//fmt.Printf("I started from %d, matched at %d, taking %d steps.\n", sp[ind], index, n.allSteps[ind] )
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func timer(name string) func() {
|
||||||
|
start := time.Now()
|
||||||
|
return func() {
|
||||||
|
fmt.Printf("%s took %v\n", name, time.Since(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer timer ("main")()
|
||||||
|
file, err := os.Open("./inputs/day08_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
// Struct with my node
|
||||||
|
n := Nodes{}
|
||||||
|
// Prepare the regex
|
||||||
|
repath := regexp.MustCompile("([A-Z]{3})")
|
||||||
|
// Build the END
|
||||||
|
var END = 'Z'
|
||||||
|
END += ('Z' << 8)
|
||||||
|
END += ('Z' << 16)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
scanner.Scan()
|
||||||
|
// First line, RL commands
|
||||||
|
strCommands := scanner.Text()
|
||||||
|
// Get every char inside the string just obtained
|
||||||
|
for i := 0; i < len(strCommands); i++ {
|
||||||
|
n.commands = append(n.commands, int32(strCommands[i]))
|
||||||
|
}
|
||||||
|
// One empty line
|
||||||
|
scanner.Scan()
|
||||||
|
// X = (Y, Z)
|
||||||
|
// We regex this one
|
||||||
|
for scanner.Scan() {
|
||||||
|
tempNodes := repath.FindAllString(scanner.Text(), -1)
|
||||||
|
n.toByteSingle(tempNodes[0])
|
||||||
|
n.toByteDuet(tempNodes[1], tempNodes[2])
|
||||||
|
}
|
||||||
|
// We start from 0, we find the match
|
||||||
|
// Let's start an infinite loop
|
||||||
|
// Circular index
|
||||||
|
i := 0
|
||||||
|
// We start from the AAA element
|
||||||
|
START := 'A'
|
||||||
|
START += ('A' << 8)
|
||||||
|
START += ('A' << 16)
|
||||||
|
matching := START
|
||||||
|
// Store where AAA is
|
||||||
|
n.findNext(matching)
|
||||||
|
// By default, we will assume we are on the right
|
||||||
|
// If we are not, we are in the left
|
||||||
|
matching = n.rightN[n.index]
|
||||||
|
if n.commands[i]^LEFT == 0 {
|
||||||
|
matching = n.leftN[n.index]
|
||||||
|
}
|
||||||
|
n.steps++
|
||||||
|
// Infinite loop
|
||||||
|
for {
|
||||||
|
// Every step is in a single direction. For every step, we may need to
|
||||||
|
// scan len(n.singleN) elements.
|
||||||
|
// Circular loop
|
||||||
|
n.findNext(matching)
|
||||||
|
// Increment i after finding the match
|
||||||
|
i++
|
||||||
|
i = i % len(n.commands)
|
||||||
|
// By default, we will assume we are on the right
|
||||||
|
matching = n.rightN[n.index]
|
||||||
|
//PrintAndWait()
|
||||||
|
// If we are not, we are in the left
|
||||||
|
if n.commands[i]^LEFT == 0 {
|
||||||
|
matching = n.leftN[n.index]
|
||||||
|
}
|
||||||
|
n.steps++
|
||||||
|
// If we find ZZZ, end
|
||||||
|
if matching^END == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Printf("\nSteps: %d\n", n.steps)
|
||||||
|
// Now, for the main event
|
||||||
|
// Let's get ready to rumble
|
||||||
|
startPoints := make([]int, 0)
|
||||||
|
for i := 0; i < len(n.singleN); i++ {
|
||||||
|
// Lets remove all bytes except last 8
|
||||||
|
temp := n.singleN[i] & 255
|
||||||
|
if (temp ^ 'A') == 0 {
|
||||||
|
startPoints = append(startPoints, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now, from the starting points, we should go and match until
|
||||||
|
// we find a path that ends in Z
|
||||||
|
n.allSteps = make([]int, len(startPoints))
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i := 0; i < len(startPoints); i++ {
|
||||||
|
wg.Add(1)
|
||||||
|
go n.findAll(i, startPoints, &wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
result := 1
|
||||||
|
for i := 0; i < len(n.allSteps); i++ {
|
||||||
|
result = LCM(result, n.allSteps[i])
|
||||||
|
}
|
||||||
|
fmt.Printf("Steps: %d\n", result)
|
||||||
|
}
|
||||||
1
day08/inputs
Symbolic link
1
day08/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
1
day09/inputs
Symbolic link
1
day09/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
149
day09/oasis.go
Normal file
149
day09/oasis.go
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import(
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"bufio"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parallel code, global vars
|
||||||
|
type Series struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
numStore [][]int
|
||||||
|
total uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
// use defer timer("funcname")() when the function you want to
|
||||||
|
// test starts
|
||||||
|
func timer(name string) func() {
|
||||||
|
start := time.Now()
|
||||||
|
return func() {
|
||||||
|
fmt.Printf("%s took %v\n", name, time.Since(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PredictValueBack(numbers []int) []int {
|
||||||
|
// Are we finished? By default, true
|
||||||
|
temp := true
|
||||||
|
for i := 0; i < len(numbers); i++ {
|
||||||
|
if numbers[i] != 0 {
|
||||||
|
temp = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check to end recursion
|
||||||
|
if temp == true {
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
newNums := make([]int, len(numbers) - 1)
|
||||||
|
for i := 0; i < len(numbers) - 1; i++ {
|
||||||
|
newNums[i] = numbers[i + 1] - numbers[i]
|
||||||
|
}
|
||||||
|
myNums := PredictValueBack(newNums)
|
||||||
|
addValue := newNums[0] - myNums[0]
|
||||||
|
// We need to append at the start
|
||||||
|
newNums = append([]int{addValue}, newNums...)
|
||||||
|
return newNums
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ser *Series) CallPredictBack(numbers []int, wg *sync.WaitGroup) {
|
||||||
|
tempNum := PredictValueBack(numbers)
|
||||||
|
ser.mu.Lock()
|
||||||
|
ser.total += uint64(numbers[0] - tempNum[0])
|
||||||
|
ser.mu.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func PredictValue(numbers []int) []int {
|
||||||
|
// Are we finished? By default, true
|
||||||
|
temp := true
|
||||||
|
for i := 0; i < len(numbers); i++ {
|
||||||
|
if numbers[i] != 0 {
|
||||||
|
temp = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check to end recursion
|
||||||
|
if temp == true {
|
||||||
|
return numbers
|
||||||
|
}
|
||||||
|
|
||||||
|
newNums := make([]int, len(numbers) - 1)
|
||||||
|
for i := 0; i < len(numbers) - 1; i++ {
|
||||||
|
newNums[i] = numbers[i + 1] - numbers[i]
|
||||||
|
}
|
||||||
|
myNums := PredictValue(newNums)
|
||||||
|
addValue := myNums[len(myNums) - 1]
|
||||||
|
newNums = append(newNums, newNums[len(newNums) - 1] + addValue)
|
||||||
|
return newNums
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ser *Series) CallPredict(numbers []int, wg *sync.WaitGroup) {
|
||||||
|
tempNum := PredictValue(numbers)
|
||||||
|
lt := len(tempNum) - 1
|
||||||
|
ln := len(numbers) - 1
|
||||||
|
ser.mu.Lock()
|
||||||
|
ser.total += uint64(numbers[ln] + tempNum[lt])
|
||||||
|
ser.mu.Unlock()
|
||||||
|
wg.Done()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
defer timer("main")()
|
||||||
|
file, err := os.Open("./inputs/day09_input")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
|
||||||
|
renum := regexp.MustCompile("(\\-[0-9]+|[0-9]+)")
|
||||||
|
|
||||||
|
ser := Series{ total: 0, }
|
||||||
|
|
||||||
|
lines := make([]string, 0)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
ser.numStore = make([][]int, len(lines))
|
||||||
|
for i := 0; i < len(lines); i++ {
|
||||||
|
temp := renum.FindAllString(lines[i], -1)
|
||||||
|
for j := 0; j < len(temp); j++ {
|
||||||
|
num, err := strconv.Atoi(temp[j])
|
||||||
|
check(err)
|
||||||
|
ser.numStore[i] = append(ser.numStore[i], num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Now I have a 2D array with all the numbers, I can start RECURSING
|
||||||
|
wg.Add(len(ser.numStore))
|
||||||
|
for i := 0; i < len(ser.numStore); i++ {
|
||||||
|
go ser.CallPredict(ser.numStore[i], &wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
fmt.Printf("%d\n", ser.total)
|
||||||
|
|
||||||
|
ser.total = 0
|
||||||
|
wg.Add(len(ser.numStore))
|
||||||
|
for i := 0; i < len(ser.numStore); i++ {
|
||||||
|
go ser.CallPredictBack(ser.numStore[i], &wg)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
fmt.Printf("%d\n", ser.total)
|
||||||
|
|
||||||
|
}
|
||||||
1
day10/inputs
Symbolic link
1
day10/inputs
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../inputs
|
||||||
48
day10/maze.go
Normal file
48
day10/maze.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Parallel code, global vars
|
||||||
|
type Nodes struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
variable int
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
|
||||||
|
// use defer timer("funcname")() when the function you want to
|
||||||
|
// test starts
|
||||||
|
func timer(name string) func() {
|
||||||
|
start := time.Now()
|
||||||
|
return func() {
|
||||||
|
fmt.Printf("%s took %v\n", name, time.Since(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open("./inputs")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
lines := make([]string, 0)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
}
|
||||||
42
template.go
Normal file
42
template.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import()
|
||||||
|
|
||||||
|
// Parallel code, global vars
|
||||||
|
type Nodes struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
variable type
|
||||||
|
}
|
||||||
|
|
||||||
|
func check(e error) {
|
||||||
|
if e != nil {
|
||||||
|
panic(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func PrintAndWait(x ...any) {
|
||||||
|
fmt.Print(x...)
|
||||||
|
fmt.Scanln()
|
||||||
|
}
|
||||||
|
// use defer timer("funcname")() when the function you want to
|
||||||
|
// test starts
|
||||||
|
func timer(name string) func() {
|
||||||
|
start := time.Now()
|
||||||
|
return func() {
|
||||||
|
fmt.Printf("%s took %v\n", name, time.Since(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
file, err := os.Open("./inputs")
|
||||||
|
check(err)
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
lines := make([]string, 0)
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
lines = append(lines, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user