solve day 7 part 1

This commit is contained in:
Gabriel Augendre 2023-12-09 11:10:31 +01:00
parent 976d3b5e01
commit 17049c1f98
8 changed files with 1406 additions and 8 deletions

View file

@ -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
View 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
}

View 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

File diff suppressed because it is too large Load diff

5
2023/inputs/day07_test1 Normal file
View file

@ -0,0 +1,5 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483

6
2023/inputs/day07_test2 Normal file
View file

@ -0,0 +1,6 @@
32T3K 765
T55J5 684
KK677 28
KTJJT 220
QQQJA 483
JJJJA 1

View file

@ -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)

View file

@ -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)