advent-of-code/aoc2024/day03/main.go

262 lines
4.3 KiB
Go
Raw Normal View History

package main
import (
_ "embed"
"fmt"
"io"
"iter"
"strings"
aoc "go.sour.is/advent-of-code"
)
// var log = aoc.Log
func main() { aoc.MustResult(aoc.RunnerReader(run)) }
type result struct {
valuePT1 int
valuePT2 int
}
func (r result) String() string { return fmt.Sprintf("%#v", r) }
func run(read io.Reader) (*result, error) {
sum := 0
2024-12-03 15:12:39 -07:00
sum2 := 0
lexer := Lexer(read)
2024-12-03 15:12:39 -07:00
active := true
for typ, _ := range lexer.Iter() {
// fmt.Println(typ, string(token))
switch {
case typ == "TokMUL":
if m := readMul(lexer); m != 0 {
sum += m
if active {
sum2 += m
}
}
case typ == "TokDONT":
if readDont(lexer) {
println("don't()", active)
active = false
}
2024-12-03 15:12:39 -07:00
case typ == "TokDO":
if readDo(lexer) {
println("do()", active)
active = true
}
}
}
2024-12-03 15:12:39 -07:00
return &result{sum, sum2}, nil
}
func Lexer(in io.Reader) *lexer {
seq := func(yield func(rune) bool) {
2024-12-03 15:12:39 -07:00
defer func() {
if err := recover(); err != nil {
fmt.Println("ERR", err)
return
}
fmt.Println("NO DEFER AND NO PANIC??")
}()
buf := make([]byte, 256)
s, _ := in.Read(buf)
buf = buf[:s]
for len(buf) > 0 {
2024-12-03 15:12:39 -07:00
for i, r := range string(buf) {
println(i, r)
if i >= 72 {
fmt.Println("START")
}
if !yield(r) {
return
}
2024-12-03 15:12:39 -07:00
if i >= 72 {
fmt.Println("STOP")
}
}
s, _ := in.Read(buf)
buf = buf[:s]
}
for !yield(-1) {
}
}
next, stop := iter.Pull(seq)
lex := lexer{iter: next, stop: stop}
lex.readRune()
lex.readRune()
return &lex
}
type lexer struct {
rune rune
next rune
iter func() (rune, bool)
stop func()
2024-12-03 15:12:39 -07:00
buf []rune
token string
literal []rune
}
func (l *lexer) Stop() { l.stop() }
func (l *lexer) readRune() {
if l.rune == -1 {
return
}
if r, ok := l.iter(); ok {
l.rune, l.next = l.next, r
} else {
l.rune, l.next = l.next, -1
}
}
func (l *lexer) loadRune(tok string) {
l.token = tok
l.literal = append(l.literal, l.rune)
l.readRune()
}
func (l *lexer) loadNumber() {
l.token = "TokNUMBER"
for strings.ContainsRune("0123456789", l.rune) {
l.literal = append(l.literal, l.rune)
l.readRune()
}
}
func (l *lexer) loadString(accept string) {
l.token = "TokSTRING"
for !(!strings.ContainsRune(accept, l.rune) || l.rune == 0 || l.rune == -1) {
l.literal = append(l.literal, l.rune)
l.readRune()
}
}
func (l *lexer) NextTok() bool {
l.literal = l.literal[:0]
switch l.rune {
case 'm':
l.loadString("mul")
l.token = "TokMUL"
2024-12-03 15:12:39 -07:00
if string(l.literal) != "mul" {
l.token = "TokILLEGAL"
return false
}
return true
case 'd':
l.loadString("don't")
switch string(l.literal) {
case "don't":
l.token = "TokDONT"
case "do":
l.token = "TokDO"
default:
l.token = "TokILLEGAL"
return false
}
return true
2024-12-03 15:12:39 -07:00
case '(':
l.loadRune("TokLPAREN")
return true
case ')':
l.loadRune("TokRPAREN")
return true
case ',':
l.loadRune("TokCOMMA")
return true
case -1:
l.loadRune("TokEOF")
return false
default:
if '0' <= l.rune && l.rune <= '9' {
l.loadNumber()
return true
}
}
l.loadRune("TokILLEGAL")
return true
}
func (l *lexer) Iter() iter.Seq2[string, string] {
return func(yield func(string, string) bool) {
for l.NextTok() {
if !yield(l.token, string(l.literal)) {
return
}
}
}
}
func readMul(lex *lexer) int {
if lex.token != "TokMUL" || string(lex.literal) != "mul" {
return 0
}
var a, b = -1, -1
if !lex.NextTok() || lex.token != "TokLPAREN" {
return 0
}
2024-12-03 15:12:39 -07:00
if !lex.NextTok() || lex.token != "TokNUMBER" {
return 0
}
a = aoc.Atoi(string(lex.literal))
if !lex.NextTok() || lex.token != "TokCOMMA" {
return 0
}
if !lex.NextTok() || lex.token != "TokNUMBER" {
return 0
}
b = aoc.Atoi(string(lex.literal))
if !lex.NextTok() || lex.token != "TokRPAREN" {
return 0
}
fmt.Println(a, "*", b)
return a * b
}
2024-12-03 15:12:39 -07:00
func readDont(lex *lexer) bool {
if lex.token != "TokDONT" || string(lex.literal) != "don't" {
return false
}
if !lex.NextTok() || lex.token != "TokLPAREN" {
return false
}
if !lex.NextTok() || lex.token != "TokRPAREN" {
return false
}
return true
}
func readDo(lex *lexer) bool {
if lex.token != "TokDO" || string(lex.literal) != "do" {
return false
}
if !lex.NextTok() || lex.token != "TokLPAREN" {
return false
}
if !lex.NextTok() || lex.token != "TokRPAREN" {
return false
}
return true
}