Big update: Adding all advent of codes to same repo

This commit is contained in:
2024-12-06 00:14:09 +00:00
parent 5116bd4696
commit 233dda4fe9
106 changed files with 7790 additions and 0 deletions

View File

@ -0,0 +1,14 @@
# Advent Of Code 2015
I started doing AoC puzzles in 2020. I have a few more days to finish in 2020, but I wanted to start on 2015 as a way to learn more about Golang.
A language which I want to properly learn, and this is a brilliant way of doing just that.
## Day 6
Brute forced solution, it would be good to get a real solution which takes less than a few milliseconds.
## Day 7
Partial solution, misread the instructions, need to rethink it entirely. I actually wrote an emulator for the second set of example instructions
## Day 8
Just started it, not finished as I have to do something else right now.
- Finished it, solution takes less than 1ms to complete. Could have finished it much quicker if I didn't forget to add regular characters onto the end result.

View File

@ -0,0 +1,39 @@
package main
import (
"fmt"
"io/ioutil"
"time"
)
func main() {
fmt.Println("Day 1")
start := time.Now()
dat, err := ioutil.ReadFile("day1.txt")
if err != nil {
panic(err)
}
var floor int64 = 0
basement := -1
for i, value := range dat {
if basement == -1 && floor == -1 {
basement = i
}
if value == 40 {
floor++
} else if value == 41 {
floor--
}
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", floor, elapsed)
fmt.Printf("Part 2: %v %v", basement, elapsed)
}

View File

@ -0,0 +1,49 @@
package main
import (
"fmt"
"strconv"
"time"
)
func main() {
fmt.Println("Day 9")
start := time.Now()
inputString := "1113122113"
input := []int64{}
for _, c := range inputString {
stringChar, _ := strconv.Atoi(string(c))
input = append(input, int64(stringChar))
}
//Change 40 to 50 for part 2
for rounds := 0; rounds < 40; rounds++ {
lastNum := input[0]
var counter int64 = 1
newNumbers := []int64{}
for i := 1; i < len(input); i++ {
if input[i] != lastNum {
newNumbers = append(newNumbers, counter)
newNumbers = append(newNumbers, lastNum)
counter = 1
lastNum = input[i]
} else {
counter++
}
}
newNumbers = append(newNumbers, counter)
newNumbers = append(newNumbers, lastNum)
input = newNumbers
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", len(input), elapsed)
fmt.Printf("Part 2: %v %v \n", len(input), elapsed)
}

View File

@ -0,0 +1,64 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"time"
)
func main() {
fmt.Println("Day 12")
start := time.Now()
dat, err := ioutil.ReadFile("day12.json")
if err != nil {
panic(err)
}
var result map[string]interface{}
json.Unmarshal(dat, &result)
fmt.Printf("Input: %v | %T \n", result, result)
var count float64 = solver(result)
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", count, elapsed)
}
func solver(json map[string]interface{}) float64 {
var counter float64
for _, value := range json {
switch valueType := value.(type) {
case bool:
case float64:
counter += valueType
case string:
case []interface{}:
counter += interfaceArraySolver(valueType)
case map[string]interface{}:
counter += solver(valueType)
}
}
return counter
}
func interfaceArraySolver(json []interface{}) float64 {
var counter float64
for _, value := range json {
switch valueType := value.(type) {
case bool:
case float64:
counter += valueType
case string:
case []interface{}:
counter += interfaceArraySolver(valueType)
case map[string]interface{}:
counter += solver(valueType)
}
}
return counter
}

View File

@ -0,0 +1,55 @@
const fs = require('fs');
const obj = JSON.parse(fs.readFileSync('day12.json', 'utf8'));
console.log("Part 1: " + solver(obj));
console.log("Part 2: ", + solverPart2(obj));
function solver(json) {
let counter = 0;
for (let value in json) {
if (typeof json[value] == 'number') {
counter += json[value]
} else if (typeof json[value] == 'boolean') {
} else if (typeof json[value] == 'string') {
} else if (typeof json[value] == 'object') {
counter += solver(json[value]);
}
}
return counter;
}
function solverPart2(json) {
let counter = 0;
let redFound = false;
let toSolver = [];
for (let value in json) {
if (typeof json[value] == 'number') {
counter += json[value]
} else if (typeof json[value] == 'boolean') {
} else if (typeof json[value] == 'string') {
if (json[value] == 'red' && !Array.isArray(json)) {
redFound = true;
break;
}
} else if (typeof json[value] == 'object') {
toSolver.push(json[value]);
}
}
if (redFound) {
return 0;
} else {
for (let e of toSolver) {
counter += solverPart2(e);
}
return counter;
}
}

View File

@ -0,0 +1,143 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"strconv"
"strings"
"time"
)
type Combination struct {
subject string
nextTo string
}
type Average struct {
person1 string
person2 string
average int
}
func main() {
fmt.Println("Day 13")
start := time.Now()
dat, err := ioutil.ReadFile("day13.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
combinationMap := make(map[Combination]int)
people := make([]string, 0)
for _, line := range lines {
stringLine := string(line)
stringLine = stringLine[:len(stringLine)-1]
lineWordArray := strings.Split(string(stringLine), " ")
gained, _ := strconv.Atoi(lineWordArray[3])
if !contains(people, lineWordArray[0]) {
people = append(people, lineWordArray[0])
}
if lineWordArray[2] == "lose" {
gained = -gained
}
combinationMap[Combination{subject: lineWordArray[0], nextTo: lineWordArray[10]}] = gained
}
averageCombinations := make([]Average, 0)
for _, person := range people {
for i := 0; i < len(people); i++ {
nextPerson := people[i]
if nextPerson != person {
average := combinationMap[Combination{subject: person, nextTo: nextPerson}] + combinationMap[Combination{subject: nextPerson, nextTo: person}]
averageCombinations = append(averageCombinations, Average{person1: person, person2: nextPerson, average: average})
}
}
}
startingPerson := people[0]
remaining := make([]string, 0)
for _, value := range people {
if value != startingPerson {
remaining = append(remaining, value)
}
}
part1 := travellingSalesMan(averageCombinations, startingPerson, startingPerson, remaining)
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", part1, elapsed)
start = time.Now()
for _, person := range people {
averageCombinations = append(averageCombinations, Average{person1: "me", person2: person, average: 0})
averageCombinations = append(averageCombinations, Average{person1: person, person2: "me", average: 0})
}
people = append(people, "me")
startingPerson = people[0]
remaining = make([]string, 0)
for _, value := range people {
if value != startingPerson {
remaining = append(remaining, value)
}
}
part2 := travellingSalesMan(averageCombinations, startingPerson, startingPerson, remaining)
elapsed = time.Since(start)
fmt.Printf("Part 2: %v %v \n", part2, elapsed)
}
func travellingSalesMan(averages []Average, startingPerson string, currentPerson string, remainingPeople []string) int {
//*Needs to return to the beginning
if len(remainingPeople) == 0 {
return getAverage(averages, startingPerson, currentPerson)
} else {
distances := make([]int, 0)
for _, person := range remainingPeople {
newRemaining := make([]string, 0)
for _, p := range remainingPeople {
if p != person {
newRemaining = append(newRemaining, p)
}
}
distances = append(distances, getAverage(averages, currentPerson, person)+travellingSalesMan(averages, startingPerson, person, newRemaining))
}
max := 0
for _, value := range distances {
if value > max {
max = value
}
}
return max
}
}
func contains(array []string, person string) bool {
for _, v := range array {
if v == person {
return true
}
}
return false
}
func getAverage(array []Average, person1 string, person2 string) int {
for _, p := range array {
if p.person1 == person1 && p.person2 == person2 {
return p.average
}
}
return 0
}

View File

@ -0,0 +1,89 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"strconv"
"strings"
"time"
)
func main() {
fmt.Println("Day 13")
start := time.Now()
dat, err := ioutil.ReadFile("day14.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
part1 := 0
total := 2503
for _, line := range lines {
stringLine := string(line)
splitLine := strings.Split(stringLine, " ")
v, _ := strconv.Atoi(splitLine[3])
s, _ := strconv.Atoi(splitLine[6])
r, _ := strconv.Atoi(splitLine[13])
currentDistance := (total / (s + r)) * v * s
remaining := total % (s + r)
if remaining >= s {
currentDistance += v * s
} else {
currentDistance += v * remaining
}
if currentDistance > part1 {
part1 = currentDistance
}
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", part1, elapsed)
start = time.Now()
horses := make(map[int]int)
for i := 1; i <= total; i++ {
longest := 0
fastestHorse := 0
for index, line := range lines {
stringLine := string(line)
splitLine := strings.Split(stringLine, " ")
v, _ := strconv.Atoi(splitLine[3])
s, _ := strconv.Atoi(splitLine[6])
r, _ := strconv.Atoi(splitLine[13])
currentDistance := (i / (s + r)) * v * s
remaining := i % (s + r)
if remaining >= s {
currentDistance += v * s
} else {
currentDistance += v * remaining
}
if currentDistance > longest {
longest = currentDistance
fastestHorse = index
}
}
horses[fastestHorse] = horses[fastestHorse] + 1
}
fastest := 0
for _, value := range horses {
if value > fastest {
fastest = value
}
}
elapsed = time.Since(start)
fmt.Printf("Part 2: %v %v \n", fastest, elapsed)
}

View File

@ -0,0 +1,93 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"strconv"
"strings"
)
func main() {
fmt.Println("Day 15")
dat, err := ioutil.ReadFile("day15.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
ingredients := make([][]int, 4)
for i := range ingredients {
ingredients[i] = make([]int, 5)
}
for index, line := range lines {
stringLine := string(line)
splitString := strings.Split(stringLine, " ")
ingredients[index][0], _ = strconv.Atoi(strings.TrimRight(splitString[2], ","))
ingredients[index][1], _ = strconv.Atoi(strings.TrimRight(splitString[4], ","))
ingredients[index][2], _ = strconv.Atoi(strings.TrimRight(splitString[6], ","))
ingredients[index][3], _ = strconv.Atoi(strings.TrimRight(splitString[8], ","))
ingredients[index][4], _ = strconv.Atoi(splitString[10])
}
best := 0
part2 := 0
for a := 0; a <= 100; a++ {
for b := 0; b <= 100-a; b++ {
for c := 0; c <= 100-a-b; c++ {
for d := 0; d <= 100-a-b-c; d++ {
calculation := calc_cookie(ingredients, a, b, c, d)
totalCalories := a*ingredients[0][4] + b*ingredients[1][4] + c*ingredients[2][4] + d*ingredients[3][4]
if calculation > best {
best = calculation
}
if totalCalories == 500 && calculation > part2 {
part2 = calculation
}
}
}
}
}
fmt.Println(best)
fmt.Println(part2)
}
func calc_cookie(ingredients [][]int, sprinkles int, peanut int, frosting int, sugar int) int {
capacity := sprinkles*ingredients[0][0] +
peanut*ingredients[1][0] +
frosting*ingredients[2][0] +
sugar*ingredients[3][0]
durability := sprinkles*ingredients[0][1] +
peanut*ingredients[1][1] +
frosting*ingredients[2][1] +
sugar*ingredients[3][1]
flavor := sprinkles*ingredients[0][2] +
peanut*ingredients[1][2] +
frosting*ingredients[2][2] +
sugar*ingredients[3][2]
texture := sprinkles*ingredients[0][3] +
peanut*ingredients[1][3] +
frosting*ingredients[2][3] +
sugar*ingredients[3][3]
if capacity <= 0 || durability <= 0 || flavor <= 0 || texture <= 0 {
return 0
} else {
return capacity * durability * flavor * texture
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,118 @@
import java.util.Scanner;
import java.io.FileNotFoundException;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) throws FileNotFoundException {
File myFile = new File("day16.txt");
Scanner in = new Scanner(myFile);
int index = 1;
while (in.hasNext()) {
String[] input = in.nextLine().replaceAll("\\s+", "").split(":");
Map<String, Integer> currentAunt = new HashMap<>();
String[] secondLineSplit = input[2].split(",");
String[] thirdLineSplit = input[3].split(",");
currentAunt.put(input[1], Integer.parseInt(secondLineSplit[0]));
currentAunt.put(secondLineSplit[1], Integer.parseInt(thirdLineSplit[0]));
currentAunt.put(thirdLineSplit[1], Integer.parseInt(input[4]));
int counter = 0;
int part2counter = 0;
for (String key : currentAunt.keySet()) {
switch (key) {
case "children":
if (currentAunt.get(key) == 3) {
counter++;
part2counter++;
}
break;
case "cats":
if (currentAunt.get(key) == 7) {
counter++;
}
if (currentAunt.get(key) > 7) {
part2counter++;
}
break;
case "samoyeds":
if (currentAunt.get(key) == 2) {
counter++;
part2counter++;
}
break;
case "pomeranians":
if (currentAunt.get(key) == 3) {
counter++;
}
if (currentAunt.get(key) < 3) {
part2counter++;
}
break;
case "akitas":
if (currentAunt.get(key) == 0) {
counter++;
part2counter++;
}
break;
case "vizslas":
if (currentAunt.get(key) == 0) {
counter++;
part2counter++;
}
break;
case "goldfish":
if (currentAunt.get(key) == 5) {
counter++;
}
if (currentAunt.get(key) < 5) {
part2counter++;
}
break;
case "trees":
if (currentAunt.get(key) == 3) {
counter++;
}
if (currentAunt.get(key) > 3) {
part2counter++;
}
break;
case "cars":
if (currentAunt.get(key) == 2) {
counter++;
part2counter++;
}
break;
case "perfumes":
if (currentAunt.get(key) == 1) {
counter++;
part2counter++;
}
break;
}
}
if (counter == 3) {
System.out.printf("Part 1: %d \n", index);
} else if (part2counter == 3) {
System.out.printf("Part 2: %d \n", index);
}
index++;
}
in.close();
}
}

View File

@ -0,0 +1,53 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"strconv"
"time"
)
func main() {
fmt.Println("Day 2")
start := time.Now()
dat, err := ioutil.ReadFile("day2.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
total := 0
totalPart2 := 0
for _, value := range lines {
splitLine := bytes.Split(value, []byte("x"))
l, _ := strconv.Atoi(string(splitLine[0]))
w, _ := strconv.Atoi(string(splitLine[1]))
h, _ := strconv.Atoi(string(splitLine[2]))
total += 2*l*w + 2*l*h + 2*w*h + MinOf(l*w, w*h, h*l)
totalPart2 += MinOf(l*2+w*2, w*2+h*2, h*2+l*2) + l*w*h
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", total, elapsed)
fmt.Printf("Part 2: %v %v", totalPart2, elapsed)
}
func MinOf(vars ...int) int {
min := vars[0]
for _, i := range vars {
if min > i {
min = i
}
}
return min
}

View File

@ -0,0 +1,69 @@
package main
import (
"fmt"
"io/ioutil"
"time"
)
type Coords struct {
x int
y int
}
func main() {
fmt.Println("Day 3")
start := time.Now()
dat, err := ioutil.ReadFile("day3.txt")
if err != nil {
panic(err)
}
position := Coords{x: 0, y: 0}
visited := make(map[Coords]int)
visited[position] = 1
for _, value := range dat {
solve(visited, &position, value)
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", len(visited), elapsed)
start = time.Now()
position = Coords{x: 0, y: 0}
visited = make(map[Coords]int)
visited[position] = 1
for i := 0; i < len(dat); i = i + 2 {
solve(visited, &position, dat[i])
}
position.x = 0
position.y = 0
for i := 1; i < len(dat); i = i + 2 {
solve(visited, &position, dat[i])
}
fmt.Printf("Part 2: %v %v", len(visited), elapsed)
}
func solve(visited map[Coords]int, position *Coords, value byte) {
if value == []byte("<")[0] {
position.x--
visited[*position]++
} else if value == []byte(">")[0] {
position.x++
visited[*position]++
} else if value == []byte("^")[0] {
position.y++
visited[*position]++
} else if value == []byte("v")[0] {
position.y--
visited[*position]++
}
}

View File

@ -0,0 +1,53 @@
package main
import (
"crypto/md5"
"fmt"
"io/ioutil"
"strconv"
"time"
)
type Coords struct {
x int
y int
}
func main() {
fmt.Println("Day 3")
start := time.Now()
dat, err := ioutil.ReadFile("day4.txt")
if err != nil {
panic(err)
}
input := string(dat)
part1 := ""
var hash [16]byte
for i := 1; part1 == ""; i++ {
hashString := input + strconv.Itoa(i)
hash = md5.Sum([]byte(hashString))
if hash[0] == 0x00 && hash[1] == 0x00 && hash[2] <= 0x0f {
part1 = hashString
}
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", part1, elapsed)
start = time.Now()
part2 := ""
for i := 1; part2 == ""; i++ {
hashString := input + strconv.Itoa(i)
hash = md5.Sum([]byte(hashString))
if hash[0] == 0x00 && hash[1] == 0x00 && hash[2] == 0x00 {
part2 = hashString
}
}
elapsed = time.Since(start)
fmt.Printf("Part 2: %v %v", part2, elapsed)
}

View File

@ -0,0 +1,107 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"time"
)
func main() {
fmt.Println("Day 5")
start := time.Now()
dat, err := ioutil.ReadFile("day5.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
part1 := 0
part2 := 0
for _, value := range lines {
vowels := 0
twiceInARow := false
forbiddenPhrases := false
for i := 0; i < len(value); i++ {
current := value[i]
if current == []byte("a")[0] || current == []byte("e")[0] || current == []byte("i")[0] || current == []byte("o")[0] || current == []byte("u")[0] {
vowels++
}
if i != 0 {
if value[i-1] == value[i] {
twiceInARow = true
}
last2 := []byte{value[i-1], value[i]}
if compare(last2, []byte("ab")) || compare(last2, []byte("cd")) || compare(last2, []byte("pq")) || compare(last2, []byte("xy")) {
forbiddenPhrases = true
break
}
}
}
if !forbiddenPhrases {
if twiceInARow && vowels >= 3 {
part1++
}
}
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", part1, elapsed)
start = time.Now()
for _, value := range lines {
repeatedPair := false
repeatedLetterWithGap := false
var pairs [][]byte
for i := 0; i < len(value)-1; i++ {
pairs = append(pairs, value[i:i+2])
}
for i := 0; i < len(pairs)-1; i++ {
for j := i + 2; j < len(pairs); j++ {
if compare(pairs[i], pairs[j]) {
repeatedPair = true
break
}
}
}
for i := 0; i < len(value)-2; i++ {
if value[i] == value[i+2] {
repeatedLetterWithGap = true
break
}
}
if repeatedLetterWithGap && repeatedPair {
part2++
}
}
elapsed = time.Since(start)
fmt.Printf("Part 2: %v %v", part2, elapsed)
}
func compare(slice1 []byte, slice2 []byte) bool {
for i := 0; i < len(slice1) && i < len(slice2); i++ {
if slice1[i] != slice2[i] {
return false
}
}
return true
}

View File

@ -0,0 +1,130 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"strconv"
"time"
)
type Square struct {
x int64
y int64
}
func main() {
fmt.Println("Day 6")
start := time.Now()
dat, err := ioutil.ReadFile("day6.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
lights := make(map[Square]bool)
lights2 := make(map[Square]int64)
SwitchTheLights(lights, false, false, 0, 0, 1000, 1000)
part1 := 0
var part2 int64 = 0
for _, value := range lines {
words := bytes.Split(value, []byte(" "))
if len(words) == 4 {
start := bytes.Split(words[1], []byte(","))
end := bytes.Split(words[3], []byte(","))
startX, _ := strconv.Atoi(string(start[0]))
startY, _ := strconv.Atoi(string(start[1]))
endX, _ := strconv.Atoi(string(end[0]))
endY, _ := strconv.Atoi(string(end[1]))
SwitchTheLights(lights, false, true, int64(startX), int64(startY), int64(endX), int64(endY))
SwitchTheLights2(lights2, false, true, int64(startX), int64(startY), int64(endX), int64(endY))
} else {
start := bytes.Split(words[2], []byte(","))
end := bytes.Split(words[4], []byte(","))
startX, _ := strconv.Atoi(string(start[0]))
startY, _ := strconv.Atoi(string(start[1]))
endX, _ := strconv.Atoi(string(end[0]))
endY, _ := strconv.Atoi(string(end[1]))
SwitchTheLights(lights, compare(words[1], []byte("on")), false, int64(startX), int64(startY), int64(endX), int64(endY))
SwitchTheLights2(lights2, compare(words[1], []byte("on")), false, int64(startX), int64(startY), int64(endX), int64(endY))
}
}
for _, v := range lights {
if v {
part1++
}
}
for _, v := range lights2 {
part2 += v
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", part1, elapsed)
fmt.Printf("Part 2: %v %v \n", part2, elapsed)
}
func SwitchTheLights(lights map[Square]bool, state bool, toggle bool, startX int64, startY int64, endX int64, endY int64) {
for i := startX; i <= endX; i++ {
for j := startY; j <= endY; j++ {
if toggle {
lights[Square{x: i, y: j}] = !lights[Square{x: i, y: j}]
} else {
lights[Square{x: i, y: j}] = state
}
}
}
}
func SwitchTheLights2(lights map[Square]int64, state bool, toggle bool, startX int64, startY int64, endX int64, endY int64) {
for i := startX; i <= endX; i++ {
for j := startY; j <= endY; j++ {
var brighness int64 = lights[Square{x: i, y: j}]
if toggle {
lights[Square{x: i, y: j}] = brighness + 2
} else {
if state {
lights[Square{x: i, y: j}] = brighness + 1
} else {
lights[Square{x: i, y: j}] = brighness - 1
if lights[Square{x: i, y: j}] < 0 {
lights[Square{x: i, y: j}] = 0
}
}
}
}
}
}
func compare(slice1 []byte, slice2 []byte) bool {
for i := 0; i < len(slice1) && i < len(slice2); i++ {
if slice1[i] != slice2[i] {
return false
}
}
return true
}

View File

@ -0,0 +1,155 @@
const std = @import("std");
const utils = @import("./utils.zig");
const InstructionType = enum { LITERAL, REASSIGN, NOT, AND, HACKY_AND, OR, LSHIFT, RSHIFT };
const Instruction = struct {
type: InstructionType,
// To be used with LITERAL
num: ?u16,
firstLetter: ?[]const u8,
secondLetter: ?[]const u8,
};
fn getOp(op: []const u8) InstructionType {
if (std.mem.eql(u8, op, "AND")) {
return InstructionType.AND;
}
if (std.mem.eql(u8, op, "OR")) {
return InstructionType.OR;
}
if (std.mem.eql(u8, op, "LSHIFT")) {
return InstructionType.LSHIFT;
}
if (std.mem.eql(u8, op, "RSHIFT")) {
return InstructionType.RSHIFT;
}
unreachable;
}
fn getLetter(map: std.StringHashMap(Instruction), cache: *std.StringHashMap(u16), letter: []const u8) !u16 {
if (cache.contains(letter)) {
return cache.*.get(letter).?;
}
var op = map.get(letter).?;
if (op.type == InstructionType.LITERAL) {
try cache.*.put(letter, op.num.?);
return op.num.?;
}
if (op.type == InstructionType.NOT) {
var notRes = ~(try getLetter(map, cache, op.firstLetter.?));
try cache.*.put(letter, notRes);
return notRes;
}
if (op.type == InstructionType.REASSIGN) {
var reassignRes = try getLetter(map, cache, op.firstLetter.?);
try cache.*.put(letter, reassignRes);
return reassignRes;
}
var first = try getLetter(map, cache, op.firstLetter.?);
if (op.type == InstructionType.HACKY_AND) {
try cache.*.put(letter, op.num.? & first);
return op.num.? & first;
}
if (op.type == InstructionType.AND or op.type == InstructionType.OR) {
var second = try getLetter(map, cache, op.secondLetter.?);
if (op.type == InstructionType.AND) {
try cache.*.put(letter, first & second);
return first & second;
}
try cache.*.put(letter, first | second);
return first | second;
}
if (op.type == InstructionType.LSHIFT) {
var shortNum: u4 = @truncate(op.num.?);
try cache.*.put(letter, first << shortNum);
return first << shortNum;
}
var shortNum: u4 = @truncate(op.num.?);
try cache.*.put(letter, first >> shortNum);
return first >> shortNum;
}
pub fn main() !void {
var allocator = std.heap.page_allocator;
var lines = try utils.splitLines("input.txt", allocator);
defer lines.deinit();
var wireMap = std.StringHashMap(Instruction).init(allocator);
defer wireMap.deinit();
var resultCache = std.StringHashMap(u16).init(allocator);
defer resultCache.deinit();
for (lines.items) |line| {
var instructionAndOutput = std.mem.tokenizeSequence(u8, line, " -> ");
var op = instructionAndOutput.next().?;
var output = instructionAndOutput.next().?;
var instructionParts = std.mem.tokenizeSequence(u8, op, " ");
var first = instructionParts.next().?;
if (std.mem.eql(u8, first, "NOT")) {
var notOp = Instruction{ .type = InstructionType.NOT, .firstLetter = instructionParts.next().?, .num = undefined, .secondLetter = undefined };
try wireMap.put(output, notOp);
continue;
}
var firstNumber = std.fmt.parseInt(u16, first, 10) catch {
// Must be a regular double operation (a AND b)
if (instructionParts.next()) |rawOperator| {
var operator = getOp(rawOperator);
var second = instructionParts.next().?;
var myOp = switch (operator) {
InstructionType.AND, InstructionType.OR => Instruction{ .type = operator, .firstLetter = first, .secondLetter = second, .num = undefined },
InstructionType.LSHIFT, InstructionType.RSHIFT => Instruction{ .type = operator, .firstLetter = first, .secondLetter = undefined, .num = try std.fmt.parseInt(u4, second, 10) },
else => unreachable,
};
try wireMap.put(output, myOp);
continue;
}
// x -> y
var reassign = Instruction{ .type = InstructionType.REASSIGN, .firstLetter = first, .secondLetter = undefined, .num = undefined };
try wireMap.put(output, reassign);
continue;
};
// Edge case. and gates can have numbers too (seems to be limited to first argument).
if (instructionParts.next()) |_| {
// an and operation with a 1 in front.
var second = instructionParts.next().?;
var hackyAnd = Instruction{ .type = InstructionType.HACKY_AND, .firstLetter = second, .secondLetter = undefined, .num = firstNumber };
try wireMap.put(output, hackyAnd);
continue;
}
var literalOp = Instruction{ .type = InstructionType.LITERAL, .num = firstNumber, .firstLetter = undefined, .secondLetter = undefined };
try wireMap.put(output, literalOp);
}
var part1 = try getLetter(wireMap, &resultCache, "a");
std.debug.print("Part 1: {}\n", .{part1});
var resetResultCache = std.StringHashMap(u16).init(allocator);
defer resetResultCache.deinit();
try resetResultCache.put("b", part1);
var part2 = try getLetter(wireMap, &resetResultCache, "a");
std.debug.print("Part 2: {}\n", .{part2});
}

View File

@ -0,0 +1 @@
../../zig/utils.zig

View File

@ -0,0 +1,83 @@
package main
import (
"bytes"
"fmt"
"io/ioutil"
"time"
)
type Square struct {
x int64
y int64
}
func main() {
fmt.Println("Day 8")
start := time.Now()
dat, err := ioutil.ReadFile("day8.txt")
if err != nil {
panic(err)
}
lines := bytes.Split(dat, []byte("\n"))
part2 := 0
totalCharacters := 0
realCharacters := 0
for _, value := range lines {
line := string(value)
totalCharacters += len(line)
newLine := line[1 : len(line)-1]
currentReal := 0
for i := 0; i < len(newLine); i++ {
char := string(newLine[i])
if char == `\` {
nextChar := string(newLine[i+1])
if nextChar == "x" {
i = i + 2
} else if nextChar == `"` || nextChar == `\` {
i++
currentReal++
}
} else {
currentReal++
}
}
realCharacters += currentReal
currentPart2 := 0
for i := 0; i < len(line); i++ {
char := string(line[i])
if char == `"` || char == `\` {
currentPart2 += 2
} else {
currentPart2++
}
}
//Double quotes around the string
currentPart2 += 2
part2 += currentPart2
}
elapsed := time.Since(start)
fmt.Printf("Part 1: %v %v \n", totalCharacters-realCharacters, elapsed)
fmt.Printf("Part 2: %v %v \n", part2-totalCharacters, elapsed)
}
func compare(slice1 []byte, slice2 []byte) bool {
for i := 0; i < len(slice1) && i < len(slice2); i++ {
if slice1[i] != slice2[i] {
return false
}
}
return true
}

View File

@ -0,0 +1,3 @@
# Advent of Code 2020
These are my solutions, currently all in Java.

Binary file not shown.

View File

@ -0,0 +1,41 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day1 {
public static void main(String[] args) {
try {
File myFile = new File("input.txt");
Scanner in = new Scanner(myFile);
int[] input = new int[200];
for (int i = 0; i < 200; i++) {
input[i] = Integer.parseInt(in.next());
}
for (int i = 0; i < 198; i++) {
for (int j = i + 1; j < 199; j++) {
//Following is for part1
//if (input[i] + input[j] == 2020) {
//System.out.println(input[i] * input[j]);
//}
for (int k = j + 1; k < 200; k++) {
if (input[i] + input[j] + input[k] == 2020) {
System.out.println(input[i] * input[j] * input[k]);
}
}
}
}
in.close();
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
}

Binary file not shown.

View File

@ -0,0 +1,140 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
class day10 {
static HashMap<ArrayList<Integer>, Long> cache = new HashMap<>();
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
ArrayList<Integer> nums = new ArrayList<>();
while (in.hasNext()) {
nums.add(Integer.parseInt(in.nextLine()));
}
nums.add(0);
Collections.sort(nums);
nums.add(nums.get(nums.size() - 1) + 3);
//Part 1 code
int one = 0;
int two = 0;
int three = 0;
for (int i = 1; i < nums.size(); i++) {
int diff = nums.get(i) - nums.get(i - 1);
if (diff == 1) {
one++;
} else if (diff == 2) {
two++;
} else if (diff == 3) {
three++;;
}
}
if (nums.get(0) == 1) one++; //From the plug to the first adaptor
three++; //Build in adaptor
//System.out.printf("One: %d | Two: %d | Three: %d \n", one, two, three);
//System.out.printf("Multiplied: %d", one * three);
//System.out.println(isValid(nums, nums.size()));
System.out.println(getSum(nums));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/*
Recursive method for part 2 solution
There is likely a method which has o(N) complexity, but seeing as this is a daily thing, and I don't have
all that much time this is still an elegant solution.
*/
public static long getSum(ArrayList<Integer> nums) {
long sum = 0;
if (nums.size() == 1) {
//System.out.println("Size 1");
return 1;
}
ArrayList<Integer> newNums = new ArrayList<>(nums);
for (int i = 1; i <= 3; i++) {
int pointer = nums.size() - 1 - i;
//System.out.println("Pointer: " + pointer);
//System.out.println("DSADS: " + nums.get(pointer));
if (pointer >= 0) {
if (nums.get(nums.size() - 1) - nums.get(pointer) <= 3) {
newNums.remove(pointer + 1);
/*System.out.println("============SENT==========");
for (int c : nums) System.out.println(c);
System.out.println("==========================");
System.out.println("==========================");
for (int c : newNums) System.out.println(c);
System.out.println("==========================");*/
if (cache.containsKey(newNums)) {
sum += cache.get(newNums);
} else {
long treeSum = getSum(newNums);
//System.out.println("Tree sum: " + treeSum);
cache.put(newNums, treeSum);
sum += treeSum;
}
}
}
}
return sum;
}
public static boolean isValid(ArrayList<Integer> nums) {
for (int i = 1; i < nums.size(); i++) {
int diff = nums.get(i) - nums.get(i - 1);
if (diff > 3) return false;
}
return true;
}
static int nCr(int n, int r) {
return fact(n) / (fact(r) *
fact(n - r));
}
// Returns factorial of n
static int fact(int n) {
int res = 1;
for (int i = 2; i <= n; i++)
res = res * i;
return res;
}
}

Binary file not shown.

View File

@ -0,0 +1,157 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day11 {
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
char[][] seats = new char[91][94];
int index = 0;
while (in.hasNext()) {
seats[index] = in.nextLine().toCharArray();
index++;
}
boolean stable = false;
while (!stable) {
//char[][] newSeats = part1(seats);
char[][] newSeats = part2(seats);
boolean notEqual = false;
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[0].length; j++) {
if (newSeats[i][j] != seats[i][j]) notEqual = true;
}
}
if (notEqual) {
seats = newSeats;
} else {
stable = true;
}
}
int occupiedSeats = 0;
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[0].length; j++) {
if (seats[i][j] == '#') occupiedSeats++;
System.out.print(seats[i][j]);
}
System.out.println();
}
System.out.println("Answer: " + occupiedSeats);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
static char[][] part1(char[][] seats) {
char[][] newSeats = new char[seats.length][seats[0].length];
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[0].length; j++) {
int emptySeats = 0;
int occupiedSeats = 0;
if (seats[i][j] != '.') {
for (int checkX = -1; checkX <= 1; checkX++) {
for (int checkY = -1; checkY <= 1; checkY++) {
if (j + checkX >= 0 && i + checkY >= 0 &&
j + checkX < seats[0].length && i + checkY < seats.length &&
!(checkX == 0 && checkY == 0)) {
if (seats[i + checkY][j + checkX] == 'L') emptySeats++;
else if (seats[i + checkY][j + checkX] == '#') occupiedSeats++;
}
}
}
if (occupiedSeats == 0 && seats[i][j] == 'L') newSeats[i][j] = '#';
else if (occupiedSeats >= 4 && seats[i][j] == '#') newSeats[i][j] = 'L';
else newSeats[i][j] = seats[i][j];
} else newSeats[i][j] = '.';
}
}
return newSeats;
}
static char[][] part2(char[][] seats) {
char[][] newSeats = new char[seats.length][seats[0].length];
for (int i = 0; i < seats.length; i++) {
for (int j = 0; j < seats[0].length; j++) {
int occupiedSeats = 0;
//System.out.print(seats[i][j]);
if (seats[i][j] != '.') {
for (int checkX = -1; checkX <= 1; checkX++) {
for (int checkY = -1; checkY <= 1; checkY++) {
if (!(checkX == 0 && checkY == 0)) {
int multipliedX = checkX;
int multipliedY = checkY;
boolean foundSeat = false;
while (j + multipliedX >= 0 && i + multipliedY >= 0 && j + multipliedX < seats[0].length && i + multipliedY < seats.length && foundSeat == false) {
if(seats[i + multipliedY][j + multipliedX] == 'L') {
foundSeat = true;
} else if (seats[i + multipliedY][j + multipliedX] == '#') {
occupiedSeats++;
foundSeat = true;
}
multipliedX += checkX;
multipliedY += checkY;
}
}
}
}
//System.out.print(occupiedSeats);
if (occupiedSeats >= 5 && seats[i][j] == '#') newSeats[i][j] = 'L';
else if (occupiedSeats == 0 && seats[i][j] == 'L') newSeats[i][j] = '#';
else newSeats[i][j] = seats[i][j];
} else newSeats[i][j] = '.';
}
//System.out.println();
}
return newSeats;
}
}

Binary file not shown.

View File

@ -0,0 +1,50 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
class day13 {
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
double timestamp = Double.parseDouble(in.nextLine());
String[] secondLine = in.nextLine().split(",");
ArrayList<Double> buses = new ArrayList<>();
for (String i : secondLine) {
if (!i.equals("x")) buses.add(Double.parseDouble(i));
}
double shortestTime = Double.MAX_VALUE;
double shortestBus = 0;
for (double i : buses) {
double closestTime = Math.ceil(timestamp / i) * i;
System.out.printf("Time: %f | Closest Time: %f \n", i, closestTime);
if (closestTime < shortestTime) {
shortestTime = closestTime;
shortestBus = i;
}
}
System.out.printf("Part 1: %f \n", (shortestTime - timestamp) * shortestBus);
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

Binary file not shown.

View File

@ -0,0 +1,136 @@
import java.io.File;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class day14 {
public static void main(String[] args) {
try {
File inputFile = new File("input.txt");
Scanner in = new Scanner(inputFile);
HashMap<Long, Long> memory = new HashMap<>();
String mask = "";
while (in.hasNext()) {
String[] line = in.nextLine().split(" = ");
if (line[0].equals("mask")) {
mask = line[1];
System.out.println("Mask: " + mask);
} else {
int address = Integer.parseInt(line[0].substring(line[0].indexOf("[") + 1, line[0].indexOf("]")));
long value = Long.parseLong(line[1]);
//memory.put(address, maskedValue(mask, value));
long[] addresses = maskedAddresses(mask, address);
for (long a : addresses) {
System.out.printf("Address: %d | Value: %d \n", a, value);
memory.put(a, value);
}
}
}
long sumLong = 0;
for (long key : memory.keySet()) {
sumLong += memory.get(key);
}
System.out.println("Answer: " + sumLong);
} catch (Exception e) {
System.out.println(e);
}
}
static long maskedValue(String mask, int value) {
String binaryString = Integer.toBinaryString(value);
while (binaryString.length() != 36) binaryString = "0" + binaryString;
String returnString = new String();
System.out.println("Binary String: " + binaryString);
for (int i = binaryString.length() - 1; i >= 0; i--) {
if (binaryString.charAt(i) != mask.charAt(i) && mask.charAt(i) != 'X') {
returnString = mask.charAt(i) + returnString;
} else {
returnString = binaryString.charAt(i) + returnString;
}
}
System.out.println("Return String: " + returnString);
return toDenary(returnString);
}
static long[] maskedAddresses(String mask, int value) {
String binaryString = Integer.toBinaryString(value);
while (binaryString.length() != 36) binaryString = "0" + binaryString;
String returnString = new String();
ArrayList<Integer> xlist = new ArrayList<>();
System.out.println("Binary String: " + binaryString);
for (int i = binaryString.length() - 1; i >= 0; i--) {
if (mask.charAt(i) == 'X') xlist.add(i);
if (binaryString.charAt(i) != mask.charAt(i) && mask.charAt(i) != '0') {
returnString = mask.charAt(i) + returnString;
} else {
returnString = binaryString.charAt(i) + returnString;
}
}
System.out.println("Return string: " + returnString);
String[] binaryStrings = new String[(int) Math.pow(2, xlist.size())];
for (int i = 0; i < Math.pow(2, xlist.size()); i++) {
String currentI = Integer.toBinaryString(i);
while (currentI.length() < xlist.size()) currentI = "0" + currentI;
String newAddress = returnString;
for (int j = 0; j < currentI.length(); j++) {
newAddress = newAddress.replaceFirst(Pattern.quote("X"), Matcher.quoteReplacement(Character.toString(currentI.charAt(j))));
}
System.out.println("New address: " + newAddress);
binaryStrings[i] = newAddress;
}
long[] newAddresses = new long[binaryStrings.length];
for (int i = 0; i < newAddresses.length; i++) {
newAddresses[i] = toDenary(binaryStrings[i]);
}
return newAddresses;
}
static long toDenary(String binary) {
long value = 0;
for (int i = 0; i < binary.length(); i++) {
if (binary.charAt(i) == '1') {
value += Math.pow(2, (35 - i));
}
}
return value;
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,40 @@
import java.util.ArrayList;
import java.util.HashMap;
class day15 {
public static void main(String[] args) {
int[] startingNumbers = {17,1,3,16,19,0};
ArrayList<Integer> spokenNums = new ArrayList<>();
HashMap<Integer, Integer> seenLast = new HashMap<>();
int lastNumber = 0;
for (int i = 0; i < startingNumbers.length; i++) {
spokenNums.add(startingNumbers[i]);
lastNumber = startingNumbers[i];
if (i + 1 != startingNumbers.length) {
seenLast.put(startingNumbers[i], i + 1);
}
}
while (spokenNums.size() < 30000000) {
if (!seenLast.containsKey(lastNumber)) {
seenLast.put(lastNumber, spokenNums.size());
spokenNums.add(0);
lastNumber = 0;
} else {
int diff = spokenNums.size() - seenLast.get(lastNumber);
seenLast.put(lastNumber, spokenNums.size());
lastNumber = diff;
spokenNums.add(lastNumber);
}
}
System.out.println("Number: " + spokenNums.get(spokenNums.size() - 1));
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,197 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;
import java.util.stream.Collectors;
import javax.print.attribute.standard.MediaSize.Other;
class day16 {
public static void main(String[] args) {
try {
File inputFile = new File("input.txt");
Scanner in = new Scanner(inputFile);
List<String> input = new ArrayList<>();
while (in.hasNext()) input.add(in.nextLine());
List<String> fields = input.subList(0, input.indexOf("your ticket:") - 1);
String ticket = input.get(input.indexOf("your ticket:") + 1);
List<String> otherTickets = input.subList(input.indexOf("nearby tickets:") + 1, input.size());
HashMap<Integer, Integer> ranges = new HashMap<>();
List<Field> formattedFields = new ArrayList<>();
for (String field : fields) {
//Part 1 uses the hasmap, part 2 doesnot
String[] currentRanges = field.substring(field.indexOf(":") + 2).split(" or ");
String[] currentUpperAndLower = currentRanges[0].split("-");
ranges.put(Integer.parseInt(currentUpperAndLower[0]), Integer.parseInt(currentUpperAndLower[1]));
int[] range1 = {Integer.parseInt(currentUpperAndLower[0]), Integer.parseInt(currentUpperAndLower[1])};
currentUpperAndLower = currentRanges[1].split("-");
ranges.put(Integer.parseInt(currentUpperAndLower[0]), Integer.parseInt(currentUpperAndLower[1]));
int[] range2 = {Integer.parseInt(currentUpperAndLower[0]), Integer.parseInt(currentUpperAndLower[1])};
String category = field.substring(0, field.indexOf(":"));
formattedFields.add(new Field(category, range1, range2));
}
long errorRate = 0;
List<Integer> toRemove = new ArrayList<>();
for (String value : otherTickets) {
String[] values = value.split(",");
int[] singleTicketValues = Arrays.stream(values).mapToInt(Integer::parseInt).toArray();
for (int singleValue : singleTicketValues) {
boolean valid = false;
for (int lower : ranges.keySet()) {
int upper = ranges.get(lower);
if (singleValue >= lower && singleValue <= upper) {
valid = true;
break;
}
}
if (!valid) {
toRemove.add(otherTickets.indexOf(value));
errorRate += singleValue;
}
}
}
List<String> newOtherTickets = new ArrayList<>();
for (int i = 0; i < otherTickets.size(); i++) {
if (!toRemove.contains(i)) newOtherTickets.add(otherTickets.get(i));
}
HashMap<Integer, List<Field>> possibleCombinations = new HashMap<>();
for (Field f : formattedFields) possibleCombinations.put(formattedFields.indexOf(f), new ArrayList<>());
for (int i = 0; i < newOtherTickets.size(); i++) {
String[] firstValues = newOtherTickets.get(i).split(",");
for (int j = 0; j < firstValues.length; j++) {
int currentValue = Integer.parseInt(firstValues[j]);
List<Field> possible = new ArrayList<>();
for (Field f : formattedFields) {
if (i == 0) {
if (f.range1[0] <= currentValue && f.range1[1] >= currentValue ||
f.range2[0] <= currentValue && f.range2[1] >= currentValue) {
possibleCombinations.get(j).add(f);
}
} else {
//Compare to this field;
if (f.range1[0] <= currentValue && f.range1[1] >= currentValue ||
f.range2[0] <= currentValue && f.range2[1] >= currentValue) {
possible.add(f);
}
}
}
//Compare withoutDuplicate and "possible"
if (i != 0) {
List<Field> newList = new ArrayList<>();
for (Field f : possible) if (possibleCombinations.get(j).contains(f) && possible.contains(f)) {
newList.add(f);
}
possibleCombinations.put(j, newList);
}
}
}
//Part 2
boolean done = false;
while (!done) {
for (int i : possibleCombinations.keySet()) {
if (possibleCombinations.get(i).size() == 1) {
Field knownField = possibleCombinations.get(i).get(0);
for (int j = 0; j < possibleCombinations.size(); j++) {
if (i != j && possibleCombinations.get(j).size() > 1) {
possibleCombinations.get(j).remove(knownField);
}
}
}
}
done = true;
for (int i : possibleCombinations.keySet()) {
if (possibleCombinations.get(i).size() != 1) done = false;
}
}
long multiplication = 1;
String[] myTicket = ticket.split(",");
for (int i : possibleCombinations.keySet()) {
Field currentField = possibleCombinations.get(i).get(0);
if (currentField.name.contains("departure")) {
multiplication *= Long.parseLong(myTicket[i]);
}
}
System.out.println("Part 1: " + errorRate);
System.out.println("Part 2: " + multiplication);
} catch (Exception e) {
System.out.println(e);
}
}
}
class Field {
public String name;
public int[] range1;
public int[] range2;
public int col = -1;
public Field(String name, int[] range1, int[] range2) {
this.name = name;
this.range1 = range1;
this.range2 = range2;
}
public String toString() {
return "Category: " + name + " | Range 1: " + range1[0] + "-" + range1[1] + " | Range 2: " + range2[0] + "-" + range2[1];
}
}

Binary file not shown.

View File

@ -0,0 +1,243 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
class day17 {
public static void main(String[] args) {
List<int[]> points = new ArrayList<>();
List<int[]> pointsPart2 = new ArrayList<>();
char[][] input = {{'.', '.', '#', '.', '.', '#', '.', '.'},
{'#', '.', '#', '.', '.', '.', '#', '.'},
{'.', '.', '#', '.', '.', '.', '.', '.'},
{'#', '#', '.', '.', '.', '.', '#', '#'},
{'#', '.', '.', '#', '.', '#', '#', '#'},
{'.', '#', '.', '.', '#', '.', '.', '.'},
{'#', '#', '#', '.', '.', '#', '.', '.'},
{'.', '.', '.', '.', '#', '.', '.', '#'}};
/*char[][] input = {{'.', '#', '.'},
{'.', '.', '#'},
{'#', '#', '#'}};*/
//Part 1
//initialise
for (int i = 0; i < input.length; i++) {
for (int j = 0; j < input[0].length; j++) {
int[] newPoint = {j, i, 0, 0};
int[] newPointPart2 = {j, i, 0, 0, 0};
if (input[i][j] == '#') {
newPoint[3] = 1;
newPointPart2[4] = 1;
}
points.add(newPoint);
pointsPart2.add(newPointPart2);
}
}
for (int i = 0; i < 6; i++) {
points = step(points);
pointsPart2 = stepPart2(pointsPart2);
}
int counter = 0;
for (int[] p : points) {
if (p[3] == 1) counter++;
//System.out.printf("x: %d | y: %d | z: %d | State: %d \n", p[0], p[1], p[2], p[3]);
}
System.out.println("Part 1: " + counter);
counter = 0;
for (int[] p : pointsPart2) {
if (p[4] == 1) counter++;
//System.out.printf("x: %d | y: %d | z: %d | State: %d \n", p[0], p[1], p[2], p[3]);
}
System.out.println("Part 2: " + counter);
}
static List<int[]> step(List<int[]> points) {
List<int[]> newPoints = new ArrayList<>();
List<int[]> pointsToCheck = new ArrayList<>();
for (int[] p : points) {
int active = 0;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
if (!(x == 0 && y == 0 && z == 0)) {
int[] potentialNeighboor = {p[0] + x, p[1] + y, p[2] + z, 0};
int index = contains(potentialNeighboor, points);
if (index != -1) {
int[] foundPoint = points.get(index);
if (foundPoint[3] == 1) {
active++;
}
} else {
if (contains(potentialNeighboor, pointsToCheck) == -1) pointsToCheck.add(potentialNeighboor);
}
}
}
}
}
int[] newPoint = {p[0], p[1], p[2], p[3]};
if (p[3] == 1) {
if (active != 2 && active != 3) newPoint[3] = 0;
} else {
if (active == 3) newPoint[3] = 1;
}
newPoints.add(newPoint);
}
for (int[] p : pointsToCheck) {
int active = 0;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
if (!(x == 0 && y == 0 && z == 0)) {
int[] potentialNeighboor = {p[0] + x, p[1] + y, p[2] + z, 0};
int index = contains(potentialNeighboor, points);
if (index != -1) {
int[] foundPoint = points.get(index);
if (foundPoint[3] == 1) active++;
}
}
}
}
}
int[] newPoint = {p[0], p[1], p[2], p[3]};
if (active == 3){
newPoint[3] = 1;
//System.out.printf("x: %d | y: %d | z: %d | State: %d \n", newPoint[0], newPoint[1], newPoint[2], newPoint[3]);
}
newPoints.add(newPoint);
}
return newPoints;
}
static List<int[]> stepPart2(List<int[]> points) {
System.out.println(points.size());
List<int[]> newPoints = new ArrayList<>();
List<int[]> pointsToCheck = new ArrayList<>();
for (int[] p : points) {
int active = 0;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
for (int w = -1; w <= 1; w++) {
if (!(x == 0 && y == 0 && z == 0 && w == 0)) {
int[] potentialNeighboor = {p[0] + x, p[1] + y, p[2] + z, p[3] + w, 0};
int index = containsPart2(potentialNeighboor, points);
if (index != -1) {
int[] foundPoint = points.get(index);
if (foundPoint[4] == 1) active++;
} else {
if (containsPart2(potentialNeighboor, pointsToCheck) == -1) pointsToCheck.add(potentialNeighboor);
}
}
}
}
}
}
int[] newPoint = {p[0], p[1], p[2], p[3], p[4]};
if (p[4] == 1) {
if (active != 2 && active != 3) newPoint[4] = 0;
} else {
if (active == 3) newPoint[4] = 1;
}
newPoints.add(newPoint);
}
for (int[] p : pointsToCheck) {
int active = 0;
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
for (int w = -1; w <= 1; w++) {
if (!(x == 0 && y == 0 && z == 0 && w == 0)) {
int[] potentialNeighboor = {p[0] + x, p[1] + y, p[2] + z, p[3] + w, 0};
int index = containsPart2(potentialNeighboor, points);
if (index != -1) {
int[] foundPoint = points.get(index);
if (foundPoint[4] == 1) active++;
}
}
}
}
}
}
int[] newPoint = {p[0], p[1], p[2], p[3], p[4]};
if (active == 3) newPoint[4] = 1;
newPoints.add(newPoint);
}
return newPoints;
}
static int contains(int[] p, List<int[]> points) {
for (int[] search : points) {
if (search[0] == p[0] && search[1] == p[1] && search[2] == p[2]) {
return points.indexOf(search);
}
}
return -1;
}
static int containsPart2(int[] p, List<int[]> points) {
for (int[] search : points) {
if (search[0] == p[0] && search[1] == p[1] && search[2] == p[2] && search[3] == p[3]) {
return points.indexOf(search);
}
}
return -1;
}
}

Binary file not shown.

View File

@ -0,0 +1,167 @@
import java.util.Scanner;
import java.io.File;
import java.math.BigInteger;
public class day18 {
public static void main(String[] args) {
try {
File inputFile = new File("input.txt");
Scanner in = new Scanner(inputFile);
long total1 = 0;
long total2 = 0;
while (in.hasNext()) {
String expression = in.nextLine();
total1 += recursive(expression);
}
System.out.println("Total: " + total1);
} catch (Exception e) {
System.out.println(e);
}
}
public static long recursive(String expression) {
System.out.println(expression);
int openIndex = -1;
int closeIndex = 0;
int count = 0;
for (int i = 0; i < expression.length(); i++) {
char check = expression.charAt(i);
if (check == '(' && count == 0) {
count = 1;
openIndex = i;
} else if (check == '(' && count != 0) {
count++;
} else if (check == ')' && count > 1) {
count--;
} else if (check == ')' && count == 1) {
closeIndex = i;
count = 0;
long solved = recursive(expression.substring(openIndex + 1, closeIndex));
expression = expression.substring(0, openIndex) + solved + expression.substring(closeIndex + 1);
}
}
if (openIndex == -1) {
//return solve(expression);
//Part 2:
return part2(expression);
} else {
return recursive(expression);
}
}
public static long part2(String expression) {
expression = expression.replace("(", "");
expression = expression.replace(")", "");
expression = expression.replace(" ", "");
if (expression.contains("+") && expression.contains("*")) {
String[] split = expression.split("[*]");
long total = 1;
for (String s : split) {
total *= solve(s);
}
return total;
} else {
return solve(expression);
}
}
public static long solve(String expression) {
expression = expression.replace("(", "");
expression = expression.replace(")", "");
expression = expression.replace(" ", "");
int loops = 0;
//Looks bad but i think its faster than some REGEX or something,
//plus its needed for iteration
loops += expression.length() - expression.replace("+", "").length();
loops += expression.length() - expression.replace("*", "").length();
if (loops == 0) return Long.parseLong(expression);
long total = 0;
for (int i = 0; i < loops - 1; i++) {
int indexRest = 0;
int currentIndex = 0;
for (int j = 0; j < expression.length(); j++) {
if (!Character.isDigit(expression.charAt(j))) {
if (currentIndex == 0) {
currentIndex = j;
} else {
indexRest = j;
break;
}
}
}
String currentExpression = expression.substring(0, indexRest);
String[] split = currentExpression.split("[+*/-]");
long left = Long.parseLong(split[0]);
long right = Long.parseLong(split[1]);
char operation = expression.charAt(currentIndex);
long currentTotal = 0;
if (operation == '+') {
currentTotal = left + right;
} else if (operation == '-') {
currentTotal = left - right;
} else if (operation == '*') {
currentTotal = left * right;
} else if (operation == '/') {
currentTotal = left / right;
}
expression = currentTotal + expression.substring(indexRest);
}
int index = 0;
for (int i = 0; i < expression.length(); i++) {
if (!Character.isDigit(expression.charAt(i))) {
index = i;
break;
}
}
String[] split = expression.split("[+*]");
long left = Long.parseLong(split[0]);
long right = Long.parseLong(split[1]);
char operation = expression.charAt(index);
if (operation == '+') {
total = left + right;
} else if (operation == '*') {
total = left * right;
}
return total;
}
}

View File

@ -0,0 +1,115 @@
package main
import (
"fmt"
"os"
"regexp"
"strings"
)
func GetRule(rules *map[string]string, r string) string {
rule := (*rules)[r]
if strings.Contains(rule, `"`) {
// Base case
matchLetter := rule[1 : len(rule)-1]
return matchLetter
}
alternates := strings.Split(rule, " | ")
if len(alternates) == 1 {
ruleNumbers := strings.Split(alternates[0], " ")
str := ""
for _, n := range ruleNumbers {
str += GetRule(rules, n)
}
return str
}
if len(alternates) > 1 {
ruleNumbers := strings.Split(alternates[0], " ")
firstAlternate := ""
for _, n := range ruleNumbers {
firstAlternate += GetRule(rules, n)
}
ruleNumbers = strings.Split(alternates[1], " ")
secondAlternate := ""
for _, n := range ruleNumbers {
secondAlternate += GetRule(rules, n)
}
return fmt.Sprintf("(%s|%s)", firstAlternate, secondAlternate)
}
panic("should never be here")
}
func main() {
content, err := os.ReadFile("./input.txt")
if err != nil {
panic(err)
}
splitInput := strings.Split(string(content), "\n\n")
rules := strings.Split(splitInput[0], "\n")
ruleMap := make(map[string]string)
for _, rule := range rules {
splitRule := strings.Split(rule, ": ")
ruleNumber := splitRule[0]
ruleMap[ruleNumber] = splitRule[1]
}
tests := splitInput[1]
tests = tests[0 : len(tests)-1]
zeroRule := regexp.MustCompile("^" + GetRule(&ruleMap, "0") + "$")
matches := 0
for _, t := range strings.Split(tests, "\n") {
if zeroRule.Match([]byte(t)) {
matches++
}
}
fmt.Printf("Part 1: %d\n", matches)
fRule := regexp.MustCompile(GetRule(&ruleMap, "42"))
tRule := regexp.MustCompile(GetRule(&ruleMap, "31"))
matches = 0
for _, t := range strings.Split(tests, "\n") {
// rule 0 = 8 11
// 8 = 42+
// 11 = 42{n} 31{n}
// Therefore: 0 = 42 {n*2} 31{n}
fortyTwoMatch := fRule.FindStringIndex(t)
fortyTwoCount := 0
for fortyTwoMatch != nil && fortyTwoMatch[0] == 0 {
t = t[fortyTwoMatch[1]:]
fortyTwoMatch = fRule.FindStringIndex(t)
fortyTwoCount++
}
thirtyMatch := tRule.FindStringIndex(t)
thirtyCount := 0
for thirtyMatch != nil && thirtyMatch[0] == 0 {
t = t[thirtyMatch[1]:]
thirtyMatch = tRule.FindStringIndex(t)
thirtyCount++
}
if len(t) == 0 && thirtyCount > 0 && fortyTwoCount > thirtyCount {
matches++
}
}
fmt.Printf("Part 2: %d\n", matches)
}

View File

@ -0,0 +1,253 @@
package main
import (
"fmt"
"os"
"strings"
)
var THREE_SIMPLE_RULE = `
func Rule%s(message string, index *int) error {
err := Rule%s(message, index)
if err != nil {
return err
}
err = Rule%s(message, index)
if err != nil {
return err
}
err = Rule%s(message, index)
if err != nil {
return err
}
return nil
}
`
var SIMPLE_RULE = `
func Rule%s(message string, index *int) error {
err := Rule%s(message, index)
if err != nil {
return err
}
err = Rule%s(message, index)
if err != nil {
return err
}
return nil
}
`
var ONE_SIMPLE_RULE = `
func Rule%s(message string, index *int) error {
err := Rule%s(message, index)
if err != nil {
return err
}
return nil
}
`
var ALTERNATE_RULE = `
func Rule%s(message string, index *int) error {
indexCopy := *index
err := Rule%sFirst(message, &indexCopy)
if err == nil {
*index = indexCopy
return nil
}
err = Rule%sSecond(message, index)
return err
}
%s
%s
`
var LITERAL_RULE = `
func Rule%s(message string, index *int) error {
if len(message) <= *index {
return errors.New("out of bounds")
}
if string(message[*index]) == "%c" {
*index++
return nil
}
return errors.New("Could not match")
}
`
func main() {
content, err := os.ReadFile("./input.txt")
if err != nil {
panic(err)
}
splitInput := strings.Split(string(content), "\n\n")
program := `
package main
import (
"errors"
"fmt"
"os"
"strings"
)
func main() {
content, err := os.ReadFile("./input.txt")
if err != nil {
panic(err)
}
splitInput := strings.Split(string(content), "\n\n")
toTry := splitInput[1]
counter := 0
toTrySplit := strings.Split(toTry, "\n")
for _, v := range toTrySplit[0: len(toTrySplit) - 1] {
index := 0
err := Rule0(v, &index)
if err == nil && index == len(v) {
counter++
}
}
fmt.Println(counter)
}
`
rules := strings.Split(splitInput[0], "\n")
for _, v := range rules {
/*
if v == "8: 42" {
v = "8: 42 | 42 8"
} else if v == "11: 42 31" {
v = "11: 42 31 | 42 11 31"
}
*/
program += CreateRule(v)
}
err = os.WriteFile("./parser.go", []byte(program), 0777)
if err != nil {
panic(err)
}
}
func CreateRule(rule string) (string) {
splitRule := strings.Split(rule, ": ")
ruleNumber := splitRule[0]
rules := strings.Split(splitRule[1], " | ")
if (len(rules) == 1) {
return CreateSingleRule(ruleNumber, rules[0])
}
return fmt.Sprintf(ALTERNATE_RULE, ruleNumber, ruleNumber, ruleNumber, CreateSingleRule(ruleNumber + "First", rules[0]), CreateSingleRule(ruleNumber + "Second", rules[1]))
}
// Single rule (4 5) or ("a")
func CreateSingleRule(ruleNumber string, rule string) string {
if string(rule[0]) == string('"') {
return fmt.Sprintf(LITERAL_RULE, ruleNumber, rule[1])
}
nums := strings.Split(rule, " ")
if len(nums) == 3 {
return fmt.Sprintf(THREE_SIMPLE_RULE, ruleNumber, nums[0], nums[1], nums[2])
} else if (len(nums) == 2) {
return fmt.Sprintf(SIMPLE_RULE, ruleNumber, nums[0], nums[1])
}
return fmt.Sprintf(ONE_SIMPLE_RULE, ruleNumber, nums[0])
}
/*
func Rule0(message string, index *int) error {
err := Rule1(message, index)
if err != nil {
return err
}
err := Rule2(message, index)
if err != nil {
return err
}
return nil
}
func Rule2(message string, index *int) error {
indexCopy := *index
err := Rule2First(message, &indexCopy)
if err == nil {
return nil
}
err = Rule2Second(message, index)
return err
}
func Rule2First(message string, index *int) error {
err := Rule1(message, index)
if err != nil {
return err
}
err := Rule3(message, index)
if err != nil {
return err
}
return nil
}
func Rule2Second(message string, index *int) error {
err := Rule3(message, index)
if err != nil {
return err
}
err := Rule1(message, index)
if err != nil {
return err
}
return nil
}
func Rule3(message string, index *int) errro {
if message[*index] == "b" {
x := 5
y := &x
*y = *y + 1
fmt.Println(x)
}
}
func Rule3(message string, index *int) error {
if string(message[*index]) == "b" {
*index++
return nil
}
return errors.New("Could not match")
}
*/

1056
AdventOfCode2020/day19/parser.go Executable file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,51 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class Main {
public static void main(String[] args) {
try {
File myFile = new File("input.txt");
Scanner in = new Scanner(myFile);
int valid = 0;
for (int i = 0; i < 1000; i++) {
String line = in.nextLine();
String[] firstSplit = line.split(" ");
//0 - numbers
//1 - letter
//2 - Password
String[] boundsStr = firstSplit[0].split("-");
int[] bounds = {Integer.parseInt(boundsStr[0]), Integer.parseInt(boundsStr[1])};
char letter = firstSplit[1].charAt(0);
String password = firstSplit[2];
//int counter = 0;
//Part 1 code
/*for (char c : password.toCharArray()) {
if (c == letter) counter++;
}
if (counter >= bounds[0] && counter <= bounds[1]) valid++;*/
//Second part code
if ((password.charAt(bounds[0] - 1) == letter || password.charAt(bounds[1] - 1) == letter) && !(password.charAt(bounds[0] - 1) == letter && password.charAt(bounds[1] - 1) == letter)) valid++;
}
System.out.println(valid);
in.close();
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
}

View File

@ -0,0 +1,140 @@
package main
import (
"fmt"
"os"
"slices"
"strings"
)
func contains(arr []string, search string) bool {
for _, val := range arr {
if val == search {
return true
}
}
return false
}
func remove(arr []string, item string) []string {
newThing := make([]string, 0)
for _, val := range arr {
if val != item {
newThing = append(newThing, val)
}
}
return newThing
}
func mergeSets(set1 []string, set2 []string) []string {
merged := make([]string, 0)
for _, val := range set1 {
if (contains(set2, val)) {
merged = append(merged, val)
}
}
return merged
}
func isMapSingleValue(myMap map[string][]string) bool {
for _, v := range myMap {
if len(v) > 1 {
return false
}
}
return true
}
func main() {
content, err := os.ReadFile("./input.txt")
if err != nil {
panic(err)
}
_lines := strings.Split(string(content), "\n")
lines := _lines[:len(_lines) - 1]
myMap := make(map[string][]string)
totalIngredients := make([]string, 0)
for _, line := range lines {
split := strings.Split(line, " (contains ")
if (len(split) == 0) {
continue
}
ingredients := strings.Split(split[0], " ")
for _, i := range ingredients {
totalIngredients = append(totalIngredients, i)
}
formatted := strings.Split(strings.TrimSuffix(split[1], ")"), ", ")
for _, v := range formatted {
val, exists := myMap[v]
if !exists {
myMap[v] = ingredients
continue
}
newSets := mergeSets(val, ingredients)
myMap[v] = newSets
if (len(newSets) == 1) {
found := newSets[0]
for key, mapVal := range myMap {
if key == v {
continue
}
if (contains(mapVal, found)) {
myMap[key] = remove(mapVal, found)
}
}
}
}
}
for !isMapSingleValue(myMap) {
for firstK, v := range myMap {
if len(v) == 1 {
for k, i := range myMap {
if k == firstK {
continue
}
myMap[k] = remove(i, v[0])
}
}
}
}
allMapValues := make([]string, 0)
for _, v := range myMap {
for _, j := range v {
if (!contains(allMapValues, j)) {
allMapValues = append(allMapValues, j)
}
}
}
fmt.Printf("%+v\n", myMap)
for _, v := range allMapValues {
totalIngredients = remove(totalIngredients, v)
}
myIngredientList := make([]string, 0)
for k := range myMap {
myIngredientList = append(myIngredientList, k)
}
slices.Sort(myIngredientList)
part2 := ""
for _, v := range myIngredientList {
part2 += myMap[v][0] + ","
}
part2 = strings.TrimSuffix(part2, ",")
fmt.Println(len(totalIngredients))
fmt.Println(part2)
}

View File

@ -0,0 +1,189 @@
package main
import (
"fmt"
"os"
"slices"
"strconv"
"strings"
)
type Queue struct {
arr []int
head uint
tail uint
}
func (s *Queue) Dequeue() int {
s.head++
return s.arr[s.head - 1]
}
func (s *Queue) Enqueue(num int) {
if len(s.arr) <= int(s.tail) {
s.arr = append(s.arr, num)
} else {
s.arr[s.tail] = num
}
s.tail++
}
func (s *Queue) Print() string {
str := ""
for i := s.head; i < s.tail; i++ {
str += strconv.Itoa(s.arr[i]) + ","
}
return str
}
func main() {
content, err := os.ReadFile("./input.txt")
if err != nil {
panic(err)
}
players := strings.Split(string(content), "\n\n")
player1 := strings.Split(players[0], "\n")[1:]
player2 := strings.Split(players[1], "\n")[1:]
player1Cards := Queue{
arr: make([]int, 0),
head: 0,
tail: 0,
}
player2Cards := Queue{
arr: make([]int, 0),
head: 0,
tail: 0,
}
for _, v := range player1 {
n, err := strconv.Atoi(v)
if err != nil {
panic(err)
}
player1Cards.Enqueue(n)
}
for _, v := range player2 {
if len(v) == 0 {
continue
}
n, err := strconv.Atoi(v)
if err != nil {
panic(err)
}
player2Cards.Enqueue(n)
}
/*
rounds := 0
for {
if player1Cards.head == player1Cards.tail || player2Cards.head == player2Cards.tail {
break
}
player1Card := player1Cards.Dequeue()
player2Card := player2Cards.Dequeue()
if player1Card > player2Card {
player1Cards.Enqueue(player1Card)
player1Cards.Enqueue(player2Card)
} else {
player2Cards.Enqueue(player2Card)
player2Cards.Enqueue(player1Card)
}
rounds++
}
*/
_, p1, p2 := PlayGame(player1Cards, player2Cards)
var winningScore uint = 0
if p1.tail - p1.head < p2.tail - p2.head {
for i := p2.head; i < p2.tail; i++ {
winningScore += (p2.tail - i) * uint(p2.arr[i])
}
} else {
for i := p1.head; i < p1.tail; i++ {
winningScore += (p1.tail - i) * uint(p1.arr[i])
}
}
fmt.Println(winningScore)
}
// true = player1, false = player2
func PlayGame(player1 Queue, player2 Queue) (bool, *Queue, *Queue) {
cache1 := make(map[string]bool)
cache2 := make(map[string]bool)
for {
if player1.head == player1.tail || player2.head == player2.tail {
return player2.head == player2.tail, &player1, &player2
}
// Before drawing, check.
player1string := player1.Print()
player2string := player2.Print()
_, exists := cache1[player1string]
if exists {
return true, &player1, &player2
}
_, exists = cache2[player2string]
if exists {
return true, &player1, &player2
}
cache1[player1string] = true
cache2[player2string] = true
player1Card := player1.Dequeue()
player2Card := player2.Dequeue()
if int(player1.tail) - int(player1.head) >= player1Card && int(player2.tail) - int(player2.head) >= player2Card {
// Recursive case!
player1Copy := Queue{
arr: slices.Clone(player1.arr),
head: player1.head,
tail: player1.head + uint(player1Card),
}
player2Copy := Queue{
arr: slices.Clone(player2.arr),
head: player2.head,
tail: player2.head + uint(player2Card),
}
winner, _, _ := PlayGame(player1Copy, player2Copy)
if winner {
player1.Enqueue(player1Card)
player1.Enqueue(player2Card)
} else {
player2.Enqueue(player2Card)
player2.Enqueue(player1Card)
}
} else {
if player1Card > player2Card {
player1.Enqueue(player1Card)
player1.Enqueue(player2Card)
} else {
player2.Enqueue(player2Card)
player2.Enqueue(player1Card)
}
}
}
}
func GetString(arr []int) string {
s := ""
for _, v := range arr {
s += "," + strconv.Itoa(v)
}
return s
}

View File

@ -0,0 +1,75 @@
package main
import (
"fmt"
)
type CustomLinkedList struct {
head *CustomListNode
length int64
}
type CustomListNode struct {
payload int64
next *CustomListNode
}
func (l *CustomLinkedList) prepend(n *CustomListNode) {
second := l.head
l.head = n
l.head.next = second
l.length++
}
func (l *CustomLinkedList) append(n *CustomListNode) {
if l.head == nil {
l.head = n
} else {
node := l.head
for node.next != nil {
node = node.next
}
node.next = n
}
l.length++
}
func (l *CustomLinkedList) appendNextTo(n *CustomListNode, pointer *CustomListNode) {
node := l.head
for node != nil {
if node == pointer {
next := node.next
node.next = n
n.next = next
l.length++
break
}
node = node.next
}
}
func main() {
linkedList := CustomLinkedList{}
linkedList.append(&CustomListNode{payload: 10})
node1 := &CustomListNode{payload: 1}
node2 := &CustomListNode{payload: 2}
node3 := &CustomListNode{payload: 3}
linkedList.append(node1)
linkedList.append(node2)
linkedList.append(node3)
linkedList.appendNextTo(&CustomListNode{payload: 69}, node2)
node := linkedList.head
for node != nil {
fmt.Println(node.payload)
node = node.next
}
fmt.Println("Length: ", linkedList.length)
}

View File

View File

@ -0,0 +1,3 @@
module main
go 1.16

View File

@ -0,0 +1,178 @@
package main
import (
"fmt"
"os"
"regexp"
"strconv"
"strings"
)
type Hex struct {
q int
r int
s int
}
func CreateHex(q int, r int, s int) Hex {
return Hex{
q: q,
r: r,
s: s,
}
}
func (h *Hex) Print() string {
return strconv.Itoa(h.q) + "," + strconv.Itoa(h.r) + "," + strconv.Itoa(h.s)
}
func Count(arr []string, search string) int {
counter := 0
for i := 0; i < len(arr); i++ {
if arr[i] == search {
counter++
}
}
return counter
}
func AdjustValues(hexMap map[string]bool, key string, white *int, black *int) {
v, exists := hexMap[key]
if !exists {
return
}
if v {
*white++
} else {
*black++
}
}
func AddIfMissing(hexMap map[string]bool, hex string) {
_, exists := hexMap[hex]
if !exists {
hexMap[hex] = true
}
}
func AddAdjacents(hexMap map[string]bool, hex string) {
split := strings.Split(hex, ",")
q, _ := strconv.Atoi(split[0])
r, _ := strconv.Atoi(split[1])
s, _ := strconv.Atoi(split[2])
nw := strconv.Itoa(q) + "," + strconv.Itoa(r - 1) + "," + strconv.Itoa(s + 1)
w := strconv.Itoa(q - 1) + "," + strconv.Itoa(r) + "," + strconv.Itoa(s + 1)
sw := strconv.Itoa(q - 1) + "," + strconv.Itoa(r + 1) + "," + strconv.Itoa(s)
se := strconv.Itoa(q) + "," + strconv.Itoa(r + 1) + "," + strconv.Itoa(s - 1)
e := strconv.Itoa(q + 1) + "," + strconv.Itoa(r) + "," + strconv.Itoa(s - 1)
ne := strconv.Itoa(q + 1) + "," + strconv.Itoa(r - 1) + "," + strconv.Itoa(s)
AddIfMissing(hexMap, nw)
AddIfMissing(hexMap, w)
AddIfMissing(hexMap, sw)
AddIfMissing(hexMap, se)
AddIfMissing(hexMap, e)
AddIfMissing(hexMap, ne)
}
func CountAdjacent(hexMap map[string]bool, hex string) (int, int) {
white := 0
black := 0
split := strings.Split(hex, ",")
q, _ := strconv.Atoi(split[0])
r, _ := strconv.Atoi(split[1])
s, _ := strconv.Atoi(split[2])
nw := strconv.Itoa(q) + "," + strconv.Itoa(r - 1) + "," + strconv.Itoa(s + 1)
w := strconv.Itoa(q - 1) + "," + strconv.Itoa(r) + "," + strconv.Itoa(s + 1)
sw := strconv.Itoa(q - 1) + "," + strconv.Itoa(r + 1) + "," + strconv.Itoa(s)
se := strconv.Itoa(q) + "," + strconv.Itoa(r + 1) + "," + strconv.Itoa(s - 1)
e := strconv.Itoa(q + 1) + "," + strconv.Itoa(r) + "," + strconv.Itoa(s - 1)
ne := strconv.Itoa(q + 1) + "," + strconv.Itoa(r - 1) + "," + strconv.Itoa(s)
AdjustValues(hexMap, nw, &white, &black)
AdjustValues(hexMap, w, &white, &black)
AdjustValues(hexMap, sw, &white, &black)
AdjustValues(hexMap, se, &white, &black)
AdjustValues(hexMap, e, &white, &black)
AdjustValues(hexMap, ne, &white, &black)
return white, black
}
func main() {
fmt.Println("Day 24 Part 1")
file, err := os.ReadFile("input.txt")
if err != nil {
panic(err)
}
_content := strings.Split(string(file), "\n")
content := _content[:len(_content) - 1]
directionRegex := regexp.MustCompile("e|se|sw|w|nw|ne")
// true = white, false = black
cache := make(map[string]bool)
for _, line := range content {
matches := directionRegex.FindAllString(line, -1)
nw := Count(matches, "nw")
w := Count(matches, "w")
sw := Count(matches, "sw")
se := Count(matches, "se")
e := Count(matches, "e")
ne := Count(matches, "ne")
hex := CreateHex(ne + e - sw - w, se + sw - ne - nw, w + nw - se - e)
white, exists := cache[hex.Print()]
if !exists {
cache[hex.Print()] = false
} else {
cache[hex.Print()] = !white
}
}
blackTiles := 0
for _, white := range cache {
if !white {
blackTiles++
}
}
fmt.Printf("Part 1: %d\n", blackTiles)
for i := 0; i < 100; i++ {
toFlip := make([]string, 0)
for k := range cache {
AddAdjacents(cache, k)
}
for k, isWhite := range cache {
_, black := CountAdjacent(cache, k)
if isWhite && black == 2 {
toFlip = append(toFlip, k)
} else if !isWhite && (black == 0 || black > 2) {
toFlip = append(toFlip, k)
}
}
for _, k := range toFlip {
cache[k] = !cache[k]
}
myTiles := 0
for _, white := range cache {
if !white {
myTiles++
}
}
fmt.Println(i, myTiles)
}
}

View File

@ -0,0 +1,40 @@
package main
import "fmt"
func main() {
var dividerr int64 = 20201227
// var cardPKey int64 = 5764801
// var doorPKey int64 = 17807724
var cardPKey int64 = 16915772
var doorPKey int64 = 18447943
var cardValue int64 = 1
var cardLoopSize int64 = 0
for cardValue != cardPKey {
cardValue *= 7 // Subject number
cardValue = cardValue % dividerr
cardLoopSize++
}
var doorValue int64 = 1
var doorLoopSize int64 = 0
for doorValue != doorPKey {
doorValue *= 7 // Subject number
doorValue = doorValue % dividerr
doorLoopSize++
}
var part1 int64 = 1
var i int64 = 0
for i = 0; i < cardLoopSize; i++ {
part1 *= doorPKey
part1 = part1 % dividerr
}
fmt.Printf("Part 1: %d %d %d\n", cardLoopSize, doorLoopSize, part1)
}

Binary file not shown.

View File

@ -0,0 +1,70 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day3 {
public static void main(String[] args) {
try {
File myFile = new File("input.txt");
Scanner in = new Scanner(myFile);
String[] trees = new String[323];
int lineLength;
long multiple = 1;
int numOfTrees = 0;
int x = 0;
for (int i = 0; i < 323; i++) {
trees[i] = in.nextLine();
}
lineLength = trees[0].length();
/*Part 1 code
for (String line : trees) {
char current = line.charAt(x % lineLength);
if (current == '#') numOfTrees++;
x = x + 3;
}
*/
for (int dy = 1; dy < 3; dy++) {
for (int dx = 1; dx < 8; dx = dx + 2) {
if (!(dy == 2 && dx > 1)) {
numOfTrees = 0;
x = 0;
for (int i = 0; i < 323; i = i + dy) {
char current = trees[i].charAt(x % lineLength);
if (current == '#') numOfTrees++;
x = x + dx;
}
System.out.println(numOfTrees);
multiple *= numOfTrees;
}
}
}
System.out.println(multiple);
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
}

Binary file not shown.

View File

@ -0,0 +1,133 @@
import java.util.ArrayList;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day4 {
public static void main(String[] args) {
try {
File myFile = new File("input.txt");
Scanner in = new Scanner(myFile);
ArrayList<String> passports = new ArrayList<String>();
String line = "";
String input = "";
while (in.hasNext()) {
input = "";
input = in.nextLine();
if (input.length() == 0) {
passports.add(line);
line = "";
} else {
line += input;
}
}
passports.add(input);
int valid = 0;
for (String current : passports) {
String currentNoSpace = current.replaceAll("\\s","");
String[] fields = currentNoSpace.split(":");
int counter = 0;
String currentField = "";
for (int i = 0; i < fields.length - 1; i++) {
currentField = fields[i].substring(fields[i].length() - 3);
System.out.println("Next value: " + fields[i + 1]);
String value = "";
try {
value = fields[i + 1].substring(0, fields[i + 1].length() - 3);
} catch (Exception e) {
value = "";
}
if (i == fields.length - 2) {
value = fields[i + 1];
}
System.out.println(currentField);
System.out.println(value);
if (currentField.equals("hcl")) {
String HEX_PATTERN = "^#([A-Fa-f0-9]{6})$";
if(value.matches(HEX_PATTERN)) counter++;
} else if (currentField.equals("pid")) {
String DIGITS_PATTERN = "\\d+";
if (value.matches(DIGITS_PATTERN) && value.length() == 9) counter++;
} else if (currentField.equals("ecl")) {
if (value.equals("amb") || value.equals("blu") || value.equals("brn") || value.equals("gry")
|| value.equals("grn") || value.equals("hzl") || value.equals("oth")) counter++;
} else if (currentField.equals("eyr")) {
String DIGITS_PATTERN = "\\d+";
if (value.matches(DIGITS_PATTERN)) {
int year = Integer.parseInt(value);
if (year >= 2020 && year <= 2030) counter++;
}
} else if (currentField.equals("hgt")) {
String DIGITS_PATTERN = "\\d+";
if (value.substring(0, value.length() - 2).matches(DIGITS_PATTERN)) {
if (value.substring(value.length() - 2, value.length()).equals("in")) {
int num = Integer.parseInt(value.substring(0, value.length() - 2));
if (num >= 59 && num <= 76) counter++;
} else if (value.substring(value.length() - 2, value.length()).equals("cm")) {
int num = Integer.parseInt(value.substring(0, value.length() - 2));
if (num >= 150 && num <= 193) counter++;
}
}
} else if (currentField.equals("byr")) {
String DIGITS_PATTERN = "\\d+";
if (value.matches(DIGITS_PATTERN)) {
int year = Integer.parseInt(value);
if (year >= 1920 && year <= 2002) counter++;
}
} else if (currentField.equals("iyr")) {
String DIGITS_PATTERN = "\\d+";
if (value.matches(DIGITS_PATTERN)) {
int year = Integer.parseInt(value);
if (year >= 2010 && year <= 2020) counter++;
}
}
}
if (counter == 7) valid++;
counter = 0;
}
System.out.println("Valid: " + valid);
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
}

Binary file not shown.

View File

@ -0,0 +1,63 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day5 {
public static void main(String[] args) {
File inputs = new File("input.txt");
try {
Scanner in = new Scanner(inputs);
String[] input = new String[884];
for (int i = 0; i < 884; i++) input[i] = in.nextLine();
int highest = 0;
int lowest = 99999999;
ArrayList<Integer> seatIDs = new ArrayList<Integer>();
for (String line : input) {
int row = binaryConvertion(line.substring(0, line.length() - 3), 'B');
int collumn = binaryConvertion(line.substring(line.length() - 3), 'R');
int calculation = row * 8 + collumn;
if (calculation > highest) highest = calculation;
else if (calculation < lowest) lowest = calculation;
seatIDs.add(calculation);
}
for (int i = lowest; i <= highest; i++) {
if (seatIDs.contains(i) == false) {
System.out.println(i);
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static int binaryConvertion(String givenInputs, char one) {
int counter = 0;
for (int i = givenInputs.length() - 1; i >= 0; i--) {
if (givenInputs.charAt(i) == one) {
counter += Math.pow(2, givenInputs.length() - i - 1);
}
}
return counter;
}
}

Binary file not shown.

View File

@ -0,0 +1,64 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
class day6 {
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
ArrayList<String> inputs = new ArrayList<String>();
String line = "";
String input = "";
while (in.hasNext()) {
input = "";
input = in.nextLine();
if (input.length() == 0) {
inputs.add(line.substring(0, line.length() - 1));
line = "";
} else {
line += input + ",";
}
}
inputs.add(line.substring(0, line.length() - 1));
int sum = 0;
for (String current : inputs) {
HashMap<Character, Integer> map = new HashMap<>();
String[] currentSplit = current.split(",");
for (String single : currentSplit) {
for (char c : single.toCharArray()) {
if (map.get(c) == null) {
map.put(c, 1);
} else {
map.put(c, map.get(c) + 1);
}
}
}
for (char c : map.keySet()) {
if (map.get(c) == currentSplit.length) sum++;
}
}
System.out.printf("Total sum %d", sum);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,117 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.ArrayList;
class day7 {
public static HashMap<String, ArrayList<BagInfo>> map = new HashMap<>();
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
String[] inputs = new String[594];
for (int i = 0; i < 594; i++) {
inputs[i] = in.nextLine();
}
for (String bag : inputs) {
String[] bags = bag.split(" bags contain ");
String outerBag = bags[0];
String innerBag = bags[1];
innerBag = innerBag.replace("bags", "").replace("bag", "");
innerBag = innerBag.substring(0, innerBag.length() - 2);
if (innerBag.equals("no other")) {
map.put(outerBag, new ArrayList<BagInfo>());
} else {
String[] Innerbags = innerBag.split(" , ");
ArrayList<BagInfo> innerBagList = new ArrayList<>();
for (String innerbag : Innerbags) {
BagInfo current = new BagInfo();
current.quantity = Integer.parseInt(innerbag.substring(0, 1));
current.bag = innerbag.substring(2);
innerBagList.add(current);
}
map.put(outerBag, innerBagList);
}
}
int sum = 0;
//Part 1 solution
/*for (String bag : map.keySet()) {
if (isBagInside(bag, "shiny gold")) {
sum++;
};
}*/
//Part 2 solution
//System.out.println(map);
System.out.println(howManyBags("shiny gold") - 1);
//System.out.println(sum);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
public static int howManyBags(String bagName) {
ArrayList<BagInfo> innerBags = map.get(bagName);
if (innerBags.size() == 0)
return 1;
int total = 1;
for (BagInfo innerbag : innerBags) {
total += (innerbag.quantity * howManyBags(innerbag.bag));
}
return total;
}
public static boolean isBagInside(String bagName, String searchBag) {
ArrayList<BagInfo> innerBags = map.get(bagName);
if (innerBags.size() != 0) {
for (BagInfo innerbag : innerBags) {
if (innerbag.bag.equals(searchBag)) return true;
}
for (BagInfo innerbag : innerBags) {
//Don't return to early, my god this took me ages.
boolean idkwhattocallthis = isBagInside(innerbag.bag, searchBag);
if (idkwhattocallthis) return true;
}
} else {
return false;
}
return false;
}
}
class BagInfo {
public int quantity;
public String bag;
public String toString() {
return "Quantity: " + quantity + " | BagName: " + bag;
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,109 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
class day8 {
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
ArrayList<Instruction> instructions = new ArrayList<>();
while (in.hasNext()) {
String[] split = in.nextLine().split(" ");
Instruction current = new Instruction(split[0], Integer.parseInt(split[1]), false);
instructions.add(current);
}
boolean done = false;
int currentChangingInstruction = 0;
ArrayList<Integer> checked = new ArrayList<>();
while (!done) {
while (instructions.get(currentChangingInstruction).instruction.equals("acc") || checked.contains(currentChangingInstruction)) {
currentChangingInstruction++;
}
checked.add(currentChangingInstruction);
Instruction currentChange = instructions.get(currentChangingInstruction);
if (currentChange.instruction.equals("jmp")) currentChange.instruction = "nop";
else currentChange.instruction = "jmp";
instructions.set(currentChangingInstruction, currentChange);
for (Instruction i : instructions) System.out.println(i);
int acc = 0;
int instructionIndex = 0;
Instruction currentInstruction = instructions.get(instructionIndex);
while (currentInstruction.ran == false && done == false) {
instructions.set(instructionIndex, new Instruction(currentInstruction.instruction, currentInstruction.arg, true));
if (currentInstruction.instruction.equals("acc")) {
acc += currentInstruction.arg;
instructionIndex++;
} else if (currentInstruction.instruction.equals("jmp")) {
if (currentInstruction.arg + instructionIndex >= 0 && currentInstruction.arg + instructionIndex <= instructions.size()) {
instructionIndex += currentInstruction.arg;
} else {
instructionIndex = instructions.size() % currentInstruction.arg;
}
} else {
instructionIndex++;
}
if (instructionIndex == instructions.size()) {
done = true;
System.out.println("Acc: " + acc);
} else {
currentInstruction = instructions.get(instructionIndex);
}
}
if (currentChange.instruction.equals("jmp")) currentChange.instruction = "nop";
else currentChange.instruction = "jmp";
instructions.set(currentChangingInstruction, currentChange);
for (int i = 0; i < instructions.size(); i++) {
Instruction changeRan = instructions.get(i);
changeRan.ran = false;
instructions.set(i, changeRan);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
class Instruction {
public String instruction;
public int arg;
public boolean ran;
public Instruction(String instruction, int arg, boolean ran) {
this.instruction = instruction;
this.arg = arg;
this.ran = ran;
}
public String toString() {
return "Instruction : " + this.instruction + " | Arg: " + this.arg + " | Ran: " + this.ran;
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,101 @@
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
class day9 {
public static void main(String[] args) {
File myFile = new File("input.txt");
try {
Scanner in = new Scanner(myFile);
ArrayList<Long> nums = new ArrayList<>();
while (in.hasNext()) {
nums.add(Long.parseLong(in.nextLine()));
}
//final int preamble = 25;
//int lower = 0;
long target = 1309761972;
for (int i = 0; i < nums.size() - 1; i++) {
boolean over = false;
long sum = 0;
ArrayList<Long> currentSet = new ArrayList<>();
for (int j = i; j < nums.size() && over == false; j++) {
sum += nums.get(j);
currentSet.add(nums.get(j));
if (sum == target) {
long highest = 0;
long lowest = Long.MAX_VALUE;
for (int k = 0; k < currentSet.size(); k++) {
long current = currentSet.get(k);
if (current < lowest) lowest = current;
if (current > highest) highest = current;
}
over = true;
System.out.println("Lowest: " + lowest);
System.out.println("highest: " + highest);
System.out.println(highest + lowest);
break;
} else if (sum > target) {
over = true;
}
}
}
//Part 1, very inefficient code, had no time to do this one today
//Made easier using a stack and an array to which the combination of numbers in the stack would add up to
//Pop and remove from the stack and remove the last 25 items from array/list
//And that would be the most efficient with an efficiency of O(n^2)? instead of O(n^3) - I think, not sure
/*for (int currentNum = preamble; currentNum < nums.size(); currentNum++) {
boolean adds = false;
for (int i = currentNum - preamble; i < currentNum - 1; i++) {
for (int j = i + 1; j < currentNum; j++) {
System.out.printf("Adding %d and %d, Current Num: %d \n", nums.get(i), nums.get(j), nums.get(currentNum));
if (nums.get(i) + nums.get(j) == nums.get(currentNum)) {
adds = true;
}
}
}
System.out.println(adds);
if (!adds) {
System.out.println(nums.get(currentNum));
break;
}
}*/
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,7 @@
# Advent Of Code 2021
The challenge for me this year is to use VIM as a text editor alone, as well as Golang for the programming language.
## Update
I have now given up on vim as I like VSCode too much and know it too well.

View File

@ -0,0 +1,41 @@
package day1
import (
"bytes"
"strconv"
)
func Run(dat []byte) (int, int) {
lines := bytes.Split(dat, []byte("\n"))
increase := 0
increaseWindow := 0
for i := 0; i < len(lines) - 1; i++ {
num1, _ := strconv.Atoi(string(lines[i]))
num2, _ := strconv.Atoi(string(lines[i + 1]))
if num1 < num2 {
increase++
}
}
for i := 0; i < len(lines) - 3; i++ {
num1, _ := strconv.Atoi(string(lines[i]))
num2, _ := strconv.Atoi(string(lines[i + 1]))
num3, _ := strconv.Atoi(string(lines[i + 2]))
num4, _ := strconv.Atoi(string(lines[i + 3]))
if num1 + num2 + num3 < num2 + num3 + num4 {
increaseWindow++
}
}
return increase, increaseWindow
}

View File

@ -0,0 +1,91 @@
package day13
import (
"bytes"
"fmt"
"strconv"
"strings"
)
type coord struct {
x int
y int
}
func Run(dat []byte) (int, int) {
splitBytes := bytes.Split(dat, []byte{10, 10})
stringCoords := strings.Split(string(splitBytes[0]), "\n")
stringInstructions := strings.Split(string(splitBytes[1]), "\n")
coordMap := make(map[coord]int)
for _, line := range stringCoords {
splitLine := strings.Split(line, ",")
x, _ := strconv.Atoi(splitLine[0])
y, _ := strconv.Atoi(splitLine[1])
coordMap[coord{x: x, y: y}] = coordMap[coord{x: x, y: y}] + 1
}
part1 := 0
part2 := 0
for i := 0; i < len(stringInstructions); i++ {
splitInstruction := strings.Split(stringInstructions[i], "fold along ")
number, _ := strconv.Atoi(string(splitInstruction[1][2:]))
if splitInstruction[1][0] == 'y' {
for k, _ := range coordMap {
if k.y > number {
delete(coordMap, k)
coordMap[coord{x: k.x, y: k.y - ((k.y - number) * 2)}] += 1
}
}
} else {
for k, _ := range coordMap {
if k.x > number {
delete(coordMap, k)
coordMap[coord{x: k.x - ((k.x - number) * 2), y: k.y}] = 1
}
}
}
if (i == 0) {
for k, _ := range coordMap {
if coordMap[k] > 0 {
part1++
}
}
}
}
highestX := 0
highestY := 0
for k, _ := range coordMap {
if k.x > highestX {
highestX = k.x
}
if k.y > highestY {
highestY = k.y
}
}
for i := 0; i <= highestY; i++ {
for j := 0; j <= highestX; j++ {
if coordMap[coord{x: j, y: i}] > 0 {
fmt.Print("#")
} else {
fmt.Print(".")
}
}
fmt.Println()
}
return part1, part2
}

View File

@ -0,0 +1,47 @@
package day14
import (
"strings"
)
func Run(dat []byte) (int64, int64) {
lines := strings.Split(string(dat), "\n")
template := lines[0]
patterns := lines[2 : len(lines) - 1]
pairInsertions := make(map[string]string, len(patterns))
for i := 0; i < len(patterns); i++ {
pairSplit := strings.Split(patterns[i], " ")
pairInsertions[pairSplit[0]] = pairSplit[2]
}
for round := 0; round < 40; round++ {
newTemplate := string(template[0])
for i := 0; i < len(template) - 1; i++ {
pair := template[i:i + 2]
newLetter := pairInsertions[pair]
newTemplate += newLetter + string(pair[1])
}
template = newTemplate
}
letterMap := make(map[byte]int64, 0)
for i := 0; i < len(template); i++ {
letterMap[template[i]] += 1
}
highest := int64(0)
lowest := int64(999999)
for _, v := range letterMap {
if v > highest {
highest = v
} else if v < lowest {
lowest = v
}
}
return (highest - lowest), 0
}

View File

@ -0,0 +1,44 @@
package day2
import (
"bytes"
"strconv"
)
func Run(dat []byte) (int, int) {
dat = dat[:len(dat) - 1]
lines := bytes.Split(dat, []byte("\n"))
vertical := 0
horizontal := 0
part2vertical := 0
part2horizontal := 0
aim := 0
for _, value := range lines {
splitInstruction := bytes.Split(value, []byte(" "))
direction := string(splitInstruction[0])
scale, _ := strconv.Atoi(string(splitInstruction[1]))
if direction == "forward" {
horizontal += scale
part2horizontal += scale
part2vertical += aim * scale
} else if direction == "up" {
vertical -= scale
aim -= scale
} else if direction == "down" {
vertical += scale
aim += scale
}
}
return vertical * horizontal, part2vertical * part2horizontal
}

View File

@ -0,0 +1,101 @@
package day3
import (
"bytes"
)
func Run(dat []byte) (int, int) {
lines := bytes.Split(dat, []byte("\n"))
lineLength := len(lines[0])
commonMap := make(map[int]int)
for _, line := range lines {
splitLine := bytes.Split(line, []byte(""))
for i := 0; i < len(splitLine); i++ {
//Negative means that 0 is more common
if splitLine[i][0] == 0x31 {
commonMap[i] = commonMap[i] - 1
} else {
commonMap[i] = commonMap[i] + 1
}
}
}
gamma := 0
epsilon := 0
for key, value := range commonMap {
if value > 0 {
gamma += intExponent(2, lineLength - key - 1)
} else {
epsilon += intExponent(2, lineLength - key - 1)
}
}
return gamma * epsilon, part2(lines[:len(lines) - 1], true, 0) *
part2(lines[:len(lines) - 1], false, 0)
}
func part2(givenLines [][]byte, higher bool, checkPosition int) int {
if len(givenLines) == 1 {
returnValue := 0
for i := len(givenLines[0]) - 1; i >= 0; i-- {
if givenLines[0][len(givenLines[0]) - 1 - i] == 0x31 {
returnValue += intExponent(2, i)
}
}
return returnValue
} else {
oneLines := make([][]byte, 0)
zeroLines := make([][]byte, 0)
for _, line := range givenLines {
if line[checkPosition] == 0x31 {
oneLines = append(oneLines, line)
} else {
zeroLines = append(zeroLines, line)
}
}
if higher {
if len(oneLines) >= len(zeroLines) {
return part2(oneLines, higher, checkPosition + 1)
} else if len(oneLines) < len(zeroLines) {
return part2(zeroLines, higher, checkPosition + 1)
}
} else {
if len(oneLines) >= len(zeroLines) {
return part2(zeroLines, higher, checkPosition + 1)
} else if len(oneLines) < len(zeroLines) {
return part2(oneLines, higher, checkPosition + 1)
}
}
}
return 0
}
func intExponent(base int, power int) int {
result := 1
for i := 1; i <= power; i++ {
result *= base
}
return result
}

View File

@ -0,0 +1,199 @@
package day4
import (
"strconv"
"strings"
)
func Run(dat []byte) (int, int) {
stringData := string(dat)
lines := strings.Split(stringData, "\n")
numbersDrawn := strings.Split(lines[0], ",")
lines = lines[2:]
currentBoard := make([][]int, 0)
boards := make([][][]int, 0)
for _, line := range lines {
if len(line) == 0 {
boards = append(boards, currentBoard)
currentBoard = make([][]int, 0)
} else {
currentLine := strings.Split(line, " ")
intLine := make([]int, 5)
counter := 0
for i := 0; i < len(currentLine); i++ {
if (len(currentLine[i]) > 0) {
intLine[counter], _ = strconv.Atoi(currentLine[i])
counter++
}
}
currentBoard = append(currentBoard, intLine)
}
}
/**
* There is probably a better way of doing this
*/
boardCheck := make([][][]int, 0)
for i := 0; i < len(boards); i++ {
boardCheck = append(boardCheck, [][]int{{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}})
}
boardComplete := false
winningIndex := 0
calledNumber := 0
//Part 1
for i := 0; i < len(numbersDrawn) && !boardComplete; i++ {
intNumber, _ := strconv.Atoi(numbersDrawn[i])
for i, board := range boards {
checkBoard(board, intNumber, &boardCheck[i])
if checkComplete(boardCheck[i]) {
boardComplete = true
winningIndex = i
calledNumber = intNumber
break
}
}
}
boardCheck = make([][][]int, 0)
for i := 0; i < len(boards); i++ {
boardCheck = append(boardCheck, [][]int{{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0},
{0, 0, 0, 0, 0}})
}
completedBoards := make([]int, 0)
lastFound := -1
part2Num := 0
for i := 0; i < len(numbersDrawn) && lastFound == -1; i++ {
intNumber, _ := strconv.Atoi(numbersDrawn[i])
for i, board := range boards {
if !contains(completedBoards, i) {
checkBoard(board, intNumber, &boardCheck[i])
if checkComplete(boardCheck[i]) {
completedBoards = append(completedBoards, i)
if len(completedBoards) == len(boards) {
part2Num = intNumber
lastFound = i
break
}
}
}
}
}
unmarkedNumbers := 0
partUnmarkedNumbers := 0
for i := 0; i < len(boards[winningIndex]); i++ {
for j := 0; j < len(boards[winningIndex][0]); j++ {
if boardCheck[winningIndex][i][j] == 0 {
unmarkedNumbers += boards[winningIndex][i][j]
}
}
}
for i := 0; i < len(boards[lastFound]); i++ {
for j := 0; j < len(boards[lastFound][0]); j++ {
if boardCheck[lastFound][i][j] == 0 {
partUnmarkedNumbers += boards[lastFound][i][j]
}
}
}
return calledNumber * unmarkedNumbers, part2Num * partUnmarkedNumbers
}
func contains(arr []int, num int) bool {
for _, e := range arr {
if e == num {
return true
}
}
return false
}
func checkBoard(board [][]int, numberDrawn int, boardCheck *[][]int) {
for i := 0; i < len(board); i++ {
for j := 0; j < len(board[0]); j++ {
if board[i][j] == numberDrawn {
(*boardCheck)[i][j] = 1
}
}
}
}
//Return -1 if board is not complete
func checkComplete(boardCheck [][]int) bool {
//Check rows
for i := 0; i < len(boardCheck); i++ {
rowComplete := true
for j := 0; j < len(boardCheck[0]); j++ {
if boardCheck[i][j] == 0 {
rowComplete = false
}
}
if rowComplete {
return true
}
}
//Check cols
for i := 0; i < len(boardCheck); i++ {
colComplete := true
for j := 0; j < len(boardCheck[0]); j++ {
if boardCheck[j][i] == 0 {
colComplete = false
}
}
if colComplete {
return true
}
}
return false
}

View File

@ -0,0 +1,119 @@
package day5
import (
"math"
"strconv"
"strings"
)
type Coord struct {
x int
y int
}
type coordPairs struct {
point1 Coord
point2 Coord
}
func Run(dat []byte) (int, int) {
stringDat := strings.Split(string(dat), "\n")
coordList := make([]coordPairs, len(stringDat))
for i := 0; i < len(stringDat); i++ {
coords := strings.Split(stringDat[i], " -> ")
firstCoord := strings.Split(coords[0], ",")
secondCoord := strings.Split(coords[1], ",")
x1, _ := strconv.Atoi(firstCoord[0])
y1, _ := strconv.Atoi(firstCoord[1])
x2, _ := strconv.Atoi(secondCoord[0])
y2, _ := strconv.Atoi(secondCoord[1])
coordList[i] = coordPairs{Coord{x: x1, y: y1}, Coord{x: x2, y: y2}}
}
coordMap := make(map[Coord]int)
part2CoordMap := make(map[Coord]int)
for _, c := range coordList {
if (c.point1.x == c.point2.x) {
lowY := int(math.Min(float64(c.point1.y), float64(c.point2.y)))
highY := int(math.Max(float64(c.point1.y), float64(c.point2.y)))
for i := lowY; i <= highY; i++ {
coordMap[Coord{x: c.point1.x, y: i}] = coordMap[Coord{x: c.point1.x, y: i}] + 1
part2CoordMap[Coord{x: c.point1.x, y: i}] = part2CoordMap[Coord{x: c.point1.x, y: i}] + 1
}
} else if (c.point1.y == c.point2.y) {
lowX := int(math.Min(float64(c.point1.x), float64(c.point2.x)))
highX := int(math.Max(float64(c.point1.x), float64(c.point2.x)))
for i := lowX; i <= highX; i++ {
coordMap[Coord{x: i, y: c.point1.y}] = coordMap[Coord{x: i, y: c.point1.y}] + 1
part2CoordMap[Coord{x: i, y: c.point1.y}] = part2CoordMap[Coord{x: i, y: c.point1.y}] + 1
}
} else {
if c.point1.x < c.point2.x {
step := 0
if c.point1.y - c.point2.y > 0 {
step = -1
} else {
step = 1
}
counter := c.point1.y
for i := c.point1.x; i <= c.point2.x; i++ {
part2CoordMap[Coord{x: i, y: counter}] = part2CoordMap[Coord{x: i, y: counter}] + 1
counter += step
}
} else {
step := 0
if c.point2.y - c.point1.y > 0 {
step = -1
} else {
step = 1
}
counter := c.point2.y
for i := c.point2.x; i <= c.point1.x; i++ {
part2CoordMap[Coord{x: i, y: counter}] = part2CoordMap[Coord{x: i, y: counter}] + 1
counter += step
}
}
}
}
part1 := 0
part2 := 0
for _, value := range coordMap {
if value > 1 {
part1++
}
}
for _, value := range part2CoordMap {
if value > 1 {
part2++
}
}
return part1, part2
}

View File

@ -0,0 +1,69 @@
package day6
import (
"strconv"
"strings"
)
func Run(dat []byte) (int, int) {
stringDat := string(dat)
fish := strings.Split(stringDat, ",")
/**
* We do not need to keep track of every fish,
* We only need to keep track of the number of fish at a certain age.
* Which is much more efficient than an exponentially increasing array.
*/
fishMap := make(map[int]int)
part2FishMap := make(map[int]int)
for _, value := range fish {
age, _ := strconv.Atoi(value)
fishMap[age] = fishMap[age] + 1
part2FishMap[age] = part2FishMap[age] + 1
}
for day := 1; day <= 80; day++ {
readyFish := fishMap[0]
for i := 1; i <= 8; i++ {
fishMap[i - 1] = fishMap[i]
}
fishMap[6] = fishMap[6] + readyFish
fishMap[8] = readyFish
}
var part1 int = 0
for _, num := range fishMap {
part1 += num
}
//-------------------
for day := 1; day <= 256; day++ {
readyFish := part2FishMap[0]
for i := 1; i <= 8; i++ {
part2FishMap[i - 1] = part2FishMap[i]
}
part2FishMap[6] = part2FishMap[6] + readyFish
part2FishMap[8] = readyFish
}
var part2 int = 0
for _, num := range part2FishMap {
part2 += num
}
return part1, part2
}

View File

@ -0,0 +1,53 @@
package day7
import (
"fmt"
"math"
"sort"
"strconv"
"strings"
)
func Run(dat []byte) (int, int) {
fmt.Println("Day 7")
stringDat := strings.Split(string(dat), ",")
crabList := make([]int, len(stringDat))
for i, value := range stringDat {
num, _ := strconv.Atoi(value)
crabList[i] = num
}
sort.Ints(crabList)
median := crabList[len(crabList) / 2]
lowest := 100000000000
part2lowest := 10000000000000
for i := median - 200; i <= median + 200; i++ {
difference := 0
part2difference := 0
for _, n := range crabList {
currentDifference := math.Abs(float64(i) - float64(n))
difference += int(currentDifference)
part2difference += int((currentDifference / 2) * (currentDifference + 1))
}
if difference < lowest {
lowest = difference
}
if part2difference < part2lowest {
part2lowest = part2difference
}
}
return lowest, part2lowest
}

View File

@ -0,0 +1,314 @@
package day8
import (
"sort"
"strconv"
"strings"
)
type Line struct {
signals []string
answer []string
}
//
// This struct will be used to store the possible corresponding patterns
// A = Top line, B = Left top, ..., I used the same pattern in the AoC problem
//
type Possible struct {
possible []string
}
func Run(dat []byte) (int, int) {
lines := strings.Split(string(dat), "\n")
lineArray := make([]Line, len(lines))
for i, v := range lines {
splitLine := strings.Split(v, " | ")
lineArray[i] = Line{signals: strings.Split(splitLine[0], " "),
answer: strings.Split(splitLine[1], " ")}
}
part1 := 0
for _, value := range lineArray {
for _, signal := range value.answer {
if len(signal) == 2 || len(signal) == 3 || len(signal) == 4 || len(signal) == 7 {
part1++
}
}
}
part2 := 0
for _, line := range lineArray {
currentPossible := make(map[string]Possible)
//#1 - Get the unique ones.
//#1.1 - Get the number one
one := getFromLength(line.signals, 2)[0]
currentPossible[string(one[0])] = Possible{possible: []string{"C", "F"}}
currentPossible[string(one[1])] = Possible{possible: []string{"C", "F"}}
//#1.2 - Get number 7 to work out first link
seven := getFromLength(line.signals, 3)[0]
topLink := getOddLetter(seven, one)[0]
currentPossible[topLink] = Possible{possible: []string{"A"}}
//#1.3 - Get the number 4.
four := getFromLength(line.signals, 4)[0]
oddLetters := getOddLetter(four, one)
currentPossible[oddLetters[0]] = Possible{possible: []string{"B", "D"}}
currentPossible[oddLetters[1]] = Possible{possible: []string{"B", "D"}}
//#1.4 - Get the number 8.
//The 8 will contain the top link which we already know.
eight := getFromLength(line.signals, 7)[0]
oddLetters = getOddLetter(eight, four)
for _, c := range oddLetters {
if c != topLink {
currentPossible[c] = Possible{possible: []string{"E", "G"}}
}
}
//#2 - Get a number with 5 segments on.
// We want to get a 3, which contains all of the 7s
// Choose one that thas the top segment.
fiveLengthNum := getFromLength(line.signals, 5)
three := ""
for _, s := range fiveLengthNum {
contains := true
for _, c := range seven {
if !strings.Contains(s, string(c)) {
contains = false
break
}
}
if contains {
three = s
break
}
}
//#2.1 Extra segments in 3 but not in 7
extraLetters := ""
commonLetters := ""
for _, c := range three {
if !strings.Contains(seven, string(c)) {
extraLetters += string(c)
} else {
if string(c) != topLink {
commonLetters += string(c)
}
}
}
c1 := currentPossible[string(extraLetters[0])].possible[0]
c2 := currentPossible[string(extraLetters[0])].possible[1]
c3 := currentPossible[string(extraLetters[1])].possible[0]
c4 := currentPossible[string(extraLetters[1])].possible[1]
//D first then G
if c1 == "D" && c3 == "G" {
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
} else if c1 == "G" && c3 == "D" {
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
} else if c1 == "D" && c4 == "G" {
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
} else if c1 == "G" && c4 == "D" {
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
} else if c2 == "D" && c3 == "G" {
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
} else if c2 == "G" && c3 == "D" {
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
} else if c2 == "D" && c4 == "G" {
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
} else if c2 == "G" && c4 == "D" {
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
}
purgeMap(currentPossible)
//#3 - Now all that is left is to find C & F
//We can use 6 which contains only contains F
//Get letters of remaining
remainingNotFound := make([]string, 0)
for k, v := range currentPossible {
if len(v.possible) > 1 {
remainingNotFound = append(remainingNotFound, k)
}
}
sixLengthNum := getFromLength(line.signals, 6)
remainingNotFoundLetter := ""
remainingNotFoundLetter2 := ""
for _, possibleNum := range sixLengthNum {
reminingNotFoundNum := 0
for i := 0; i < len(possibleNum); i++ {
if string(possibleNum[i]) == remainingNotFound[0] {
reminingNotFoundNum++
remainingNotFoundLetter = remainingNotFound[0]
remainingNotFoundLetter2 = remainingNotFound[1]
} else if string(possibleNum[i]) == remainingNotFound[1] {
reminingNotFoundNum++
remainingNotFoundLetter = remainingNotFound[1]
remainingNotFoundLetter2 = remainingNotFound[0]
}
}
if reminingNotFoundNum == 1 {
break
}
}
currentPossible[remainingNotFoundLetter] = Possible{possible: []string{"F"}}
currentPossible[remainingNotFoundLetter2] = Possible{possible: []string{"C"}}
answer := ""
for _, testNum := range line.answer {
testNumArray := make([]string, 0)
for i := 0; i < len(testNum); i++ {
testNumArray = append(testNumArray, currentPossible[string(testNum[i])].possible[0])
}
answer += getNum(testNumArray)
}
numAnswer, _ := strconv.Atoi(answer)
part2 += numAnswer
}
return part1, part2
}
func purgeMap(givenMap map[string]Possible) {
singleValues := make([]string, 0)
for _, v := range givenMap {
if len(v.possible) == 1 {
singleValues = append(singleValues, v.possible[0])
}
}
for k, v := range givenMap {
//Check that any of the single values are in v
newValues := make([]string, 0)
for _, singleValue := range v.possible {
if !containsInArray(singleValues, singleValue) {
newValues = append(newValues, singleValue)
}
}
if len(newValues) > 0 {
givenMap[k] = Possible{possible: newValues}
}
}
}
func getNum(arr []string) string {
sort.Strings(arr)
if equals(arr, []string{"A", "B", "C", "E", "F", "G"}) {
return "0"
} else if equals(arr, []string{"C", "F"}) {
return "1"
} else if equals(arr, []string{"A", "C", "D", "E", "G"}) {
return "2"
} else if equals(arr, []string{"A", "C", "D", "F", "G"}) {
return "3"
} else if equals(arr, []string{"B", "D", "C", "F"}) {
return "4"
} else if equals(arr, []string{"A", "B", "D", "F", "G"}) {
return "5"
} else if equals(arr, []string{"A", "B", "D", "E", "F", "G"}) {
return "6"
} else if equals(arr, []string{"A", "C", "F"}) {
return "7"
} else if equals(arr, []string{"A", "B", "C", "D", "E", "F", "G"}) {
return "8"
} else if equals(arr, []string{"A", "B", "C", "D", "F", "G"}) {
return "9"
}
return ""
}
func getFromLength(arr []string, length int) []string {
returnArray := make([]string, 0)
for _, v := range arr {
if len(v) == length {
returnArray = append(returnArray, v)
}
}
return returnArray
}
//First parameter is the bigger array
func getOddLetter(string1 string, string2 string) []string {
returnArray := make([]string, 0)
for _, v := range string1 {
if !contains(string2, v) {
returnArray = append(returnArray, string(v))
}
}
return returnArray
}
func contains(givenString string, value rune) bool {
for _, v := range givenString {
if v == value {
return true
}
}
return false
}
func containsInArray(givenArr []string, char string) bool {
for _, v := range givenArr {
if v == char {
return true
}
}
return false
}
func equals(arr1 []string, arr2 []string) bool {
sort.Strings(arr1)
sort.Strings(arr2)
for i, v := range arr1 {
if v != arr2[i] {
return false
}
}
return true
}

3
AdventOfCode2021/go.mod Normal file
View File

@ -0,0 +1,3 @@
module johncosta.tech/AdventOfCode2021
go 1.17

75
AdventOfCode2021/main.go Normal file
View File

@ -0,0 +1,75 @@
package main
import (
"fmt"
"io/ioutil"
"time"
"johncosta.tech/AdventOfCode2021/day14"
)
func main() {
fmt.Println("---------------------------------------")
fmt.Println("Advent of Code 2021")
fmt.Println("---------------------------------------")
start := time.Now()
/*day1input, _ := ioutil.ReadFile("day1/day1.txt")
day2input, _ := ioutil.ReadFile("day2/day2.txt")
day3input, _ := ioutil.ReadFile("day3/day3.txt")
day4input, _ := ioutil.ReadFile("day4/day4.txt")
day5input, _ := ioutil.ReadFile("day5/day5.txt")
day6input, _ := ioutil.ReadFile("day6/day6.txt")
day7input, _ := ioutil.ReadFile("day7/day7.txt")
day8input, _ := ioutil.ReadFile("day8/day8.txt")
day13input, _ := ioutil.ReadFile("day13/day13.txt")*/
day14input, _ := ioutil.ReadFile("day14/day14.txt")
dayTime := time.Now()
/*day1part1, day1part2 := day1.Run(day1input)
printAnswers(1, time.Since(dayTime), day1part1, day1part2)
day2part1, day2part2 := day2.Run(day2input)
printAnswers(2, time.Since(dayTime), day2part1, day2part2)
day3part1, day3part2 := day3.Run(day3input)
printAnswers(3, time.Since(dayTime), day3part1, day3part2)
day4part1, day4part2 := day4.Run(day4input)
printAnswers(4, time.Since(dayTime), day4part1, day4part2)
day5part1, day5part2 := day5.Run(day5input)
printAnswers(5, time.Since(dayTime), day5part1, day5part2)
day6part1, day6part2 := day6.Run(day6input)
printAnswers(6, time.Since(dayTime), day6part1, day6part2)
day7part1, day7part2 := day7.Run(day7input)
printAnswers(7, time.Since(dayTime), day7part1, day7part2)
day8part1, day8part2 := day6.Run(day8input)
printAnswers(8, time.Since(dayTime), day8part1, day8part2)
day13part1, _ := day13.Run(day13input)
printAnswers(13, time.Since(dayTime), day13part1, 0)*/
day14part1, day14part2 := day14.Run(day14input)
printAnswers(8, time.Since(dayTime), day14part1, day14part2)
elapsed := time.Since(start)
fmt.Printf("Total Time taken: %v \n", elapsed)
fmt.Println("---------------------------------------")
}
func printAnswers(day int, time time.Duration, part1 int64, part2 int64) {
fmt.Println("---------------------------------------")
fmt.Printf("Day %v \n", day)
fmt.Printf("Part 1: %v \n", part1)
fmt.Printf("Part 2: %v \n", part2)
fmt.Printf("Time Taken: %v \n", time)
fmt.Println("---------------------------------------")
}

View File

@ -0,0 +1,3 @@
# Advent of Code 2022
This year I am sticking to Typescript, a language I use basically everyday. The only spicy thing I am doing this year is using Bun.js as a JavaScript runner, it has been making some headlines recently with its performance.

BIN
AdventOfCode2022/bun.lockb Executable file

Binary file not shown.

View File

@ -0,0 +1,6 @@
{
"watch": ["src"],
"ext": ".ts,.js",
"ignore": [],
"exec": "bun run start"
}

View File

@ -0,0 +1,16 @@
{
"name": "AdventOfCode2022",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "bun src/index.ts"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bun-types": "^0.3.0",
"nodemon": "^2.0.20"
}
}

View File

@ -0,0 +1,18 @@
import { DayFunc } from "..";
export const Day1: DayFunc = (input) => {
const elfFood: number[][] = input
.split("\n\n")
.map((i) => i.split("\n"))
.map((i) => i.map((j) => parseInt(j)));
let highest = [0, 0, 0];
elfFood.forEach((n) => {
const h = n.reduce((prev, current) => (current += prev));
const index = highest.findIndex(v => v < h);
if (index !== -1) highest[index] = h;
highest.sort();
});
return [highest[0], highest.reduce((p, c) => c += p)];
};

View File

@ -0,0 +1,42 @@
import { DayFunc } from "..";
export const Day10: DayFunc = (input) => {
const parsed = input.trim().split('\n').map(v => {
const s = v.split(' ');
if (s.length === 1) return [s[0]];
return [s[0], parseInt(s[1])];
});
let x = 1;
let cycles: number[] = [x];
parsed.forEach(i => {
if (i[0] === "noop") {
cycles.push(x);
} else {
cycles.push(x);
cycles.push(x);
x += i[1] as number;
}
});
const part1 = cycles[20] * 20 + cycles[60] * 60 + cycles[100] * 100 + cycles[140] * 140 + cycles[180] * 180 + cycles[220] * 220;
let outStr = "";
for (let i = 1; i < cycles.length; i++) {
if ((i - 1) % 40 === 0) {
outStr += '\n';
}
if (cycles[i] === (i - 1) % 40 || cycles[i] === (i - 2) % 40 || cycles[i] === i % 40) {
outStr += '#';
} else {
outStr += '.';
}
}
console.log(outStr);
return [part1, 0];
}

View File

@ -0,0 +1,103 @@
import { DayFunc } from "..";
type MonkeyList = Record<
number,
{
inspected: number;
items: string[];
operation: string;
test: number;
ifTrue: number;
ifFalse: number;
}
>;
const Hcf = (a: number, b: number): number => {
let larger = a > b ? a : b;
let smaller = a > b ? b : a;
let r = -1;
while (true) {
if (larger % smaller === 0) break;
r = larger % smaller;
larger = smaller;
smaller = r;
}
return r;
}
export const Day11: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n\n")
.map((v) => v.split("\n").map((i) => i.trim()));
const list: MonkeyList = parsed.reduce((prev, next) => {
const num = next[0].split(" ")[1].slice(0, -1);
const items = next[1]
.split(" ")
.slice(2)
.map((i) => i.replace(",", ""));
const op = next[2].split("new = old ")[1];
const test = parseInt(next[3].split(" ").pop());
const ifTrue = parseInt(next[4].split(" ").pop());
const ifFalse = parseInt(next[5].split(" ").pop());
prev[num] = {
items: items,
operation: op,
test: test,
ifTrue: ifTrue,
ifFalse: ifFalse,
inspected: 0,
};
return prev;
}, {});
const part1List: MonkeyList = JSON.parse(JSON.stringify(list));
const part2List: MonkeyList = JSON.parse(JSON.stringify(list));
for (let round = 1; round <= 20; round++) {
Object.values(part1List).forEach((v) => {
v.items.forEach(old => {
v.inspected++;
let newVal = eval(`${old}${v.operation.replace('old', old.toString())}`);
newVal = Math.floor(newVal / 3);
if (newVal % v.test === 0) {
part1List[v.ifTrue].items.push(newVal);
} else {
part1List[v.ifFalse].items.push(newVal);
}
});
v.items = [];
});
}
const part1 = Object.values(part1List).map(v => v.inspected).sort((a, b) => b - a);
const product = Object.values(part2List).reduce((p, v) => p * v.test, 1);
for (let round = 0; round < 10000; round++) {
Object.values(part2List).forEach((v) => {
v.inspected += v.items.length;
v.items.forEach(old => {
let newVal = eval(`${old}${v.operation.replace('old', old.toString())}`);
if (newVal > product) {
newVal = newVal % product;
}
if (newVal % v.test === 0) {
part2List[v.ifTrue].items.push(newVal);
} else {
part2List[v.ifFalse].items.push(newVal);
}
});
v.items = [];
});
}
const part2 = Object.values(part2List).map(v => v.inspected).sort((a, b) => b - a);
console.log(part2);
return [part1[0] * part1[1], part2[0] * part2[1]];
};

View File

@ -0,0 +1,132 @@
import { DayFunc } from "..";
const FunnyCharCode = (input: string): number => {
if (input === "S") return "a".charCodeAt(0);
if (input === "E") return "z".charCodeAt(0);
return input.charCodeAt(0);
};
const IsOk = (
input: string[][],
edges: Record<string, string[]>,
a: [number, number],
b: [number, number]
) => {
if (!edges[`${a[0]},${a[1]}`]) {
edges[`${a[0]},${a[1]}`] = [];
}
const c = edges[`${a[0]},${a[1]}`];
if (FunnyCharCode(input[a[0]][a[1]]) - FunnyCharCode(input[b[0]][b[1]]) >= -1) {
c.push(`${b[0]},${b[1]}`);
}
};
export const Day12: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) => i.split(""));
const edges: Record<string, string[]> = {};
const visited: { letter: string; node: string; visited: boolean }[] = [];
for (let i = 0; i < parsed.length; i++) {
for (let j = 0; j < parsed[0].length; j++) {
visited.push({
letter: parsed[i][j],
node: `${i},${j}`,
visited: false,
});
if (i > 0 && j > 0 && i < parsed.length - 1 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i > 0 && j > 0 && i < parsed.length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i > 0 && j > 0 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (i === 0 && j > 0 && j < parsed[0].length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
IsOk(parsed, edges, [i, j], [i, j - 1]);
} else if (j === 0 && i > 0 && i < parsed.length - 1) {
IsOk(parsed, edges, [i, j], [i + 1, j]);
IsOk(parsed, edges, [i, j], [i - 1, j]);
IsOk(parsed, edges, [i, j], [i, j + 1]);
}
}
}
IsOk(parsed, edges, [0, 0], [0, 1]);
IsOk(parsed, edges, [0, 0], [1, 0]);
IsOk(
parsed,
edges,
[parsed.length - 1, parsed[0].length - 1],
[parsed.length - 1, parsed[0].length - 2]
);
IsOk(
parsed,
edges,
[parsed.length - 1, parsed[0].length - 1],
[parsed.length - 2, parsed[0].length - 1]
);
IsOk(parsed, edges, [parsed.length - 1, 0], [parsed.length - 2, 0]);
IsOk(parsed, edges, [parsed.length - 1, 0], [parsed.length - 1, 1]);
IsOk(parsed, edges, [0, parsed[0].length - 1], [0, parsed[0].length - 2]);
IsOk(parsed, edges, [0, parsed[0].length - 1], [1, parsed[0].length - 1]);
const startNode = visited.find((v) => v.letter === "S");
const part1 = BFS(startNode.node, edges, visited);
const part2 = visited.filter(v => v.letter === 'a').map(n => BFS(n.node, edges, visited));
return [part1, Math.min(...part2)];
};
const BFS = (
currentNode: string,
edges: Record<string, string[]>,
visited: { letter: string; node: string; visited: boolean }[]
): number => {
const q: Array<{ letter: string; node: string; visited: boolean } | null> =
[];
const marked = new Set();
const c = visited.find((v) => v.node === currentNode);
q.push(c);
const depthQueue = [0];
marked.add(c.node);
while (q.length > 0) {
const head = q.shift();
const level = depthQueue.shift();
marked.add(head.node);
if (head.letter === "E") {
return level;
}
edges[head.node].filter(p => !marked.has(p)).forEach(v => {
const n = visited.find(i => i.node === v);
marked.add(n.node);
q.push(n);
depthQueue.push(level + 1);
});
}
return 10000000;
};

View File

@ -0,0 +1,56 @@
import { DayFunc } from "..";
const Compare = (a: any, b: any): "left" | "right" | null => {
if (typeof a === "number" && typeof b === "number") {
if (a < b) {
return "right";
} else if (a > b) {
return "left";
} else {
return null;
}
} else if (typeof a === "object" && typeof b === "object") {
if (a.length === 0 && b.length > 0) return "right";
if (b.length === 0 && a.length > 0) return "left";
if (a.length === 0 && b.length === 0) return null;
const ans = Compare(a[0], b[0]);
if (ans !== null) return ans;
a.shift();
b.shift();
return Compare(a, b);
} else if (typeof a === "object") {
return Compare(a, [b]);
} else if (typeof b === "object") {
return Compare([a], b);
}
};
export const Day13: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n\n")
.map((v) => v.split("\n").map((w) => JSON.parse(w)));
const part2Parsed = input.trim().replaceAll('\n\n', '\n').split('\n').map(v => JSON.parse(v));
part2Parsed.push([[2]]);
part2Parsed.push([[6]]);
let part1 = 0;
parsed.forEach(([a, b], i) => {
const side = Compare(a, b);
if (side === "right") {
part1 += i + 1;
}
});
part2Parsed.sort((a, b) => {
if (Compare(JSON.parse(JSON.stringify(a)), JSON.parse(JSON.stringify(b))) === "left") return 1
return -1;
});
const two = part2Parsed.findIndex(i => JSON.stringify(i) === JSON.stringify([[2]])) + 1;
const six = part2Parsed.findIndex(i => JSON.stringify(i) === JSON.stringify([[6]])) + 1;
return [part1, two * six];
};

View File

@ -0,0 +1,178 @@
import { DayFunc, UP } from "..";
const writer = Bun.stdout.writer();
const PrintGrid = async (g: string[][]) => {
for (let i = 0; i < g.length; i++) {
for (let j = 0; j < g[0].length; j++) {
process.stdout.write(g[i][j]);
}
process.stdout.write('\n');
}
for (let i = 0; i < g.length; i++) {
process.stdout.write(UP)
}
};
const EraseSand = ([x, y]: [number, number]) => {
process.stdout.write(`\033[${y}B`);
process.stdout.write(`\033[${x}C`);
process.stdout.write('.');
process.stdout.write(`\033[${y}A`);
process.stdout.write(`\033[${x + 1}D`);
}
const PrintSand = ([x, y]: [number, number]) => {
process.stdout.write(`\033[${y}B`);
process.stdout.write(`\033[${x}C`);
process.stdout.write('+');
process.stdout.write(`\033[${y}A`);
process.stdout.write(`\033[${x + 1}D`);
}
let minX = 0;
let maxX = 0;
let ySize = 0;
// Returns true if the sand has settled.
const OneTick = (
[y, x]: [number, number],
grid: string[][]
): [boolean, boolean, [number, number]] => {
const next = grid[y + 1][x];
if (grid[y + 1][x] === undefined) {
return [false, true, [0, 0]];
}
if (next === ".") {
grid[y][x] = ".";
grid[y + 1][x] = "+";
return [false, false, [y + 1, x]];
} else {
if (grid[y + 1][x - 1] === ".") {
grid[y][x] = ".";
grid[y + 1][x - 1] = "+";
return [false, false, [y + 1, x - 1]];
} else if (grid[y + 1][x - 1] === undefined) {
return [false, true, [0, 0]];
} else if (grid[y + 1][x + 1] === ".") {
grid[y][x] = ".";
grid[y + 1][x + 1] = "+";
return [false, false, [y + 1, x + 1]];
} else if (grid[y + 1][x + 1] === undefined) {
return [false, true, [0, 0]];
} else {
//Settled
grid[y][x] = "o";
return [true, false, [y, x]];
}
}
};
export const Day14: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) =>
i.split(" -> ").map((v) => v.split(",").map((w) => parseInt(w)))
);
const xs = parsed.flatMap((v) => v).map((v) => v[0]);
const ys = parsed.flatMap((v) => v).map((v) => v[1]);
minX = Math.min(...xs);
maxX = Math.max(...xs);
const xSize = maxX - minX;
ySize = Math.max(...ys);
let sand: [number, number] = [0, 500 - minX];
const grid = Array.from({ length: ySize + 1 }, (_) =>
new Array(xSize + 1).fill(".")
);
parsed.forEach((rocks) => {
for (let i = 0; i < rocks.length - 1; i++) {
const [x1, y1] = rocks[i];
const [x2, y2] = rocks[i + 1];
if (x1 === x2) {
const startY = Math.min(y1, y2);
const endY = Math.max(y1, y2);
for (let j = startY; j <= endY; j++) {
grid[j][x1 - minX] = "#";
}
} else {
const startX = Math.min(x1, x2) - minX;
const endX = Math.max(x1, x2) - minX;
for (let j = startX; j <= endX; j++) {
grid[y1][j] = "#";
}
}
}
});
PrintGrid(grid);
grid[sand[0]][sand[1]] = "+";
const increaseSize = 200;
const part2Grid: string[][] = JSON.parse(JSON.stringify(grid));
for (let i = 0; i < part2Grid.length; i++) {
part2Grid[i] = [...Array(increaseSize).fill("."), ...part2Grid[i], ...Array(increaseSize).fill(".")];
}
part2Grid.push(Array(xSize + increaseSize * 2 + 1).fill("."));
part2Grid.push(Array(xSize + increaseSize * 2 + 1).fill("#"));
while (true) {
Bun.sleepSync(0.01);
const [settled, gameOver, newSand] = OneTick(sand, grid);
EraseSand([sand[1], sand[0]]);
if (gameOver) {
grid[sand[0]][sand[1]] = ".";
break;
}
if (!settled) {
sand = newSand;
} else {
sand = [0, 500 - minX];
grid[sand[0]][sand[1]] = "+";
}
PrintSand([sand[1], sand[0]]);
}
for (let i = 0; i < grid.length; i++) {
process.stdout.write('\n');
}
const part1 = grid.reduce((p, n) => p + n.filter((i) => i === "o").length, 0);
minX = minX - increaseSize;
ySize = ySize + 2;
sand = [0, 500 - minX];
while (true) {
// Bun.sleepSync(0.001);
// PrintGrid(part2Grid);
const [settled, gameOver, newSand] = OneTick(sand, part2Grid);
if (gameOver) {
part2Grid[sand[0]][sand[1]] = ".";
break;
}
if (!settled) {
sand = newSand;
} else {
if (newSand[0] === 0 && newSand[1] === 500 - minX) {
part2Grid[0][500 - minX] = 'o';
break;
}
sand = [0, 500 - minX];
part2Grid[sand[0]][sand[1]] = "+";
}
}
for (let i = 0; i < grid.length; i++) {
writer.write('\n');
}
const part2 = part2Grid.reduce((p, n) => p + n.filter((i) => i === "o").length, 0);
return [part1, part2];
};

View File

@ -0,0 +1,69 @@
import { DayFunc } from "..";
type Pos = { x: number; y: number };
export const Day15: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((v) => v.split(" at "))
.map((v) => [v[1].slice(0, v[1].indexOf(":")), v[2]])
.map((v) => v.map((i) => i.replaceAll(/[a-z]=/g, "").replaceAll(" ", "")))
.map((v) => {
const oneSplit = v[0].split(",");
const twoSplit = v[1].split(",");
return [
[parseInt(oneSplit[0]), parseInt(oneSplit[1])],
[parseInt(twoSplit[0]), parseInt(twoSplit[1])],
];
});
const grid: Array<{ sensor: Pos; beacon: Pos; distance: number }> = [];
let smallestX = 10000;
let largestX = 0;
parsed.forEach((i) => {
const dist = Math.abs(i[0][0] - i[1][0]) + Math.abs(i[0][1] - i[1][1]);
if (i[0][0] < smallestX) smallestX = i[0][0];
if (i[1][0] < smallestX) smallestX = i[1][0];
if (i[0][0] > largestX) largestX = i[0][0];
if (i[1][0] > largestX) largestX = i[1][0];
grid.push({
sensor: {
x: i[0][0],
y: i[0][1],
},
beacon: {
x: i[1][0],
y: i[1][1],
},
distance: dist,
});
});
const y = 10;
let part1 = 0;
console.log(smallestX);
console.log(largestX);
for (let i = smallestX - 10000000; i <= largestX + 10000000; i++) {
const testPos: Pos = {
x: i,
y: y,
};
const beaconHere = grid.find(p => p.beacon.x === testPos.x && p.beacon.y === testPos.y);
if (beaconHere) {
continue;
}
const testPoint = grid.find(p => Math.abs(p.sensor.x - testPos.x) + Math.abs(p.sensor.y - testPos.y) <= p.distance);
if (testPoint) {
part1++;
}
}
return [part1, 0];
};

View File

@ -0,0 +1,218 @@
import { DayFunc } from "..";
const blocks = [
[["@", "@", "@", "@"]],
[
[".", "@", "."],
["@", "@", "@"],
[".", "@", "."],
],
[
[".", ".", "@"],
[".", ".", "@"],
["@", "@", "@"],
],
[["@"], ["@"], ["@"], ["@"]],
[
["@", "@"],
["@", "@"],
],
];
function PrintGrid(grid: string[][]) {
for (let i = grid.length - 1; i >= 0; i--) {
for (let j = 0; j < grid[0].length; j++) {
process.stdout.write(grid[i][j]);
}
process.stdout.write("\n");
}
process.stdout.write("++++++++++++++++++++++++++++\n");
}
function MoveDown(
grid: string[][],
block: string[][],
[x, y]: [number, number]
): boolean {
// Moving through the floor.
if (y - block.length + 1 === 0) return false;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@" && grid[y - i - 1][j + x] === "#") {
return false;
}
}
}
// No collision. Clear block.
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = ".";
}
}
}
y--;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "@";
}
}
}
return true;
}
function MoveSides(
grid: string[][],
block: string[][],
[x, y]: [number, number],
unit: -1 | 1
): boolean {
// Goes off the sides
if (x + unit < 0 || x + block[0].length + unit > grid[0].length) return false;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@" && grid[y - i][j + x + unit] === "#") {
return false;
}
}
}
// No collision. Clear block.
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = ".";
}
}
}
x += unit;
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "@";
}
}
}
return true;
}
function SettleBlock(
grid: string[][],
block: string[][],
[x, y]: [number, number]
) {
for (let i = block.length - 1; i >= 0; i--) {
for (let j = 0; j < block[0].length; j++) {
if (block[i][j] === "@") {
grid[y - i][j + x] = "#";
}
}
}
}
function* BlockGen(start = 0, end = Infinity, step = 1) {
for (let i = start; i < end; i += step) {
yield { block: blocks[i % blocks.length]!, index: i % blocks.length };
}
}
function CalcHeight(grid: string[][]) {
let e = 0;
for (let i = grid.length - 1; i >= 0; i--) {
if (grid[i].some((j) => j === "#")) {
break;
}
e++;
}
return grid.length - e;
}
export const Day17: DayFunc = (input) => {
const parsed = input.trim().split("");
const gen = BlockGen();
const grid: string[][] = [];
let jet = 0;
let part1: number;
let addedOnHeight = 0;
const depthMap: Record<string, {height: number; index: number}> = {};
for (let i = 0; i < 1e12; i++) {
if (i === 2022) {
part1 = CalcHeight(grid);
}
const g = gen.next().value;
if (!g) return;
const block = g.block;
// Not right, not necessarily the top row.
let emptyRows = 0;
let rock = -1;
for (let c = grid.length - 1; c >= 0; c--) {
if (grid[c].some((i) => i === "#")) {
rock = c;
break;
}
emptyRows++;
}
if (emptyRows < 3 + block.length) {
for (let c = 0; c <= 2 + block.length - emptyRows; c++) {
grid.push([".", ".", ".", ".", ".", ".", "."]);
}
}
const topLeft: [number, number] = [2, rock + 3 + block.length];
for (let j = block.length - 1; j >= 0; j--) {
const newRow = [".", ".", ...block[j]];
for (let k = 0; k < 5 - block[j].length; k++) {
newRow.push(".");
}
grid[rock === -1 ? 3 - j : block.length - j + rock + 3] = newRow;
}
let movedDown = true;
do {
if (parsed[jet % parsed.length] === "<") {
const moved = MoveSides(grid, block, topLeft, -1);
if (moved) topLeft[0]--;
} else {
const moved = MoveSides(grid, block, topLeft, 1);
if (moved) topLeft[0]++;
}
jet++;
movedDown = MoveDown(grid, block, topLeft);
if (movedDown) {
topLeft[1]--;
}
} while (movedDown);
SettleBlock(grid, block, topLeft);
const depth = [0, 0, 0, 0, 0, 0, 0];
for (let x = 0; x < 7; x++) {
for (let y = grid.length - 1; y >= 0; y--) {
if (grid[y][x] === '#') {
depth[x] = grid.length - y;
break;
}
}
}
const key = `${g.index},${jet % parsed.length},${JSON.stringify(depth)}`;
if (key in depthMap) {
const height = CalcHeight(grid);
const mapEntry = depthMap[key];
const diff = height - mapEntry.height;
const cycleNum = Math.floor((1e12 - i) / (i - mapEntry.index));
i += cycleNum * (i - mapEntry.index);
addedOnHeight += diff * cycleNum;
} else {
depthMap[key] = { height: CalcHeight(grid), index: i };
}
}
return [part1, CalcHeight(grid) + addedOnHeight];
};

