Initial commit

This commit is contained in:
yxzzy-wtf
2023-12-01 15:13:45 +02:00
committed by GitHub
commit a474acea1e
9 changed files with 779 additions and 0 deletions

143
2022/02/code.go Executable file
View File

@@ -0,0 +1,143 @@
package main
import (
"fmt"
"strings"
"github.com/jpillora/puzzler/harness/aoc"
)
func main() {
aoc.Harness(run)
}
func run(part2 bool, input string) any {
sum := 0
for _, line := range strings.Split(strings.TrimSpace(input), "\n") {
pair := strings.SplitN(line, " ", 2)
var op move
op.unmarshal('A', pair[0])
if op.String() == "unknown" {
panic("invalid opponent move")
}
if part2 {
var o outcome
o.unmarshal(pair[1])
me := op.want(o)
sum += o.score() + me.score()
} else {
var me move
me.unmarshal('X', pair[1])
s := op.play(me).score()
sum += me.score() + s
}
}
return sum
}
type outcome byte
const (
lose outcome = iota
draw
win
)
func (o *outcome) unmarshal(s string) {
*o = outcome(delta('X', s))
}
func (o outcome) String() string {
switch o {
case lose:
return "lose"
case draw:
return "draw"
case win:
return "win"
}
return "unknown"
}
func (o outcome) score() int {
switch o {
case lose:
return 0
case draw:
return 3
case win:
return 6
}
panic("invalid outcome")
}
type move byte
const (
rock move = iota
paper
scissors
)
func (m *move) unmarshal(base byte, s string) {
*m = move(delta(base, s))
}
func (m move) String() string {
switch m {
case rock:
return "rock"
case paper:
return "paper"
case scissors:
return "scissors"
}
return "unknown"
}
func (m move) score() int {
return int(m) + 1
}
func (m move) play(against move) outcome {
if m == against {
return draw
}
if byte(m) == up(byte(against), 3) {
return lose
}
if byte(m) == down(byte(against), 3) {
return win
}
panic(fmt.Sprintf("invalid moves: %d plays %d", m, against))
}
func (m move) want(outcome outcome) move {
switch outcome {
case lose:
return move(down(byte(m), 3))
case draw:
return m
case win:
return move(up(byte(m), 3))
}
panic("invalid outcome")
}
func delta(base byte, m string) byte {
if len(m) != 1 {
panic("invalid delta")
}
return m[0] - base
}
func up(n, mod byte) byte {
return (n + 1) % mod
}
func down(n, mod byte) byte {
if n == 0 {
return mod - 1
}
return (n - 1) % mod
}

77
2022/04/code.go Executable file
View File

@@ -0,0 +1,77 @@
package main
import (
"fmt"
"log"
"strconv"
"strings"
"github.com/jpillora/puzzler/harness/aoc"
)
func main() {
aoc.Harness(run)
}
func run(part2 bool, input string) any {
if input == "" {
return "not implemented"
}
count := 0
lines := strings.Split(strings.TrimSpace(input), "\n")
for _, line := range lines {
pair := strings.SplitN(line, ",", 2)
if len(pair) != 2 {
log.Panicf("invalid input %q", line)
}
a := parse(pair[0])
b := parse(pair[1])
if !part2 && a.subsetEither(b) {
count++
} else if part2 && a.intersetsEither(b) {
count++
}
}
return count
}
type hilo struct {
lo, hi int
}
func (h hilo) String() string {
return fmt.Sprintf("%d-%d", h.lo, h.hi)
}
func parse(s string) hilo {
pair := strings.SplitN(s, "-", 2)
if len(pair) != 2 {
panic("bad pair")
}
lo, err := strconv.Atoi(pair[0])
if err != nil {
panic(err)
}
hi, err := strconv.Atoi(pair[1])
if err != nil {
panic(err)
}
return hilo{lo, hi}
}
func (a hilo) subsetEither(b hilo) bool {
return a.subsetOf(b) || b.subsetOf(a)
}
func (a hilo) subsetOf(b hilo) bool {
return a.lo >= b.lo && a.hi <= b.hi
}
func (a hilo) intersetsEither(b hilo) bool {
return a.intersets(b) || b.intersets(a)
}
func (a hilo) intersets(b hilo) bool {
return a.lo <= b.lo && b.lo <= a.hi || // b.lo in a OR
a.lo <= b.hi && b.hi <= a.hi // b.hi in a
}

260
2022/07/code.go Executable file
View File

