scarecrw's recent activity
-
Comment on What games have you been playing, and what's your opinion on them? in ~games
-
Comment on What programming/technical projects have you been working on? in ~comp
scarecrw This is super cool! Do you have a link to any of the papers you used as reference? I'd love to learn about how this works.This is super cool! Do you have a link to any of the papers you used as reference? I'd love to learn about how this works.
-
Comment on United States: What personal (non-business) tax software/program do you use? in ~finance
scarecrw The IRS system was available in my state last year, but it only covered federal taxes, not state. That meant I was going to have to use another service anyways to file state taxes, and it wasn't...The IRS system was available in my state last year, but it only covered federal taxes, not state. That meant I was going to have to use another service anyways to file state taxes, and it wasn't worth doing everything twice. I suppose if you're in a state without income tax then it might be worth it, but otherwise I didn't really see the benefit.
-
Comment on Randomized trial shows AI tutoring effective in Nigeria in ~tech
scarecrw I've been eagerly waiting to see how some of these AI-assisted educational programs perform, especially those focused on broadening access to education. A lot of the overly-rosy perspectives tend...I've been eagerly waiting to see how some of these AI-assisted educational programs perform, especially those focused on broadening access to education. A lot of the overly-rosy perspectives tend to compare outcomes to students who received no treatment whatsoever, which is a disingenuous way to report an approach's effectiveness, so it was very confidence inspiring to see that this also outperformed the majority of comparable interventions.
I was also pleased to see from their videos how they seemed to have made the experience a social activity, involving interaction with the teacher and other students. A lot of failed attempts at using technology in education seem tailored for some mythical, emotionless, entirely self-motivated student.
There's some draw to the idea that, if only the explanations were perfect and practice exercises just-so, every student would breeze through any topic. Maybe the AI optimists are correct, and we'll see some revolution coming, but from my experience with students in the present, a lot of the effectiveness of educational approaches stems from fostering an environment conducive for learning and building students' confidence in their own abilities. While current LLMs seem far from providing this on their own, I hope more efforts like this one find ways to use them in conjunction with more human approaches.
-
Comment on Day 25: Code Chronicle in ~comp.advent_of_code
scarecrw Part 2 was definitely this year's "don't generalize, just inspect your input" problem. I can say that while I at some point knew how adders were set up, the only information that was necessary is...Part 2 was definitely this year's "don't generalize, just inspect your input" problem. I can say that while I at some point knew how adders were set up, the only information that was necessary is that each bit in the output is calculated in roughly the same way.
minor spoiler
For example, after sorting all the connections that led to a z output, I could see:
... gmw XOR cqn -> z08 jgj XOR gff -> z09 x10 AND y10 -> z10 // that's weird fgb XOR bmd -> z11 qbw XOR gvj -> z12 bgh XOR ctc -> z13 pvs XOR wgc -> z14 ...
Just the obvious stand-outs accounted for 3/4 of the swaps for my input. Finding what to replace them with was a bit more challenging, but the same premise of "follow the pattern" still holds.
Btw, thanks for sharing your Jai work! I'd never heard of the language, and while I'm not sure if I'm interested in trying it, I watched one of the creator's videos and the ideas seemed super interesting!
-
Comment on Day 25: Code Chronicle in ~comp.advent_of_code
scarecrw Short and sweet to finish! I just hardcoded all the dimensions, but it's the last day, so I'm happy enough with it. Smalltalk Solution Class { #name : 'Day25Solver', #superclass : 'AoCSolver',...Short and sweet to finish! I just hardcoded all the dimensions, but it's the last day, so I'm happy enough with it.
Smalltalk Solution
Class { #name : 'Day25Solver', #superclass : 'AoCSolver', #instVars : [ 'locks', 'keys' ], #category : 'AoCDay25', #package : 'AoCDay25' } Day25Solver >> getHeights: aString [ | heights | heights := OrderedCollection new: 5 withAll: 0. aString lines do: [ :row | row withIndexDo: [ :c :i | c = $# ifTrue: [ heights at: i put: (heights at: i) + 1 ] ] ]. ^ heights ] Day25Solver >> parseRawData [ locks := OrderedCollection new. keys := OrderedCollection new. (rawData splitOn: String cr , String cr) do: [ :schematic | (schematic startsWith: '#') ifTrue: [ locks add: (self getHeights: schematic) ] ifFalse: [ keys add: (self getHeights: schematic) ] ] ] Day25Solver >> solvePart1 [ ^ locks collectAndSum: [ :lock | keys count: [ :key | (lock + key) max <= 7 ] ] ]
I've certainly come a long with Pharo since the beginning of the month! I can't say I expect to use it much going forward, but I'm pleased to have gotten through AoC with it and definitely feel like I've gotten the "experience" of working in a language like this. I caught myself the other day writting in another language and thinking "oh man, I wish I could do it like Pharo..." which is always a great indicator that something's started to rub off.
Always more puzzles to be had, but this year's AoC was a wonderful time!
-
Comment on Day 24: Crossed Wires in ~comp.advent_of_code
scarecrw This was a fantastic problem for using Pharo! I still don't have a generalized solution to Part 2, but this was a great opportunity to showcase the difference between Pharo and traditional...This was a fantastic problem for using Pharo! I still don't have a generalized solution to Part 2, but this was a great opportunity to showcase the difference between Pharo and traditional programming environments. Instead of writing an algorithm to solve, I focused on building objects and tools and just working in the inspector.
I can't really share this process in a neat way, but here's a screenshot to give a sense of what this looks like during the process: https://i.imgur.com/3Sq9t8E.png
Once I had a way to inspect the connections, swap outputs, and test the result, actually finding the solutions was fairly trivial: just look for the odd ones out that don't follow the pattern of every other connection.
-
Comment on Day 23: LAN Party in ~comp.advent_of_code
scarecrw (edited )LinkI'm sure at some point I knew some proper clique finding algorithm, but I couldn't remember anything. IIRC a generalized solution is NP-hard, but I took a look at the graph and noticed all the...I'm sure at some point I knew some proper clique finding algorithm, but I couldn't remember anything. IIRC a generalized solution is NP-hard, but I took a look at the graph and noticed all the nodes have the same degree, and just counted down from this upper bound on the clique size.
Similar to yesterday, I think one of the most useful skills I've most developed for these types of problems is being able to quickly eyeball what approaches are going to fit the input size. I can definitely see myself in the past getting lost in the weeds on an approach that was never going to be efficient enough.
I didn't do much refactoring, so code's pretty ugly today, with some goofy deep nesting.
Pharo Smalltalk Solution
Class { #name : 'Day23Solver', #superclass : 'AoCSolver', #instVars : [ 'computers' ], #category : 'AoCDay23', #package : 'AoCDay23' } Day23Solver >> cliquesOfSize: size [ | potentialCliques | potentialCliques := OrderedCollection new. computers keysAndValuesDo: [ :comp :neighbors | neighbors combinations: size - 1 atATimeDo: [ :comb | potentialCliques add: comb asOrderedCollection , { comp } ] ]. ^ potentialCliques select: [ :x | self isClique: x ] ] Day23Solver >> isClique: aCollection [ aCollection withIndexDo: [ :v :i | ((computers at: v) includesAll: (aCollection allButFirst: i)) ifFalse: [ ^ false ] ]. ^ true ] Day23Solver >> parseRawData [ | comps | computers := Dictionary new. rawData lines do: [ :line | comps := line splitOn: '-'. (computers at: comps first ifAbsentPut: OrderedCollection new) add: comps second. (computers at: comps second ifAbsentPut: OrderedCollection new) add: comps first ] ] Day23Solver >> solvePart1 [ ^ ((self cliquesOfSize: 3) count: [ :clique | clique anySatisfy: [ :x | x first = $t ] ]) // 3 ] Day23Solver >> solvePart2 [ | maxSize cliques | maxSize := computers values first size + 1. maxSize to: 1 by: -1 do: [ :size | cliques := self cliquesOfSize: size. cliques ifNotEmpty: [ ^ ',' join: cliques first sorted ] ]. ]
Edit: simplified code a bit
-
Comment on Day 22: Monkey Market in ~comp.advent_of_code
scarecrw (edited )LinkNot super proud of the result, but solving went smoothly. I didn't make any optimizations on the PRNG, though I suspect there may be some. My part 2 takes ~12 seconds to run, so if I have some...Not super proud of the result, but solving went smoothly. I didn't make any optimizations on the PRNG, though I suspect there may be some. My part 2 takes ~12 seconds to run, so if I have some time I might see if I can fix that. I think the issue is in storing and using the delta sequence as a key in the dictionary; that or in merging dictionaries.
Pharo Smalltalk Solution:
PRNG
Class { #name : 'Day22PRNG', #superclass : 'Object', #instVars : [ 'startingNumber', 'currentNumber', 'deltaHistory' ], #category : 'AoCDay22', #package : 'AoCDay22' } Day22PRNG >> initialize [ startingNumber := 0. deltaHistory := 0 ] Day22PRNG >> next [ | oldPrice delta | oldPrice := self price. currentNumber := (currentNumber << 6 bitXor: currentNumber) % (1 << 24). currentNumber := (currentNumber >> 5 bitXor: currentNumber) % (1 << 24). currentNumber := (currentNumber << 11 bitXor: currentNumber) % (1 << 24). delta := self price - oldPrice. deltaHistory := (deltaHistory * 18 + delta + 9) % (18 ** 4). ^ currentNumber ] Day22PRNG >> price [ ^ currentNumber rem: 10 ] Day22PRNG >> startingNumber: anObject [ startingNumber := anObject. currentNumber := anObject ]
Solver
Class { #name : 'Day22Solver', #superclass : 'AoCSolver', #instVars : [ 'startingNumbers' ], #category : 'AoCDay22', #package : 'AoCDay22' } Day22Solver >> parseRawData [ startingNumbers := rawData lines collect: #asInteger ] Day22Solver >> solvePart1 [ | prng | ^ startingNumbers collectAndSum: [ :startingNum | prng := Day22PRNG new startingNumber: startingNum. 2000 timesRepeat: [ prng next ]. prng currentNumber ] ] Day22Solver >> solvePart2 [ | sums prng key totalSums | totalSums := Dictionary new. startingNumbers do: [ :startingNum | sums := Dictionary new. prng := Day22PRNG new startingNumber: startingNum. prng next; next; next; next. 1996 timesRepeat: [ key := prng deltaHistory. sums at: key put: (sums at: key ifAbsent: prng price). prng next ]. sums keysAndValuesDo: [ :k :v | totalSums at: k update: [ :curr | curr + v ] initial: v ] ]. ^ totalSums values max ]
Edit: Sorted out the delta history hashing! Part 2 now runs in ~2.5 seconds which is good enough for me!
-
Comment on Day 21: Keypad Conundrum in ~comp.advent_of_code
scarecrw Definitely a step up in difficulty from the previous few days! I was shocked to almost make the leaderboard for part 1, but definitely struggled a bit more with part 2. I spent some time after...Definitely a step up in difficulty from the previous few days! I was shocked to almost make the leaderboard for part 1, but definitely struggled a bit more with part 2. I spent some time after refactoring to generalize the keypads a bit, though I still wouldn't describe today's solution as particularly comprehensible.
Solution Logic
The core insight was that, while each level was different, the best move sequence to get from one key to another was always the same for a given level. With 5 keys to move between and 25 levels, this leads to a manageable number of options to test.
-
Comment on Day 20: Race Condition in ~comp.advent_of_code
scarecrw Came up with the approach I ended up using fairly quickly, but made some silly mistakes along the way. Part 2 still takes ~5 seconds to run, so I'm hoping to see someone else with a better...Came up with the approach I ended up using fairly quickly, but made some silly mistakes along the way. Part 2 still takes ~5 seconds to run, so I'm hoping to see someone else with a better solution.
Smalltalk Solution
Class { #name : 'Day20Solver', #superclass : 'AoCSolver', #instVars : [ 'startPos', 'endPos', 'walls', 'goal', 'width', 'height', 'endDistance' ], #category : 'AoCDay20', #package : 'AoCDay20' } Day20Solver >> parseRawData [ height := rawData lines size. width := (rawData lines at: 1) size. walls := Set new. rawData lines withIndexDo: [ :row :r | row withIndexDo: [ :val :c | val = $# ifTrue: [ walls add: r @ c ]. val = $S ifTrue: [ startPos := r @ c ]. val = $E ifTrue: [ endPos := r @ c ] ] ]. self buildEndDistance ] Day20Solver >> buildEndDistance [ | curr dist | endDistance := Dictionary new. curr := Set newFrom: { endPos }. dist := 0. [ curr isEmpty ] whileFalse: [ curr do: [ :pos | endDistance at: pos put: dist ]. dist := dist + 1. curr := ((curr flatCollect: [ :pos | pos fourNeighbors ]) select: [ :pos | self canMove: pos ]) reject: [ :pos | endDistance includesKey: pos ] ] ] Day20Solver >> canMove: pos [ ^ (pos between: 1 @ 1 and: height @ width) and: [ (walls includes: pos) not ] ] Day20Solver >> neighborsOf: aPoint distance: dist [ | neighbors | neighbors := (aPoint x - dist to: aPoint x + dist) flatCollect: [ :r | (aPoint y - dist to: aPoint y + dist) collect: [ :c | r @ c ] ]. ^ neighbors select: [ :pos | (self canMove: pos) and: [ (aPoint manhattanDistanceTo: pos) <= dist ] ] ] Day20Solver >> solveWithJumpSize: jumpSize [ | cheatValues jumpStarts | jumpStarts := (1 to: height) flatCollect: [ :r | (1 to: width) collect: [ :c | r @ c ] ]. jumpStarts := jumpStarts select: [ :pos | self canMove: pos ]. cheatValues := jumpStarts flatCollect: [ :jumpStart | (self neighborsOf: jumpStart distance: jumpSize) collect: [ :jumpEnd | (endDistance at: jumpStart) - (endDistance at: jumpEnd) - (jumpStart manhattanDistanceTo: jumpEnd) ] ]. ^ cheatValues count: [ :cheatVal | cheatVal >= goal ] ] Day20Solver >> solvePart1 [ ^ self solveWithJumpSize: 2 ] Day20Solver >> solvePart2 [ ^ self solveWithJumpSize: 20 ]
-
Comment on Day 19: Linen Layout in ~comp.advent_of_code
scarecrw (edited )LinkHard to complain, but this felt far easier than previous day 19s. I think I might just be biased having done enough coding puzzles in the past that I've probably done something similar a half...Hard to complain, but this felt far easier than previous day 19s. I think I might just be biased having done enough coding puzzles in the past that I've probably done something similar a half dozen times.
Nothing special about the solution, just recursively solving each string by testing all the prefixes, caching results for part 2.
Smalltalk Solution
Class { #name : 'Day19Solver', #superclass : 'AoCSolver', #instVars : [ 'patterns', 'designs', 'cache' ], #category : 'AoCDay19', #package : 'AoCDay19' } Day19Solver >> canBuild: design [ design ifEmpty: [ ^ true ]. ^ (patterns select: [ :pattern | design beginsWith: pattern ]) anySatisfy: [ :pattern | self canBuild: (design allButFirst: pattern size) ] ] Day19Solver >> countBuilds: aString [ | options ans | (cache includesKey: aString) ifTrue: [ ^ cache at: aString ]. aString isEmpty ifTrue: [ ^ 1 ]. options := patterns select: [ :pattern | aString beginsWith: pattern ]. ans := (options collect: [ :option | self countBuilds: (design allButFirst: option size) ]) sumNumbers. cache at: aString put: ans. ^ ans ] Day19Solver >> initialize [ cache := Dictionary new. ] Day19Solver >> parseRawData [ patterns := rawData lines first splitOn: ', '. designs := rawData lines allButFirst: 2. ] Day19Solver >> solvePart1 [ ^ designs count: [ :design | self canBuild: design ] ] Day19Solver >> solvePart2 [ ^ (designs collect: [ :design | self countBuilds: design ]) sum ]
-
Comment on Day 18: RAM Run in ~comp.advent_of_code
scarecrw (edited )LinkFastest day so far! That's not saying too much, as I wasn't particularly going for speed this year, but I'm happy that I'm getting more fluent with Pharo and not having to spend time searching...Fastest day so far! That's not saying too much, as I wasn't particularly going for speed this year, but I'm happy that I'm getting more fluent with Pharo and not having to spend time searching around too much.
I just used BFS, which was fast enough when combined with a binary search for part 2. Thankfully, I've learned from previous years not to use an actual 2D grid when possible, and instead just use borders and a set of obstacles, which made running the search with a different collection of obstacles trivial.
Smalltalk Solution
Class { #name : 'Day18Solver', #superclass : 'AoCSolver', #instVars : [ 'gridSize', 'bytes', 'part1Size' ], #category : 'AoCDay18', #package : 'AoCDay18' } Day18Solver >> parseRawData [ | coords | bytes := rawData lines collect: [ :line | coords := (line splitOn: $,) collect: #asInteger. coords first @ coords second ] ] Day18Solver >> pathLengthWithFallen: fallenCount [ | steps queue currPos fallen | fallen := (bytes first: fallenCount) asSet. steps := Dictionary newFromPairs: { 0 @ 0 . 0 }. queue := { 0 @ 0 } asOrderedCollection. [ queue isNotEmpty ] whileTrue: [ currPos := queue removeFirst. currPos fourNeighbors select: [ :neighbor | self validPosition: neighbor withFallen: fallen ] thenDo: [ :neighbor | (steps includesKey: neighbor) ifFalse: [ steps at: neighbor put: (steps at: currPos) + 1. queue add: neighbor ] ] ]. ^ steps at: gridSize @ gridSize ifAbsent: 0 ] Day18Solver >> solvePart1 [ ^ self pathLengthWithFallen: part1Size ] Day18Solver >> solvePart2 [ | lower upper mid | lower := part1Size. upper := bytes size. [ lower < upper ] whileTrue: [ mid := upper + lower // 2. (self pathLengthWithFallen: mid) = 0 ifTrue: [ upper := mid - 1 ] ifFalse: [ lower := mid + 1 ] ]. ^ bytes at: lower ] Day18Solver >> validPosition: pos withFallen: fallen [ ^ (pos between: 0 @ 0 and: gridSize @ gridSize) & (fallen includes: pos) not ]
-
Comment on Day 17: Chronospatial Computer in ~comp.advent_of_code
scarecrw (edited )LinkPretty fun day! Very reminiscent of a previous year (I can't remember which one) which also relied on interpreting the given instructions. I think that day was about optimizing them, whereas today...Pretty fun day! Very reminiscent of a previous year (I can't remember which one) which also relied on interpreting the given instructions. I think that day was about optimizing them, whereas today the only necessary information was how the A register was iterated over 3 bits of at a time (I'm assuming this was the same in everyone's input, or at least similar).
I'm still getting burned by indexing from 1... Today it was that
findNext:
returns a 1-based index, or 0 on failure.Computer Simulator
Class { #name : 'Day17Computer', #superclass : 'Object', #instVars : [ 'a', 'b', 'c', 'program', 'ip', 'halted', 'output' ], #category : 'AoCDay17', #package : 'AoCDay17' } Day17Computer >> initialize [ ip := 1. halted := false. output := OrderedCollection new. ] Day17Computer >> step [ | opcode operations combo literal | (ip between: 1 and: program size) ifFalse: [ halted := true. ^ self ]. opcode := program at: ip. literal := program at: (ip + 1). combo := { 0 . 1 . 2 . 3 . a . b . c } at: ((program at: (ip + 1)) + 1). operations := Dictionary newFromPairs: { 0 . [ a := a >> combo ] . 1 . [ b := b bitXor: literal ] . 2 . [ b := combo % 8 ] . 3 . [ a ~= 0 ifTrue: [ ip := literal - 1 ] ] . 4 . [ b := b bitXor: c ] . 5 . [ output add: combo % 8 ] . 6 . [ b := a >> combo ] . 7 . [ c := a >> combo ] }. (operations at: opcode) value. ip := ip + 2 ]
Solver
Class { #name : 'Day17Solver', #superclass : 'AoCSolver', #instVars : [ 'aInitial', 'bInitial', 'cInitial', 'program' ], #category : 'AoCDay17', #package : 'AoCDay17' } Day17Solver >> parseRawData [ | nums | nums := ('\d+' asRegex matchesIn: rawData) collect: #asInteger. aInitial := nums first. bInitial := nums second. cInitial := nums third. program := nums allButFirst: 3 ] Day17Solver >> solvePart1 [ ^ $, join: ((self runComputer: aInitial) collect: #asString) ] Day17Solver >> solvePart2 [ ^ self solve2Helper: 0 finished: 0 ] Day17Solver >> runComputer: aStart [ | computer | computer := Day17Computer new a: aStart; b: bInitial; c: cInitial; program: program. [ computer halted ] whileFalse: [ computer step ]. ^ computer output ] Day17Solver >> solve2Helper: a finished: n [ | output target recResult | n = program size ifTrue: [ ^ a ]. target := program at: program size - n. 0 to: 7 do: [ :x | output := self runComputer: a << 3 + x. output first = target ifTrue: [ recResult := self solve2Helper: a << 3 + x finished: n + 1. recResult > 0 ifTrue: [ ^ recResult ] ] ]. ^ 0 ]
-
Comment on Day 16: Reindeer Maze in ~comp.advent_of_code
scarecrw While exploring Pharo before AoC started, I did notice that there are some pathfinding algorithms programmed in. I actually found them because they seem to be where the generalized graph data...While exploring Pharo before AoC started, I did notice that there are some pathfinding algorithms programmed in. I actually found them because they seem to be where the generalized graph data structure is also contained. I didn't end up using them, but I might go back and try to re-solve with that approach to learn how those work.
I ended up storing the nodes as 3D points, with the regular position in x and y and the z storing the direction. I mostly did this to avoid having to write a new class with its own hash function, but it worked quite well. I've also gotten more comfortable adding methods to base classes: today I extended the
x@y
syntax for creating aPoint
tox@y@z
to create aG3DCoordinates
as well as addedatPoint:put:
forArray2D
which I had been wanting in previous days. -
Comment on Day 15: Warehouse Woes in ~comp.advent_of_code
scarecrw Definitely my longest day as far as LOC, but that's mostly because there's lots of repeated code for the slightly different cases. Paired with the way Pharo outputs to text files it's nearing 200...Definitely my longest day as far as LOC, but that's mostly because there's lots of repeated code for the slightly different cases. Paired with the way Pharo outputs to text files it's nearing 200 lines...
Other than getting tripped up again with input parsing (I've updated my tools to avoid it going forward), this was a pretty smooth day.
-
Comment on Day 14: Restroom Redoubt in ~comp.advent_of_code
scarecrw Continuing to find more new tools that Pharo has built-in! Today was quadrantOf: which was helpful for part 1 and fourNeighbors which I could have avoided writing myself in some previous days and...Continuing to find more new tools that Pharo has built-in! Today was
quadrantOf:
which was helpful for part 1 andfourNeighbors
which I could have avoided writing myself in some previous days and helped for my approach to part 2.If I have time this weekend I might look a bit more into Morphs and how to set up some useful displays for future days. In the past I always just relied on ASCII displays, but Morphs seem to make generating simple visualizations very straightforward, so worth checking out.
-
Comment on Day 13: Claw Contraption in ~comp.advent_of_code
scarecrw You're absolutely right that the tools to edit the environment and built-ins is probably the coolest part. Numerous times now I've found myself thinking "oh man, I wish that X had a Y feature..."...You're absolutely right that the tools to edit the environment and built-ins is probably the coolest part. Numerous times now I've found myself thinking "oh man, I wish that X had a Y feature..." before realizing, I can just add that! That and the tests/debugging definitely set it apart from other languages in how you work.
I've definitely been learning a lot as I go! Most days I'm kicking myself as I find a tool that would have been very helpful on a previous problem. I looked at those MOOC courses myself, and started through the first couple weeks of one, but ended up finding this book more useful: Pharo By Example.
The only pain point so far is that finding/guessing method names and what they do has not been very intuitive. The aim of having the names flow more like natural language is neat, but ends up making it tough to get used to, coming from other languages.
-
Comment on Day 13: Claw Contraption in ~comp.advent_of_code
scarecrw (edited )LinkProbably one of the easier days so far for most of the logic. I guess if you haven't dealt with math in a bit this could be tricky, but compared to some previous AoC math-y problems this was...Probably one of the easier days so far for most of the logic. I guess if you haven't dealt with math in a bit this could be tricky, but compared to some previous AoC math-y problems this was fairly tame.
I spent most of my time trying to get regex working properly.
Smalltalk Solution
Class { #name : 'Day13Solver', #superclass : 'AoCSolver', #instVars : [ 'machines' ], #category : 'AoCDay13', #package : 'AoCDay13' } Day13Solver >> parseRawData [ machines := ('<n><n>' expandMacros split: rawData) collect: [ :machineString | Day13Machine newFromString: machineString ] ] Day13Solver >> solvePart1 [ ^ (machines collect: [ :machine | machine tokensToWin]) sum ] Day13Solver >> solvePart2 [ ^ (machines collect: [ :machine | machine tokensToWinAlt]) sum ] Class { #name : 'Day13Machine', #superclass : 'Object', #instVars : [ 'aButton', 'bButton', 'prizeLocation', 'prizeLocationAlt' ], #category : 'AoCDay13', #package : 'AoCDay13' } Day13Machine class >> newFromString: aString [ | machine re nums | machine := self new. re := '\d+' asRegex. nums := (re matchesIn: aString) collect: #asInteger. machine aButton: nums first @ nums second. machine bButton: nums third @ nums fourth. machine prizeLocation: nums fifth @ nums sixth. machine prizeLocationAlt: machine prizeLocation + 10000000000000. ^ machine ] Day13Machine >> tokensToWin [ 0 to: 100 do: [ :aPresses | 0 to: 100 do: [ :bPresses | aPresses * aButton + (bPresses * bButton) = prizeLocation ifTrue: [ ^ 3 * aPresses + bPresses ] ] ]. ^ 0 ] Day13Machine >> tokensToWinAlt [ | l1 l2 result | l1 := GLine a: aButton x b: bButton x c: prizeLocationAlt x negated. l2 := GLine a: aButton y b: bButton y c: prizeLocationAlt y negated. result := (l1 intersectionsWith: l2) first asPoint. ^ result isIntegerPoint ifTrue: [ 3 * result x + result y ] ifFalse: [ 0 ] ]
-
Comment on Day 12: Garden Groups in ~comp.advent_of_code
scarecrw Ugh, first day truly annoyed by Pharo... I had the logic quickly, but ran into so many issues just trying to store a grid. There's a built in Array2D, but it doesn't have a neat way to create it...Ugh, first day truly annoyed by Pharo... I had the logic quickly, but ran into so many issues just trying to store a grid. There's a built in
Array2D
, but it doesn't have a neat way to create it from the original data and is also deprecated. I found Containers-Array2D, which hasCTArray2D
withfromRows
, but I spent far too long before realizing that it uses points as x-y instead of row-column... but it does includeCTAlternateArray2D
which uses row-column, but doesn't havefromRows
!I like a lot of what Pharo has as far as tools, but to have something as basic as a 2D array have 3+ inconsistent versions is just ridiculous. I haven't even looked at
CTNewArray2D
,CTNewArray2DRowsAndColumns
, orCTNewArray2DXAndY
...
I hope you enjoy it! It was one of my favorite game experiences.
Something about the game made it much more natural to embrace the role-playing aspect of an RPG. I think it was mostly a nice reprieve from all the games where you're "The Hero" who will inevitably be better and stronger and more special than everyone around you. Your character certainly grows and develops, but it stays much more down to earth and let's you be part of the world instead of treating it like a sandbox.
I'll be curious if you have a take on the monastery quest. I can't say I enjoyed it, but I recall it was fairly devisive.