View File

@ -0,0 +1,31 @@
import { DayFunc } from "..";
function CalcDist(
[x1, y1, z1]: [number, number, number],
[x2, y2, z2]: [number, number, number]
): number {
return Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2 + (z1 - z2) ** 2);
}
export const Day18: DayFunc = (input) => {
const parsed = input
.trim()
.split("\n")
.map((i) => i.split(",").map((j) => parseInt(j)));
let part1 = parsed.length * 6;
for (let i = 0; i < parsed.length; i++) {
const a = parsed[i];
for (let j = 0; j < parsed.length; j++) {
if (i === j) continue;
const b = parsed[j];
// @ts-ignore
const dist = CalcDist(a, b);
if (dist === 1) {
part1--;
}
}
}
return [part1, 0];
};

View File

@ -0,0 +1,70 @@
import { DayFunc } from "..";
// A = Rock, B = Paper, C = Scissors
// X = Rock, Y = Paper, Z = Scissors
// 1 = Rock, 2 = Paper, 3 = Scissors
// 0 = Lose, 3 = Draw, 6 = Win
type Options = 'r' | 'p' | 's';
const mapping: {[key: string]: Options} = {
A: 'r',
B: 'p',
C: 's',
X: 'r',
Y: 'p',
Z: 's',
}
const scores: Record<
Options,
{
score: number;
beats: Options;
loses: Options;
}
> = {
'r': {
score: 1,
beats: "s",
loses: "p",
},
'p': {
score: 2,
beats: "r",
loses: "s",
},
's': {
score: 3,
beats: "p",
loses: "r",
},
};
export const Day2: DayFunc = (input) => {
const plays: string[][] = input
.trim()
.split("\n")
.map((line) => line.split(" "));
let part1 = 0;
let part2 = 0;
plays.forEach(([opp, you]) => {
part1 += scores[mapping[you]].score;
if (mapping[you] === mapping[opp]) {
part1 += 3;
} else if (scores[mapping[you]].beats === mapping[opp]) {
part1 += 6;
}
if (you === 'X') {
part2 += scores[scores[mapping[opp]].beats].score;
} else if (you === 'Y') {
part2 += 3 + scores[mapping[opp]].score;
} else {
part2 += 6 + scores[scores[mapping[opp]].loses].score;
}
});
return [part1, part2];
};

