Advent of code Day 10

Oforth examples. Feel free to post your own code.

Advent of code Day 10

Postby sotolf » 11 Dec 2016 03:37

I'm doing this years advent of code in python, and I was trying the challenge for today in oforth, it was fun. I really got stuck in debugging my loops for a while though, so I've learnt how to better debug in oforth, when you get used to it it's actually very powerful.

As normally the code is full of inefficiencies and things a good programmer wouldn't do, but I was thinking I'd share this little example as well.

--- Day 10: Balance Bots ---

You come upon a factory in which many robots are zooming around handing small microchips to each other.

Upon closer examination, you notice that each bot only proceeds when it has two microchips, and once it does, it gives each one to a different bot or puts it in a marked "output" bin. Sometimes, bots take microchips from "input" bins, too.

Inspecting one of the microchips, it seems like they each contain a single number; the bots must use some logic to decide what to do with each chip. You access the local control computer and download the bots' instructions (your puzzle input).

Some of the instructions specify that a specific-valued microchip should be given to a specific bot; the rest of the instructions indicate what a given bot should do with its lower-value or higher-value chip.

For example, consider the following instructions:

value 5 goes to bot 2
bot 2 gives low to bot 1 and high to bot 0
value 3 goes to bot 1
bot 1 gives low to output 1 and high to bot 0
bot 0 gives low to output 2 and high to output 0
value 2 goes to bot 2

Initially, bot 1 starts with a value-3 chip, and bot 2 starts with a value-2 chip and a value-5 chip.
Because bot 2 has two microchips, it gives its lower one (2) to bot 1 and its higher one (5) to bot 0.
Then, bot 1 has two microchips; it puts the value-2 chip in output 1 and gives the value-3 chip to bot 0.
Finally, bot 0 has two microchips; it puts the 3 in output 2 and the 5 in output 0.

In the end, output bin 0 contains a value-5 microchip, output bin 1 contains a value-2 microchip, and output bin 2 contains a value-3 microchip. In this configuration, bot number 2 is responsible for comparing value-5 microchips with value-2 microchips.

Based on your instructions, what is the number of the bot that is responsible for comparing value-61 microchips with value-17 microchips?

Your puzzle answer was 161.
--- Part Two ---

What do you get if you multiply together the values of one chip in each of outputs 0, 1, and 2?

Your puzzle answer was 133163.

Both parts of this puzzle are complete! They provide two gold stars: **

At this point, you should return to your advent calendar and try another puzzle.

If you still want to see it, you can get your puzzle input.

Code: Select all

import: collect

\ Hash of which bots are holding which values
tvar: bots
Hash new to bots

\ Hash of output values
tvar: outputs
Hash new to outputs

\ Opens file with given name for reading
: openFile \ filename -- aFile
  File new dup open(File.READ); \ open file with input

\ Reads all lines from an open file to an ArrayBuffer
: readLines \ file(open) -- ArrayBuffer
  ArrayBuffer new
  while ( over readLine dup notNull )
    [ over add ]
  drop nip ;

\ gives value to a bot, if the bot doesn't exist it gets created
: givebot \ value bot#  --
  dup bots keyAt isNull
    ifTrue: [ swap ArrayBuffer new tuck add bots insert ]
    else: [ bots valueAt add ] ;

\ gives value to output, creates if doesn't exist
: giveout \ bot# value --
  dup outputs keyAt isNull
    ifTrue: [ swap ArrayBuffer new tuck add outputs insert ]
    else: [ outputs valueAt add ] ;

\ get second word in a sentence as an int
: 2ndint \ String -- Int
  words at(2) asInteger ;

\ adds a bot and its value to botsbuffer
: addBot \ String --
  dup words at(6) asInteger swap
  2ndint swap
  givebot ;

\ checks if string starts with the word "value"
: isValue \ String - ?
  words first "value" == ;

\ checks if string starts with the word "bot"
: isBot \ String - ?
  words first "bot" == ;

