mirror of
https://github.com/Crocmagnon/advent-of-code.git
synced 2024-11-23 06:58:06 +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 (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"strings"
|
||||
|
@ -15,7 +14,6 @@ func Day06Part1(input io.Reader) (int, error) {
|
|||
times := lineToInts(strings.TrimPrefix(scanner.Text(), "Time:"))
|
||||
scanner.Scan()
|
||||
distances := lineToInts(strings.TrimPrefix(scanner.Text(), "Distance:"))
|
||||
fmt.Println(times, distances)
|
||||
|
||||
margin := 1
|
||||
|
||||
|
@ -47,7 +45,6 @@ func Day06Part2(input io.Reader) (int, error) {
|
|||
times := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Time:"), " ", ""))
|
||||
scanner.Scan()
|
||||
distances := lineToInts(strings.ReplaceAll(strings.TrimPrefix(scanner.Text(), "Distance:"), " ", ""))
|
||||
fmt.Println(times, distances)
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
type testCase struct {
|
||||
filename string
|
||||
want int
|
||||
}
|
||||
|
||||
func check(test testCase, fn solveFunc) func(t *testing.T) {
|
||||
return func(t *testing.T) {
|
||||
file, err := os.Open(test.filename)
|
||||
|
|
|
@ -2,9 +2,4 @@ package _023
|
|||
|
||||
import "io"
|
||||
|
||||
type testCase struct {
|
||||
filename string
|
||||
want int
|
||||
}
|
||||
|
||||
type solveFunc func(reader io.Reader) (int, error)
|
||||
|
|
Loading…
Reference in a new issue