mirror of
https://github.com/Crocmagnon/advent-of-code.git
synced 2024-11-23 15:08:09 +01:00
solve day 7 part 1
This commit is contained in:
parent
976d3b5e01
commit
17049c1f98
8 changed files with 1406 additions and 8 deletions
|
@ -2,7 +2,6 @@ package _023
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -15,7 +14,6 @@ func Day06Part1(input io.Reader) (int, error) {
|
||||||
times := lineToInts(strings.TrimPrefix(scanner.Text(), "Time:"))
|
times := lineToInts(strings.TrimPrefix(scanner.Text(), "Time:"))
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
distances := lineToInts(strings.TrimPrefix(scanner.Text(), "Distance:"))
|
distances := lineToInts(strings.TrimPrefix(scanner.Text(), "Distance:"))
|
||||||
fmt.Println(times, distances)
|
|
||||||
|
|
||||||
margin := 1
|
margin := 1
|
||||||
|
|
||||||
|
@ -47,7 +45,6 @@ func Day06Part2(input io.Reader) (int, error) {
|
||||||
times := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Time:"), " ", ""))
|
times := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Time:"), " ", ""))
|
||||||
scanner.Scan()
|
scanner.Scan()
|
||||||
distances := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Distance:"), " ", ""))
|
distances := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Distance:"), " ", ""))
|
||||||
fmt.Println(times, distances)
|
|
||||||
|
|
||||||
margin := 1
|
margin := 1
|
||||||
|
|
||||||
|
|
220
2023/day07_camel_cards.go
Normal file
220
2023/day07_camel_cards.go
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
package _023
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"slices"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const d07CardsP1 = "23456789TJQKA"
|
||||||
|
const d07CardsP2 = "J23456789TQKA"
|
||||||
|
|
||||||
|
const (
|
||||||
|
d07HandHigh = iota
|
||||||
|
d07HandPair
|
||||||
|
d07HandTwoPairs
|
||||||
|
d07HandThree
|
||||||
|
d07HandHouse
|
||||||
|
d07HandFour
|
||||||
|
d07HandFive
|
||||||
|
)
|
||||||
|
|
||||||
|
type d07Hand struct {
|
||||||
|
hand string
|
||||||
|
bid int
|
||||||
|
value int
|
||||||
|
}
|
||||||
|
|
||||||
|
func newD07Hand(hand string, bid int) d07Hand {
|
||||||
|
return d07Hand{
|
||||||
|
hand: hand,
|
||||||
|
bid: bid,
|
||||||
|
value: d07HandValueP1(hand),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newD07HandP2(hand string, bid int) d07Hand {
|
||||||
|
return d07Hand{
|
||||||
|
hand: hand,
|
||||||
|
bid: bid,
|
||||||
|
value: d07HandValueP2(hand),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Day07Part1(input io.Reader) (int, error) {
|
||||||
|
scanner := bufio.NewScanner(input)
|
||||||
|
|
||||||
|
var hands []d07Hand
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.Split(scanner.Text(), " ")
|
||||||
|
hand, bidS := line[0], line[1]
|
||||||
|
bid, err := strconv.Atoi(bidS)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("converting bid to int on line %v: %w", line, err)
|
||||||
|
}
|
||||||
|
hands = append(hands, newD07Hand(hand, bid))
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(hands, d07CmpHands)
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for i, hand := range hands {
|
||||||
|
sum += (i + 1) * hand.bid
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func d07CmpHands(a d07Hand, b d07Hand) int {
|
||||||
|
// cmp(a, b) should return a negative number when a < b, a positive number when
|
||||||
|
// a > b and zero when a == b.
|
||||||
|
if a.value < b.value {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a.value > b.value {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(a.hand); i++ {
|
||||||
|
aValue := strings.Index(d07CardsP1, a.hand[i:i+1])
|
||||||
|
bValue := strings.Index(d07CardsP1, b.hand[i:i+1])
|
||||||
|
if aValue > bValue {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if aValue < bValue {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func d07HandValueP1(hand string) int {
|
||||||
|
count := make(map[rune]byte)
|
||||||
|
var maxCount byte = 1
|
||||||
|
var maxFor rune
|
||||||
|
var secondMax byte = 1
|
||||||
|
for _, c := range hand {
|
||||||
|
v := count[c]
|
||||||
|
v++
|
||||||
|
if v > maxCount {
|
||||||
|
maxCount = v
|
||||||
|
maxFor = c
|
||||||
|
}
|
||||||
|
count[c] = v
|
||||||
|
}
|
||||||
|
for c, v := range count {
|
||||||
|
if secondMax < v && c != maxFor {
|
||||||
|
secondMax = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case maxCount == 5:
|
||||||
|
return d07HandFive
|
||||||
|
case maxCount == 4:
|
||||||
|
return d07HandFour
|
||||||
|
case maxCount == 3 && secondMax == 2:
|
||||||
|
return d07HandHouse
|
||||||
|
case maxCount == 3 && secondMax == 1:
|
||||||
|
return d07HandThree
|
||||||
|
case maxCount == 2 && secondMax == 2:
|
||||||
|
return d07HandTwoPairs
|
||||||
|
case maxCount == 2 && secondMax == 1:
|
||||||
|
return d07HandPair
|
||||||
|
default:
|
||||||
|
return d07HandHigh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Day07Part2(input io.Reader) (int, error) {
|
||||||
|
scanner := bufio.NewScanner(input)
|
||||||
|
|
||||||
|
var hands []d07Hand
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := strings.Split(scanner.Text(), " ")
|
||||||
|
hand, bidS := line[0], line[1]
|
||||||
|
bid, err := strconv.Atoi(bidS)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("converting bid to int on line %v: %w", line, err)
|
||||||
|
}
|
||||||
|
hands = append(hands, newD07HandP2(hand, bid))
|
||||||
|
}
|
||||||
|
|
||||||
|
slices.SortFunc(hands, d07CmpHandsP2)
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
for i, hand := range hands {
|
||||||
|
sum += (i + 1) * hand.bid
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func d07HandValueP2(hand string) int {
|
||||||
|
count := make(map[rune]byte)
|
||||||
|
var maxCount byte = 1
|
||||||
|
var maxFor rune
|
||||||
|
var secondMax byte = 1
|
||||||
|
for _, c := range hand {
|
||||||
|
v := count[c]
|
||||||
|
v++
|
||||||
|
if v > maxCount && c != 'J' {
|
||||||
|
maxCount = v
|
||||||
|
maxFor = c
|
||||||
|
}
|
||||||
|
count[c] = v
|
||||||
|
}
|
||||||
|
joker, ok := count['J']
|
||||||
|
maxCount += joker
|
||||||
|
if ok {
|
||||||
|
delete(count, 'J')
|
||||||
|
}
|
||||||
|
for c, v := range count {
|
||||||
|
if secondMax < v && c != maxFor {
|
||||||
|
secondMax = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case maxCount == 5:
|
||||||
|
return d07HandFive
|
||||||
|
case maxCount == 4:
|
||||||
|
return d07HandFour
|
||||||
|
case maxCount == 3 && secondMax == 2:
|
||||||
|
return d07HandHouse
|
||||||
|
case maxCount == 3 && secondMax == 1:
|
||||||
|
return d07HandThree
|
||||||
|
case maxCount == 2 && secondMax == 2:
|
||||||
|
return d07HandTwoPairs
|
||||||
|
case maxCount == 2 && secondMax == 1:
|
||||||
|
return d07HandPair
|
||||||
|
default:
|
||||||
|
return d07HandHigh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func d07CmpHandsP2(a d07Hand, b d07Hand) int {
|
||||||
|
// cmp(a, b) should return a negative number when a < b, a positive number when
|
||||||
|
// a > b and zero when a == b.
|
||||||
|
if a.value < b.value {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if a.value > b.value {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(a.hand); i++ {
|
||||||
|
aValue := strings.Index(d07CardsP2, a.hand[i:i+1])
|
||||||
|
bValue := strings.Index(d07CardsP2, b.hand[i:i+1])
|
||||||
|
if aValue > bValue {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if aValue < bValue {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
170
2023/day07_camel_cards_test.go
Normal file
170
2023/day07_camel_cards_test.go
Normal file
|
@ -0,0 +1,170 @@
|
||||||
|
package _023
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDay07Part1(t *testing.T) {
|
||||||
|
tests := []testCase{
|
||||||
|
{"inputs/day07_test1", 6440},
|
||||||
|
{"inputs/day07", 246424613},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.filename, check(test, Day07Part1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDay07Part2(t *testing.T) {
|
||||||
|
tests := []testCase{
|
||||||
|
{"inputs/day07_test1", 5905},
|
||||||
|
{"inputs/day07_test2", 5911},
|
||||||
|
{"inputs/day07", 0}, // 247974245 is too low
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.filename, check(test, Day07Part2))
|
||||||
|
}
|
||||||
|
t.Run("247974245 is too low", func(t *testing.T) {
|
||||||
|
file, err := os.Open("inputs/day07")
|
||||||
|
require.NoError(t, err)
|
||||||
|
got, err := Day07Part2(file)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Greater(t, got, 247974245)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDay07HandValueP1(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
hand string
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{"AAAAA", d07HandFive},
|
||||||
|
{"AAAA2", d07HandFour},
|
||||||
|
{"AA2AA", d07HandFour},
|
||||||
|
{"3KKK3", d07HandHouse},
|
||||||
|
{"3KKK4", d07HandThree},
|
||||||
|
{"KKQQT", d07HandTwoPairs},
|
||||||
|
{"KQTQK", d07HandTwoPairs},
|
||||||
|
{"QQ567", d07HandPair},
|
||||||
|
{"T6862", d07HandPair},
|
||||||
|
{"A2345", d07HandHigh},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.hand, func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expected, d07HandValueP1(test.hand))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDay07HandValueP2(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
hand string
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{"AAAAA", d07HandFive},
|
||||||
|
{"AAJJJ", d07HandFive},
|
||||||
|
{"AAAA2", d07HandFour},
|
||||||
|
{"JJAJ2", d07HandFour},
|
||||||
|
{"JKKK2", d07HandFour},
|
||||||
|
{"QJJQ2", d07HandFour},
|
||||||
|
{"AA2AA", d07HandFour},
|
||||||
|
{"AJ2JA", d07HandFour},
|
||||||
|
{"3KKK3", d07HandHouse},
|
||||||
|
{"3KJK3", d07HandHouse},
|
||||||
|
{"3KKK4", d07HandThree},
|
||||||
|
{"3KKJ4", d07HandThree},
|
||||||
|
{"KKQQT", d07HandTwoPairs},
|
||||||
|
{"KQTQK", d07HandTwoPairs},
|
||||||
|
{"QQ567", d07HandPair},
|
||||||
|
{"JQ567", d07HandPair},
|
||||||
|
{"T6862", d07HandPair},
|
||||||
|
{"T68J2", d07HandPair},
|
||||||
|
{"A2345", d07HandHigh},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
t.Run(test.hand, func(t *testing.T) {
|
||||||
|
assert.Equal(t, test.expected, d07HandValueP2(test.hand))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestD07CmpHands(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a string
|
||||||
|
b string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "five and four",
|
||||||
|
args: args{"AAAAA", "KAAAA"},
|
||||||
|
want: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "four and four",
|
||||||
|
args: args{"2AAAA", "33332"},
|
||||||
|
want: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "house and house",
|
||||||
|
args: args{"77888", "77788"},
|
||||||
|
want: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, d07CmpHands(newD07Hand(tt.args.a, 0), newD07Hand(tt.args.b, 0)), "d07CmpHands(%v, %v)", tt.args.a, tt.args.b)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestD07CmpHandsP2(t *testing.T) {
|
||||||
|
type args struct {
|
||||||
|
a string
|
||||||
|
b string
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
args args
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
args: args{"T55J5", "KTJJT"},
|
||||||
|
want: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{"KTJJT", "QQQJA"},
|
||||||
|
want: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{"T55J5", "QQQJA"},
|
||||||
|
want: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{"J55T5", "JQQQA"},
|
||||||
|
want: -1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{"555T5", "JQQQA"},
|
||||||
|
want: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
args: args{"QQQQ2", "JKKK2"},
|
||||||
|
want: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
char := "<"
|
||||||
|
if tt.want == 1 {
|
||||||
|
char = ">"
|
||||||
|
}
|
||||||
|
t.Run(fmt.Sprintf("%v%v%v", tt.args.a, char, tt.args.b), func(t *testing.T) {
|
||||||
|
assert.Equalf(t, tt.want, d07CmpHandsP2(newD07HandP2(tt.args.a, 0), newD07HandP2(tt.args.b, 0)), "d07CmpHandsP2(%v, %v)", tt.args.a, tt.args.b)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1000
2023/inputs/day07
Normal file
1000
2023/inputs/day07
Normal file
File diff suppressed because it is too large
Load diff
5
2023/inputs/day07_test1
Normal file
5
2023/inputs/day07_test1
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
6
2023/inputs/day07_test2
Normal file
6
2023/inputs/day07_test2
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
32T3K 765
|
||||||
|
T55J5 684
|
||||||
|
KK677 28
|
||||||
|
KTJJT 220
|
||||||
|
QQQJA 483
|
||||||
|
JJJJA 1
|
|
@ -7,6 +7,11 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
filename string
|
||||||
|
want int
|
||||||
|
}
|
||||||
|
|
||||||
func check(test testCase, fn solveFunc) func(t *testing.T) {
|
func check(test testCase, fn solveFunc) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
file, err := os.Open(test.filename)
|
file, err := os.Open(test.filename)
|
||||||
|
|
|
@ -2,9 +2,4 @@ package _023
|
||||||
|
|
||||||
import "io"
|
import "io"
|
||||||
|
|
||||||
type testCase struct {
|
|
||||||
filename string
|
|
||||||
want int
|
|
||||||
}
|
|
||||||
|
|
||||||
type solveFunc func(reader io.Reader) (int, error)
|
type solveFunc func(reader io.Reader) (int, error)
|
||||||
|
|
Loading…
Reference in a new issue