\ checks if the bot is already initialized
\ and that it has 2 values that it can give out
: canActivate \ String - ?
  2ndint  dup bots keyAt isNull
    ifTrue: [ drop false return ]
  bots valueAt size 2 = ;

\ activates a bot and follows the command
: activate \ string --
  dup 2ndint
  bots valueAt sort dup second swap first
  3 pick words at(6) "bot" ==
    ifTrue: [ 3 pick words at(7) asInteger givebot ]
    else:   [ 3 pick words at(7) asInteger giveout ]
  over words at(11) "bot" ==
    ifTrue: [ swap words at(12) asInteger givebot ]
    else:   [ swap words at(12) asInteger giveout ] ;

\ handles one line, and throws it away if it can be handled
\ else puts it back at the end of the ArrayBuffer
: handle \ ArrayBuffer -- ArrayBuffer
  dup removeAt(1)
  dup isValue
    ifTrue: [ addBot return ]
  dup isBot
  over canActivate and
    ifTrue: [ activate return ]
  \ Couldn't do anything with the instruction for now, so we'll
  \ just add it back in the end of the queue
  over add ;

\ loops through the list of lines until it has handled every line
: loopThrough  \ ArrayBuffer -- Empty ArrayBuffe
while( dup size ) [ handle ] drop ;

: findbot \ ArrayBuffer -- key
| o | bots forEach: o [ dup o value == ifTrue: [ drop o key return ] ] ;

: getoutput
  outputs valueAt first ;

"day10" openFile dup readLines swap close  loopThrough
[61, 17] dup findbot "Bot" . . "handles" . dup first . "and" . second .cr
"Output 0 * 1 * 2:" . 0 getoutput 1 getoutput 2 getoutput * * .cr

Posts: 55
Joined: 30 Jul 2015 15:53

Re: Advent of code Day 10

Postby Franck » 11 Dec 2016 12:37


Thank you for sharing.
Your code in Oforth has improved a lot !

Just some comments :

1) In Oforth, files are collections of lines.
You can use methods on collections on files.

For instance :
Code: Select all
\ Return a list of all lines into a file
"afile" File new map( #yourself)

Code: Select all
\ Return a list of all size of lines into a file
"afile" File new map( #size )

Code: Select all
\ Returns lines with size greater than 20
"afile" File new mapIf( #[ size 20 >= ], #yourself )

2) If you test for null, you can you #ifNull: or ifNotNull:

Of course, you can add a #else: after if necessary

Code: Select all
: givebot \ value bot#  --
  dup bots keyAt
    ifNull: [ swap ArrayBuffer new tuck add bots insert ]
    else:   [ bots valueAt add ] ;

3) #givebot and #giveout are really similar.
This needs to be factored :)

4) Some shotcuts :
at(2) --> second
removeAt(1) --> removeFirst
findbot --> keyAt

5) I don't like your activate word :)

Its obvious that you are becoming a lot more familiar with Oforth. Great !

Posts: 140
Joined: 29 Oct 2014 19:01

Re: Advent of code Day 10

Postby sotolf » 11 Dec 2016 14:28

As always, thank you for all the tips, the ifNull function is very cool.

I have to say I really like the nil punning possibility with booleans, since their just numbers it's quite practical.

and Yeah, there are a lot of factoring possible, but at the time I posted it was 04:00 :P and I needed some sleep, I was just so happy that I got it to work :P

I'm not sure if it's feasable to do the problem without the tvars, it feels a bit dirty, but it would clutter the code up so much having to drag the two hashes around into all functions, and it would make the stack juggling a nightmare.

I have to say though that I was going into the thing thinking it would be very hard, and barred some stupid mistakes that was keeping me down.

I'm starting to see more possibilities for factoring every time that I write a new thing in oforth, and every time it surprises me with having some elegant ways of doing stuff. It sure has a bit of a steep learning curve some times, but man is it fun :)
Posts: 55
Joined: 30 Jul 2015 15:53

Return to Oforth examples

Who is online

Users browsing this forum: No registered users and 1 guest