@@ -0,0 +1,260 @@
package main
import (
"fmt"
"math"
"strconv"
"strings"
"github.com/jpillora/puzzler/harness/aoc"
)
func main() {
aoc.Harness(run)
}
func run(part2 bool, input string) any {
if input == "" {
return "skip"
}
var e *exec
execs := []*exec{}
for _, line := range strings.Split(strings.TrimSpace(input), "\n") {
if strings.HasPrefix(line, "$ ") {
command := strings.Split(line[2:], " ")
e = &exec{command: command}
execs = append(execs, e)
} else {
e.output = append(e.output, line)
}
}
fs := newFileSystem()
for _, e := range execs {
fs.simulate(e)
}
const draw = false
if draw {
fmt.Println(fs.root.tree())
}
if part2 {
return fs.MinDeleteFor(updateSize)
}
return fs.root.Size100KB()
}
type exec struct {
command []string
output []string
}
func (e exec) prog() string {
return e.command[0]
}
func (e exec) arg(i int) string {
return e.command[1+i]
}
type fileSystem struct {
root *dir
wd *dir
total int64
}
const updateSize = 30000000
func newFileSystem() *fileSystem {
root := newDir("", nil)
return &fileSystem{
root: root,
wd: root,
total: 70000000,
}
}
func (fs *fileSystem) simulate(e *exec) {
switch e.prog() {
case "cd":
fs.changeDir(e.arg(0))
case "ls":
fs.listDir(e.output)
default:
panic("unknown command")
}
}
func (fs *fileSystem) unused() int64 {
return fs.total - fs.root.Size()
}
func (fs *fileSystem) changeDir(target string) {
switch target {
case "/":
fs.wd = fs.root
case "..":
if fs.wd.parent == nil {
panic("nil parent")
}
fs.wd = fs.wd.parent
default:
fs.wd = fs.wd.subDir(target)
}
}
func (fs fileSystem) listDir(output []string) {
for _, line := range output {
pair := strings.SplitN(line, " ", 2)
name := pair[1]
if pair[0] == "dir" {
fs.wd.subDir(name)
continue
}
size, err := strconv.ParseInt(pair[0], 10, 64)
if err != nil {
panic(err)
}
fs.wd.file(name, size)
}
}
func (fs fileSystem) MinDeleteFor(target int64) int64 {
required := target - fs.unused()
if required < 0 {
panic("no min required")
}
min := int64(math.MaxInt64)
fs.root.forEach(func(d *dir) {
s := d.Size()
if s < required {
return
}
// d is a candidate
if s < min {
min = s
}
})
if min == math.MaxInt64 {
panic("no min found")
}
return min
}
type dir struct {
name string
children map[string]any
parent *dir
}
func newDir(name string, parent *dir) *dir {
return &dir{
name: name,
children: map[string]any{},
parent: parent,
}
}
func (d *dir) subDir(name string) *dir {
x, ok := d.children[name]
if !ok {
dir := newDir(name, d)
d.children[name] = dir
return dir
}
dir, ok := x.(*dir)
if !ok {
panic("file/dir mismatch")
}
return dir
}
func (d dir) tree() string {
sb := strings.Builder{}
fmt.Fprintf(&sb, "%s (%d) {\n", d.path(), d.Size())
for _, c := range d.children {
var out string
switch v := c.(type) {
case *dir:
out = v.tree()
case *file:
out = v.String()
default:
panic("invalid child")
}
ls := strings.Split(out, "\n")
for i := range ls {
ls[i] = " " + ls[i]
}
indented := strings.Join(ls, "\n")
sb.WriteString(indented)
sb.WriteRune('\n')
}
sb.WriteString("}")
return sb.String()
}
func (d *dir) file(name string, size int64) {
d.children[name] = &file{
name: name,
size: size,
}
}
func (d *dir) path() string {
if d.name == "" {
return "/"
}
p := []string{d.name}
w := d.parent
for w != nil {
p = append([]string{w.name}, p...)
w = w.parent
}
return strings.Join(p, "/")
}
func (d dir) Size() int64 {
sum := int64(0)
for _, c := range d.children {
switch v := c.(type) {
case *dir:
sum += v.Size()
case *file:
sum += v.size
default:
panic("invalid child")
}
}
return sum
}
func (d *dir) forEach(fn func(*dir)) {
fn(d)
for _, c := range d.children {
sub, ok := c.(*dir)
if !ok {
continue
}
sub.forEach(fn)
}
}
func (d dir) Size100KB() int64 {
const limit = 100000
sum := int64(0)
d.forEach(func(sub *dir) {
size := sub.Size()
if size < limit {
sum += size
}
})
return sum
}
type file struct {
name string
size int64
}
func (f file) String() string {
return fmt.Sprintf("%s (%d)", f.name, f.size)
}