Another straightforward one. Here, I’ve used the “closure object trick”. Reindeer are stored as a hash of reindeer hashes, keyed by name. Each of these hashes is created by the addreindeer
function, which creates a closure. The hash contains code elements, which access data in this closure. This data is effectively private to the hash. Other elements of the hash contain data, which the code in the hash can access via the this
variable, also stored in the closure, which references the hash itself. Thus, we have private members, methods, and we could have inheritance if we ever wrote code to take the hash and change some of its members. There’s also some moderately clever list processing and functional stuff.
Angort is good for this sort of thing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
require "util.ang" import `regex library drop `io library drop # a hash of hashes of reindeer data by name [%] !Reindeer # add a reindeer to the reindeer hash, initialising # the travelled distance :addreindeer |name,speed,flytime,resttime:this| # addreindeer creates a closure which we use to access # the reindeer's private attributes [% dup!this # store "this" in the closure # these are values we can access from outside the hash # the usual way `distance 0, `resting 0, `score 0, `modetimeleft ?flytime, `tick ( ?this?`resting if ?this?`modetimeleft 1- dup ?this!`modetimeleft 0 = if 0 ?this!`resting ?flytime ?this!`modetimeleft then else ?this?`modetimeleft 1- dup ?this!`modetimeleft 0 = if 1 ?this!`resting ?resttime ?this!`modetimeleft then ?this?`distance ?speed + ?this!`distance then ), `show ( [?name, ?this?`resting if "resting" else "flying " then, ?this?`modetimeleft, ?this?`distance, ?this?`score ] "%10s : %s timeleft:%-6d distance:%-6d score: %-6d" format. ), `reset ( 0 ?this!`distance 0 ?this!`resting 0 ?this!`score ?flytime ?this!`modetimeleft ), `incscore ( ?this?`score 1+ ?this!`score ) ] ?name ?Reindeer set ; :tick ?Reindeer each { ival?`tick@ } ; :resetall ?Reindeer each {ival?`reset@}; (|:l,m| "day14in" "r" io$open each {i <<"\\s+" regex$compile>> regex$split !l # slightly terse technique for getting certain elements from # the input list and passing them to a function ?l fst [3,6,13] (?l get toint) map explode addreindeer } # part 1 0 2503 range each {tick} nl nl # sort names by reindeer distance, only need to get names once. [] ?Reindeer each{i,} !L ?L (|a,b:| ?a ?Reindeer get?`distance ?b ?Reindeer get?`distance -) fsort ?L each { i ?Reindeer get?`show@ } nl nl ?L reverse fst ?Reindeer get?`show@ # part 2 nl nl nl nl nl 0 2503 range each { resetall } 0 2503 range each { tick # get the list of reindeer names, sorted in reverse order of # distance ?L (|a,b:| ?b ?Reindeer get?`distance ?a ?Reindeer get?`distance -) fsort # get the maximum dist 0 ?L (?Reindeer get?`distance) map (|a,b:| ?a ?b > if ?a else ?b then) reduce !m # increment the score of all those with that dist ?L each {i ?Reindeer get?`distance ?m = if i ?Reindeer get?`incscore@ then} } nl nl # sort names by score ?L (|a,b:| ?a ?Reindeer get?`score ?b ?Reindeer get?`score -) fsort ?L each { i ?Reindeer get?`show@ } nl nl ?L reverse fst ?Reindeer get?`show@ )@ quit |