View File

@ -0,0 +1,35 @@
import { DayFunc } from "..";
const getCode = (x: Set<string>): number => {
const code = x.values().next().value.charCodeAt(0);
return code + (code <= 90 ? -38 : -96);
};
export const Day3: DayFunc = (input) => {
const bags: string[] = input
.trim()
.split("\n")
const part1Bags = bags.map((i) => [i.slice(0, i.length / 2), i.slice(i.length / 2)]);
const part2Bags = []
for (let i = 0; i < bags.length; i += 3) {
part2Bags.push(bags.slice(i, i + 3));
}
const part1 = part1Bags.reduce((prev, [c1, c2]) => {
const set1 = new Set(c1);
const set2 = new Set(c2);
const n = new Set([...set1].filter((x) => set2.has(x)));
return prev + getCode(n);
}, 0);
const part2 = part2Bags.reduce((prev, [c1, c2, c3]) => {
const set1 = new Set(c1);
const set2 = new Set(c2);
const set3 = new Set(c3);
const n = new Set([...set1].filter((x) => set2.has(x)).filter(x => set3.has(x)));
return prev + getCode(n as Set<string>);
}, 0)
return [part1, part2];
};

View File

@ -0,0 +1,29 @@
import { DayFunc } from "..";
export const Day4: DayFunc = (input) => {
const pairs: number[][][] = input
.trim()
.split("\n")
.map((l) => l.split(",").map((p) => p.split("-").map((v) => parseInt(v))));
const [part1, part2] = pairs.reduce(
([part1, part2], next) => {
if (
(next[0][0] <= next[1][0] && next[0][1] >= next[1][1]) ||
(next[1][0] <= next[0][0] && next[1][1] >= next[0][1])
) {
part1++;
part2++;
} else if (
(next[0][0] <= next[1][0] && next[1][0] <= next[0][1]) ||
(next[1][0] <= next[0][0] && next[0][0] <= next[1][1])
) {
part2++;
}
return [part1, part2];
},
[0, 0]
);
return [part1, part2];
};

View File

@ -0,0 +1,45 @@
import { DayFunc } from "..";
export const Day5: DayFunc = (input) => {
let [inStacks, instructions] = input
.split("\n\n")
const stacks = inStacks.split('\n')
stacks.pop();
const numOfStacks = (stacks[0].length + 1) / 4;
let realStacks = [...Array(numOfStacks)].map(() => []);
for (let i = 0; i < stacks.length; i++) {
for (let j = 1; j < stacks[i].length; j += 4) {
const c = stacks[i].charAt(j);
const stackNum = (j - 1) / 4;
if (c !== " ") {
realStacks[stackNum].push(c);
}
}
}
realStacks.map(s => s.reverse());
const realStacks2 = [...realStacks].map(i => [...i]);
const rules = instructions.split('\n').map((i) => {
const is = i.split(" ");
return [parseInt(is[1]), parseInt(is[3]) - 1, parseInt(is[5]) - 1];
});
rules.pop();
rules.forEach(r => {
for (let i = 0; i < r[0]; i++) {
const popped = realStacks[r[1]].pop();
realStacks[r[2]].push(popped);
}
const crates = realStacks2[r[1]].splice(-r[0]);
realStacks2[r[2]].push(...crates);
});
const part1 = realStacks.reduce((prev, next) => prev + next[next.length - 1], "");
const part2 = realStacks2.reduce((prev, next) => prev + next[next.length - 1], "");
return [part1, part2];
};

View File

@ -0,0 +1,21 @@
import { DayFunc } from "..";
const FindRepeated = (input: string, gap: number): number => {
for (let i = 0; i < input.length - gap; i++) {
const sub = input.substring(i, i + gap);
let changed = false;
for (const c of sub) {
if (sub.split(c).length > 2) {
i += sub.indexOf(c);
changed = true;
break;
}
}
if (!changed) return i + gap;
}
return -1;
}
export const Day6: DayFunc = (input) => {
return [FindRepeated(input, 4), FindRepeated(input, 14)];
}

Some files were not shown because too many files have changed in this diff Show More