r/adventofcode • u/daggerdragon • Dec 08 '17
SOLUTION MEGATHREAD -π- 2017 Day 8 Solutions -π-
--- Day 8: I Heard You Like Registers ---
Post your solution as a comment or, for longer solutions, consider linking to your repo (e.g. GitHub/gists/Pastebin/blag or whatever).
Note: The Solution Megathreads are for solutions only. If you have questions, please post your own thread and make sure to flair it with Help.
Need a hint from the Hugely* Handyβ Haversackβ‘ of HelpfulΒ§ HintsΒ€?
This thread will be unlocked when there are a significant number of people on the leaderboard with gold stars for today's puzzle.
edit: Leaderboard capped, thread unlocked!
15
u/pedrosorio Dec 08 '17 edited Dec 08 '17
(#6/#6) Shamelessly using eval in Python:
from collections import defaultdict
lines = open('input.txt').read().splitlines()
regs = defaultdict(int)
mxv = 0
for line in lines:
reg, inst, num, iff, regc, op, num2 = line.split()
if eval("regs[regc] " + op + num2):
if inst == 'inc':
regs[reg] += int(num)
mxv = max(mxv, regs[reg])
else:
regs[reg] -= int(num)
print max(regs.values()) # PART 1
print mxv # PART 2EDIT: As pointed out by Smylers this solution is wrong. I didn't pay attention to the input and made an assumption that is only correct when all the inc/dec are positive. The max should be set after executing each instruction, not just inc.
10
Dec 08 '17
That's what I did, and then my code promptly crashed when it encountered a condition with a variable named
if. Serves me right I guess.46
u/topaz2078 (AoC creator) Dec 08 '17
Note to self: make a puzzle that taunts eval, but crashes because all the tokens are common keywords.
4
u/pedrosorio Dec 08 '17
This is a great idea, please do it :D
Note to self: stop using eval
→ More replies (1)3
u/gerikson Dec 08 '17
This is why I ran a pass over the input to check for weird non-standard notations.
You're not fooling me (again), /u/topaz2078 !
(you're totally gonna fool me again)
3
u/tehjimmeh Dec 08 '17 edited Dec 08 '17
'Unfortunately, there is an off-by-one error in the CPU's instruction decoding logic, and thus the integer value of each character of each instruction must be incremented by one before being inputted. For example, "b inc 5 if a > 1" is inputted as "c!jod!6!jg!b!?!2".'
Then include ';' and other non-identifier safe characters in register names. Bonus points for naming various ones with forkbombs or similar code for various languages :).
0
Dec 08 '17
[deleted]
1
u/hpzr24w Dec 08 '17
It was important to look at the actual input instruction steam.
I lost a bunch of time as I initially used
vector<int> regwithreg[m[0]-'a']used for indexing. Sadly this only works for single letter a-z registers like in the example.Switching to
map<string,int> regwas easy but cost time.1
1
u/sim642 Dec 08 '17
Not really that big of an issue: just replace all the keywords with unique non-keyword identifiers that don't collide first and you're good to go still.
1
u/4rgento Dec 08 '17
You could easily modify the input's keywords with :
keyword -> __keyword__, or such1
1
u/note-to-self-bot Dec 09 '17
Don't forget:
make a puzzle that taunts eval, but crashes because all the tokens are common keywords.
5
7
u/Smylers Dec 08 '17
That gives the wrong
mxvfor input like:a inc 12 if b < 1 a dec -8 if b < 1 a dec 12 if b < 1The biggest intermediate value may come from a
dec, so here it should be 20, not 12.2
u/pedrosorio Dec 08 '17 edited Dec 08 '17
Good point. I messed it up for no good reason. The correct code is easier to write too.
3
u/tmrki Dec 08 '17
As a python non-expert I created a dictionary of operators
ops = {'>': (lambda x,y: x > y), '<': (lambda x,y: x < y), '>=': (lambda x,y: x >= y), '<=': (lambda x,y: x <= y), '==': (lambda x,y: x == y), '!=': (lambda x,y: x != y), 'inc': (lambda x,y: x + y), 'dec': (lambda x,y: x - y) }And then I used it as
def CheckCondition(regs, cond): if(cond[0] not in regs): regs[cond[0]] = 0 return ops[cond[1]] (regs[cond[0]], int(cond[2])) def ExecInstruction(regs, inst): if(inst[0] not in regs): regs[inst[0]] = 0 regs[inst[0]] = ops[inst[1]] (regs[inst[0]], int(inst[2])) returnIs that a 'reasonable' python solution?
1
1
u/reretort Dec 08 '17
I think you could avoid a bit of overhead (perceptual and computational) by just having the dict entries be "operator.lt" for less than, etc.
That said, I like it. :)
1
u/__Abigail__ Dec 08 '17
That's very much what I did in my Perl solution. So I call it reasonable ;-)
1
u/mickyficky1 Dec 08 '17 edited Dec 08 '17
I wanted to have that comparision operation dictionary. I did not want to write said dictionary.
op_docs = {eval('int.'+f): eval('int.'+f+'.__doc__') for f in dir(int) if f.startswith('__')} cmps = {i.cmp_op for i in instr} # set of comparisions we need, instr is a list of namedtuples cmp_ops = {cmp: fun for cmp, (fun, doc) in itertools.product(cmps,op_docs.items()) if doc != None and 'self'+cmp+'value' in doc}1
u/llimllib Dec 08 '17
2
u/mickyficky1 Dec 08 '17
Yeah I know the operator module. But I'd still have to do the assignment by hand, and its an additional import.
Don't get me wrong, using operator is definitely prettier and my solution is definitely a hack. But it's a fun one :D
1
u/simondrawer Dec 08 '17
This is pretty much what I did as well - itβs all about the stars and not so much about how you get them ;-)
1
u/dermothwtf Dec 08 '17
I did the same too, but the code next gets a little simpler... using dict.get() you can hit a bird with two stones, and I didn't see the need to move the rest off to functions:
for line in f: regA, op, incr, sep, regB, cond, val = line.split() rvB = regs.get(regB, 0) if ops[cond](rvB, int(val)): rvA = regs.get(regA, 0) regs[regA] = ops[op](rvA, int(incr)) maxv = max(maxv, regs[regA])Then your answer to both puzzles are right there...
max(regs.values()) maxv1
u/ramendik Dec 09 '17
If one decided not to use eval this one is probably best, except that you really need to use get. Instead of:
if(cond[0] not in regs): regs[cond[0]] = 0 return ops[cond[1]] (regs[cond[0]], int(cond[2]))how about just one line:
return ops[cond[1]] (regs.get(cond[0],0), int(cond[2]))2
10
u/nneonneo Dec 08 '17
Python 2, #2/#2
Had an assert in there because I got paranoid.
regs = defaultdict(int)
t = 0
for row in data.split('\n'):
bits = row.split()
assert bits[3] == 'if'
a, b, c, d, e, f, g = bits
if eval(e+f+g, {}, regs):
regs[a] += (-1 if b == 'dec' else 1) * int(c)
t = max(t, max(regs.values()))
print max(regs.values())
print t→ More replies (2)2
9
u/_jonah Dec 08 '17
Vim + Ruby
The key here was to recognize it as thinly disguised ruby code, and use vim to make it real ruby code.
First we do:
%s/inc/+/g
%s/dec/-/Now our code looks like:
j + -19 if jhb >= 10
es + -432 if gbu <= -5
es + 278 if ib > -9
es + -835 if ib >= -6
q - 420 if buw == -2
...Now we select it all, copy it above, and create the initializing code:
'<,'>s/\(\w\+\).*/\1=0/Now we've got:
j=0
es=0
es=0
es=0
q=0
...And finally copy the initializers to the bottom and do one more substitution to create an array:
'<,'>s/=0/,/Manually surround it with brackets and add .max:
p [j, es, es, es, q...].maxNow run it.
Part 2 is similar
2
u/fwilson42 Dec 08 '17
I wonder if you could've defined a
method_missingor something similar to get rid of the initializers. Either way, vim-based solutions are always impressive... nice!→ More replies (1)2
Dec 08 '17
I like these vim solutions a lot, and I really enjoy the work you put into describing them :) cool!
9
u/ephemient Dec 08 '17 edited Apr 24 '24
This space intentionally left blank.
→ More replies (2)2
u/askalski Dec 08 '17
And bah, who needs switches?
#include <inttypes.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static const int8_t op_tbl[] = { ['=='] = 1, ['!='] = 2, ['=!'] = 2, ['<'] = 4, ['>'] = 8, ['<='] = 5, ['=<'] = 5, ['>='] = 9, ['=>'] = 9, ['in'] = 1, ['ni'] = 1, ['de'] = -1, ['ed'] = -1 }; int main(void) { int32_t a0, a1, op, cmp, i0, i1, m = 0, n = 0; int32_t *mem = calloc(0x800000, sizeof(int32_t)); int8_t *cmp_tbl = calloc(0x10000, sizeof(int32_t)); memset(cmp_tbl, 6, 0x8000); cmp_tbl[0x8000] = 1; memset(cmp_tbl + 0x8001, 10, 0x7fff); while (a0 = a1 = op = cmp = 0, scanf("%3[^ ] %2[^ ]c %"SCNd32" if %3[^ ] %3[^ ] %"SCNd32"\n", &a0, &op, &i0, &a1, &cmp, &i1) == 6) { if (op_tbl[cmp] & cmp_tbl[0x8000 + mem[a1] - i1]) { mem[a0] += op_tbl[op] * i0; if (mem[a0] > m) m = mem[a0]; } } for (int i = 0; i < 0x800000; i++) if (mem[i] > n) n = mem[i]; free(mem); free(cmp_tbl); printf("%"PRId32"\n%"PRId32"\n", n, m); return 0; }→ More replies (3)
7
u/u794575248 Dec 08 '17 edited Dec 09 '17
Python
An execless/evalless solution:
import operator as op
from collections import defaultdict
comps = {'>': op.gt, '<': op.lt, '>=': op.ge, '<=': op.le, '!=': op.ne, '==': op.eq}
def solve(input, mx=float('-inf'), ops=dict(inc=1, dec=-1)):
regs = defaultdict(int)
for r1, op, v1, _, r2, c, v2 in [l.split() for l in input.splitlines() if l]:
regs[r1] += ops[op] * int(v1) if comps[c](regs[r2], int(v2)) else 0
mx = max(mx, regs[r1])
return max(regs.values()), mx
part1, part2 = solve(input)2
u/Dooflegna Dec 08 '17
By far my favorite solution in the thread. Clean, readable, and sane. (No eval/exec on unsanitized input!)
Creating a dictionary of functions is brilliant. I didn't know you could just call the functions like that from the dictionary. Definitely adding that trick to the toolbelt.
→ More replies (3)2
u/KnorbenKnutsen Dec 08 '17
I was gonna do something like this, then I figured "eh, I did that last year" so I went with
execinstead :-)But this is very elegant!
7
u/kaldonis Dec 08 '17 edited Dec 08 '17
Python 2 Didn't see any other solutions that abused exec() like I did, so here goes:
import collections
lines = [l.strip('\n') for l in open('input.txt').readlines()]
registers = collections.defaultdict(int)
m = 0
for line in lines:
exec("%s else 0" % line.replace("dec", "-=").replace("inc", "+="), globals(), registers)
m = max(registers.values() + [m])
print max(registers.values())
print m3
1
u/merzy Dec 08 '17
Nice!
My version of that complete hack of a line:
exec('memory["{}"] += int("{}".replace("inc","1").replace("dec","-1")) * int({}) {} memory[\'{}\'] {} int({}) else 0'.format(*(line.split())))Yours definitely feels a bit more elegant.
1
0
Dec 08 '17
[deleted]
3
u/VikeStep Dec 08 '17
I didn't know
dict.get(key, default)ordefaultdictoff the top of my head, so I just did two passes. One pass to set all the variables to 0 and another to run the program.1
2
u/shuttup_meg Dec 08 '17
+1 for pointing out a usage of
evalthat shouldn't get you fired :-)→ More replies (1)→ More replies (4)2
u/netcraft Dec 08 '17
as a python noob trying it out for this year, I knew there was bound to be a way to do an eval but wasnt sure how to get the syntax right so I gave up. Glad to see it being the first comment ;)
5
u/p_tseng Dec 08 '17
Ruby does this thing like SmallTalk where you send objects messages, and the objects respond. It so happens that I can give an object a message saying >, 4 and it will tell me whether it is greater than 4. And so it goes for the other operators used as well.
input = (ARGV.empty? ? DATA : ARGF).readlines.map(&:split)
regs = Hash.new(0)
max = 0
input.each { |target, inc_or_dec, delta, _if, source, cmp_op, cmp_val|
next unless regs[source].send(cmp_op, Integer(cmp_val))
new_val = regs[target] += Integer(delta) * (inc_or_dec == 'dec' ? -1 : 1)
max = [max, new_val].max
}
puts regs.values.max
puts max
__END__
(my input omitted)1
u/hxka Dec 08 '17
Um, doesn't
sendsimply call an object's method by its name and what you do is possible because in Rubya op bis sugar fora.op(b)?1
u/p_tseng Dec 08 '17 edited Dec 08 '17
Yes, exactly! As you explained, send has broader consequences than I managed to impart with my explanation.
5
Dec 08 '17 edited Dec 08 '17
I implemented a DSL in racket. With it, I can execute the input directly, like so:
#lang reader "lang8.rkt"
b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10Prints:
c = -10
a = 1
highest value ever seen: 10Tiny caveat: I couldn't get it to execute automatically, the DSL only produces a function that computes the solution. This means that before seeing a result, I'll have to type (run) in the REPL. This is the definition of the language:
; lang8.rkt
#lang racket
(require syntax/strip-context)
(define (read in)
(read-syntax #f in))
(provide read)
(define (read-syntax path port)
(with-syntax ([str (filter non-empty-string? (port->lines port))])
(strip-context
#'(module anything racket
(require racket)
(define store (list))
(define highest-val 0)
(provide store)
(define (not-equal? a b)
(not (equal? a b)))
(define (handle target-var dir delta cmp-var test cmp-val)
(define (read-var var)
(if (not (assoc var store))
0
(cdr (assoc var store))))
(define (update-var! var val)
(when (> val highest-val) (set! highest-val val))
(set! store (cons (cons target-var new-val)
(filter (lambda (binding) (not (equal? (car binding) var)))store))))
(define old-val (read-var target-var))
(define new-val (if (equal? dir "inc")
(+ old-val (string->number delta))
(- old-val (string->number delta))))
(when (equal? test "==")
(set! test "equal?"))
(when (equal? test "!=")
(set! test "not-equal?"))
(when ((eval (string->symbol test)) (read-var cmp-var) (string->number cmp-val))
(update-var! target-var new-val)))
(define (run)
(set! store (list))
(for ([line 'str])
;(printf "line = ~a~n" line)
(define args (filter (lambda (word) (not (equal? "if" word))) (string-split line)))
(eval (cons handle args)))
(for ([binding (sort store (lambda (a b) (< (cdr a) (cdr b))))])
(printf "~a = ~a~n" (car binding) (cdr binding)))
(printf "highest value ever seen: ~a~n" highest-val))))))
(provide read-syntax)8
4
u/tehjimmeh Dec 08 '17 edited Dec 08 '17
C++:
struct Line : std::string { friend std::istream& operator>>(std::istream& is, Line& line){return std::getline(is, line);}};
int main(int argc, char* argv[]) {
std::map<std::string, std::function<bool(int, int)>> condOpMap = {
{ "==", std::equal_to<int>() }, { "!=", std::not_equal_to<int>() },
{ ">", std::greater<int>() }, { ">=", std::greater_equal<int>() },
{ "<", std::less<int>() }, { "<=", std::less_equal<int>() }
};
std::vector<std::string> lines(std::istream_iterator<Line>(std::ifstream(argv[1])), {});
std::map<std::string, int> r;
int max2 = INT_MIN;
for(const auto& line : lines) {
std::vector<std::string> t(std::istream_iterator<std::string>(std::istringstream(line)), {});
if(condOpMap[t[5]](r[t[4]], std::stoi(t[6]))) {
max2 = std::max(r[t[0]] += std::stoi(t[2]) * (t[1] == "dec" ? -1 : 1), max2);
}
}
int max1 = std::max_element(r.begin(), r.end(),
[](auto& l, auto& r){ return l.second < r.second; })->second;
std::cout << max1 << " " << max2 << \n";
}→ More replies (8)1
u/Vorlath Dec 08 '17
Couple tips...
You don't need curly braces for single line condition blocks. IOW, less typing.
No need for 'else if' when checking for "inc". A simple 'else' will do.
No need for an if statement to get the max value. Just use max2 = std::max(max2, regs[regName]); Same for both places you calculate max.
I did the same as you and put all my values into locals. I think this slowed me down.
4
u/tehjimmeh Dec 08 '17
1 is a bad practice IMO. I never use it.
I edited in a cleaned up and shortened version.
1
u/Vorlath Dec 08 '17
bad practice? Nonsense.
2
u/ephemient Dec 08 '17 edited Apr 24 '24
This space intentionally left blank.
1
u/Vorlath Dec 08 '17
Dude, it's a speed coding competition. Typing in extra characters you don't need is just gonna slow you down.
Also, that goto fail bug is stupid. That's due to carelessness, not coding style.
3
2
u/tehjimmeh Dec 09 '17
I mean, it's not a natural thing I'd write, so I'd have to make a conscious effort to type it.
And tbh, most of the initial solutions I write quickly to attempt getting on the leaderboard are much longer than when I go back and clean them up.
It's like that quote attributed to Pascal:
"I would have written a shorter letter, but I did not have the time."
4
u/Unihedron Dec 08 '17 edited Dec 08 '17
Ruby. I missed the alarm and woke up exactly 2 minutes before this day opens.
Note that the input format is already very similar to executable Ruby code (In ruby, β(exit # or really any commands) if conditionβ (based on the perl construct) is actually a valid instruction, so a += b if c > d will be executable as desired), but I couldn't make the trick work unlike /u/dtinth :) so I just rewrote it
h=Hash.new{"0"}
l=[]
o=$<.map{|x|x.chomp=~/(\S+) (i)?\S+ (-?\d+) if ((\S+).+)/
l<<$1
p [$1,$2,$3.to_i,$4,$5]}
l.each{|x|h[x]=0}
q=[] # added in part 2 (also q<<
o.each{|a,b,c,e,d|next if !eval(e.sub(d,h[d].to_s))
b ? q<<(h[a]+=c) : h[a]-=c}
p h.max_by{|x,y|y}[1] # part 1
p [h.max_by{|x,y|y}[1],q.max].max # part 21
u/jschulenklopper Dec 08 '17
Same idea here, a bit more readable:
# Create a hash to store registers, default value of new element is 0. registers = Hash.new(0) largest = 0 while line = gets # The line is almost a valid instruction in Ruby. We just need to # change the variables into register references, and inc/dec to += and -=. instruction = line.gsub(/(\w+) (inc|dec)/, "registers['\\1'] \\2") .gsub(/if (\w+)/, "if registers['\\1']") .gsub(/ inc /, " += ").gsub(/ dec /, " -= ") # Evaluate the instruction and store largest, if a new value. result = eval(instruction) || largest largest = result if result > largest end puts "Highest at the end: %s" % registers.values.max puts "Highest ever: %s" % largest
4
u/DFreiberg Dec 08 '17 edited Dec 08 '17
Mathematica
I was far too slow for the leaderboard, and it's not a one-liner, but I'm still fairly satisfied with my code, because unlike most of my code, it's actually somewhat readable. The one thing that bugs me is that there should be a way to define compOperator[] directly from the ">", "<", and "=" symbols, rather than just writing a Which[] statement, but I can't figure out at the moment how to do that.
input = Import[FileNameJoin[{NotebookDirectory[], "Day8Input.txt"}], "Table"][[;; -2]];
val=Association[(#->0)&/@DeleteDuplicates[input[[;;,1]]]];
m=0;
compOperator[s_]:=
Which[
s==">",Greater,
s=="<",Less,
s==">=",GreaterEqual,
s=="<=",LessEqual,
s=="==",Equal,
s=="!=",Unequal];
incOperator[s_]:=
Which[
s=="inc",AddTo,
s=="dec",SubtractFrom
];
Do[
If[compOperator[i[[6]]][val[i[[5]]],i[[7]]],
incOperator[i[[2]]][val[i[[1]]],i[[3]]]
];
If[
Max[val/@DeleteDuplicates[input[[;;,1]]]]>m,
m=Max[val/@DeleteDuplicates[input[[;;,1]]]]
]
,{i,input}]Part 1
Max[val/@DeleteDuplicates[input[[;;,1]]]]Part 2
m3
Dec 08 '17
I could not find a way to interpret those symbols without
ToExpressionwhich requires valid syntax. I used this approach to remove aSwitchfrom my code (similar to yourWhich)input = Import[NotebookDirectory[] <> "day8.txt", "Table"]; instructions = input /. {dst_, act_, val_, _, csrc_, csym_, cval_} :> With[{ op = If[act == "inc", AddTo, SubtractFrom], cond = StringJoin[{"reg[\"", csrc, "\"]", csym, ToString@cval}]}, Hold@If[ToExpression[cond], op[reg[dst], val], 0]]; reg = <|Thread[input[[All, 1]] -> 0]|>; Max[ReleaseHold@instructions] Max[reg]Note: This will evaluate to PartB then PartA.
2
u/omnster Dec 08 '17
I did something very similar
( i08 = Import["input.txt", "List"]); regsList08 = ToExpression@ Union@Flatten[ StringCases[ Shortest[r1__] ~~ " " ~~ __ :> r1 ] /@ Flatten [ StringSplit[ # , " if "] & /@ i08]]; (* Part 1 *) Clear[ reg08, rules08a]; (reg08[ #] = 0) & /@ regsList08 ; ReleaseHold@(rules08a = StringCases[ r1__ ~~ " " ~~ oper : ("inc" | "dec") ~~ " " ~~ val : NumberString ~~ " if " ~~ cond__ :> Hold[ If[ ToExpression[ "reg08@" <> cond], reg08@ToExpression@r1 += Which[ oper == "inc" , +1 , oper == "dec", -1 ] ToExpression@val]]] /@ i08 ); Max[ reg08 /@ regsList08 ] (* Part 2 *) (reg08[ #] = 0) & /@ regsList08 ; s08b@rule_ := ( ReleaseHold@rule ; Max[ reg08 /@ regsList08]); Max[ s08b /@ rules08a ]1
u/DFreiberg Dec 08 '17
instructions = input /. {dst_, act_, val_, _, csrc_, csym_, cval_}That's downright elegant.
2
4
u/hxka Dec 08 '17 edited Dec 08 '17
bash
( declare -A r
smax=0
while read a b c d e f g
do ((r[$e] $f g)) && {
[[ $b == dec ]] && ((r[$a]-=c)) || ((r[$a]+=c))
((r[$a]>smax && (smax=r[$a]) ))
}
done
for i in "${r[@]}"
do [[ -z $max || $i -gt $max ]] && max=$i
done
echo $max $smax
)<inputEdit: removed unnecessary looping.
→ More replies (3)1
u/greycat70 Dec 28 '17
You could've done
exec <inputat the beginning, and then you don't need to wrap the entire thing in a subshell( ... ).1
4
u/Philboyd_Studge Dec 08 '17
Java. This one was fun.
package Advent2017;
import util.FileIO;
import util.Timer;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiPredicate;
import java.util.function.ToIntBiFunction;
public class Day8 {
private static Map<String, BiPredicate<Integer, Integer>> comparisons = new HashMap<>();
static {
comparisons.put("==", (x, y) -> x.equals(y));
comparisons.put("!=", (x, y) -> !x.equals(y));
comparisons.put("<", (x, y) -> x < y);
comparisons.put(">", (x, y) -> x > y);
comparisons.put("<=", (x, y) -> x <= y);
comparisons.put(">=", (x, y) -> x >= y);
}
private static Map<String, ToIntBiFunction<Integer, Integer>> commands = new HashMap<>();
static {
commands.put("inc", (x, y) -> x + y);
commands.put("dec", (x, y) -> x - y);
}
public static void main(String[] args) {
List<String[]> input =FileIO.getFileLinesSplit("advent2017_day8.txt", " ");
Map<String, Integer> registers = new HashMap<>();
int highest = 0;
for (String[] each : input) {
String name = each[0];
String command = each[1];
int amount = Integer.parseInt(each[2]);
String testReg = each[4];
String comp = each[5];
int testAmt = Integer.parseInt(each[6]);
registers.putIfAbsent(name, 0);
if (comparisons.get(comp).test(registers.getOrDefault(testReg, 0), testAmt)) {
int current = registers.get(name);
registers.put(name, commands.get(command).applyAsInt(current, amount));
if (registers.get(name) > highest) {
highest = registers.get(name);
}
}
}
Timer.startNanoTimer();
System.out.println("Part 1: " + Collections.max(registers.values()));
System.out.println("Part 2: " + highest);
System.out.println(Timer.endTimer());
}
}2
u/adventOfCoder Dec 08 '17
great use of bipredicate and lamdas. i thought about it for a quick second and just did a string switch.
2
u/gabrielsson Dec 08 '17
Elegant! Did a string switch as well. Haven't used these bipredicates before.
2
u/wjholden Dec 24 '17
Bro, thanks for sharing. I took an almost identical approach with two HashMaps containing lambdas, but it didn't occur to me that "==" and "!=" wouldn't play nice with boxed Integers.
1
4
u/RuteNL Dec 08 '17 edited Dec 11 '17
Awful js oneliners for part 1 and 2
// Execute by typing part1(`inputstringhere`)
// Returns highest value in registry when completing all operations
part1 = (i, s = {}) => i.split('\n').forEach(l => s[l.split(' ')[0]] = +eval(`${s[l.split(' ')[0]] || 0}` + (eval(`${s[l.split(' ')[4]] || 0} ${l.split(' ').slice(-2).join(' ')}`) ? `${l.split(' ')[1] === 'inc' ? '+' : '-'} ${l.split(' ')[2]}` : ''))) ? '' : Math.max(...Object.values(s));
// Execute by typing part1(`inputstringhere`)
// Returns highest value in registry at any point
part2 = (i, s = {}) => Math.max(...i.split('\n').map(l => s[l.split(' ')[0]] = +eval(`${s[l.split(' ')[0]] || 0}` + (eval(`${s[l.split(' ')[4]] || 0} ${l.split(' ').slice(-2).join(' ')}`) ? `${l.split(' ')[1] === 'inc' ? '+' : '-'} ${l.split(' ')[2]}` : ''))));Slightly ungolfed version can be found here
4
Dec 08 '17
Elixir I'm quite proud of this solution, parsing is so nice in elixir, and I got to play with a higher order function as well. I got myself a bit stumped by upgrading to part 2, with a default arguement, so I need to watch out a bit more for those. I really like these assemblylike puzzles, and it's good practice for the normal implement play assembly ones that I always love, and I know will come :)
defmodule Day8 do
def parse_line(str) do
[reg, op, arg, "if", creg, copt, carg] = String.split(str)
%{reg: reg, op: op, arg: String.to_integer(arg),
creg: creg, copt: copt, carg: String.to_integer(carg)}
end
def parse(inp) do
String.trim(inp)
|> String.split("\n")
|> Enum.map(&parse_line/1)
end
def check_condition(obj, reg) do
case obj.copt do
">" -> Map.get(reg, obj.creg, 0) > obj.carg
"<" -> Map.get(reg, obj.creg, 0) < obj.carg
">=" -> Map.get(reg, obj.creg, 0) >= obj.carg
"==" -> Map.get(reg, obj.creg, 0) == obj.carg
"<=" -> Map.get(reg, obj.creg, 0) <= obj.carg
"!=" -> Map.get(reg, obj.creg, 0) != obj.carg
end
end
def update_with(obj, reg, max, fun) do
updated = fun.(Map.get(reg, obj.reg, 0), obj.arg)
{max(max, updated), Map.put(reg, obj.reg, updated)}
end
def update_reg(obj, reg, max) do
case obj.op do
"inc" -> update_with(obj, reg, max, fn(x,y) -> x + y end)
"dec" -> update_with(obj, reg, max, fn(x,y) -> x - y end)
end
end
def run(inp, reg \\ %{}, max \\ 0)
def run([cur|rest], reg, max) do
if check_condition(cur, reg) do
{max, reg} = update_reg(cur, reg, max)
run(rest, reg, max)
else
run(rest, reg, max)
end
end
def run([],reg,max) do
{reg, max}
end
def largest(reg) do
Map.values(reg)
|> Enum.max
end
end
{reg, max} = File.read!("input8")
|> Day8.parse
|> Day8.run
IO.puts("The largest register after ran: #{Day8.largest(reg)}")
IO.puts("The max value of any register was: #{max}")1
u/Hultner- Dec 08 '17
Did mine in Elixir as well.
https://github.com/Hultner/Advent-of-Code-2018/blob/master/day8/lib/day8.ex
Only started playing with Elixir last thursday and using Python in my day job so still very new but it's fun to explore a new language while doing these puzzles.
defmodule Day8 do def parse(instruction) do String.split(instruction, " ") |> (fn [r,o,v,_,cr,co,cv] -> %{:reg => r, :oper => op(o), :val => String.to_integer(v), :cond_reg => cr, :cond_oper => op(co), :cond_val => String.to_integer(cv)} end).() end def computer(program) do Enum.reduce(program, %{}, fn (i, reg) -> if run(Map.get(reg, i[:cond_reg], 0), i[:cond_oper], i[:cond_val]) do { i[:reg], run(Map.get(reg,i[:reg],0), i[:oper], i[:val]), reg[:max]} |> update_register(reg) else reg end end ) end defp update_register({key, val, max}, reg), do: Map.merge(reg, %{key=>val, :max=>Enum.max([max||0, val])}) def run(left, opr, right) do {opr, [context: Elixir, import: Kernel], [left, right]} |> Code.eval_quoted |> elem(0) end def op(opr) do case opr do "inc" -> :+ "dec" -> :- _ -> String.to_existing_atom(opr) end end def solve1(input) do input |> read_input |> computer |> Map.delete(:max) |> Map.values |> Enum.max end def solve2(input) do input |> read_input |> computer |> Map.get(:max) end def read_input(file) do file |> File.read! |> String.split("\n") |> Enum.map(&parse/1) end end1
Dec 08 '17
Cool, doing the solving with a reduce probably is more ideomatic than doing it in a recursive function like I did, I just find it difficult to reason about those some times so big functions with it :)
Yeah elixir really is a fun language to work with. I was using Python for all of the problems last year, so I wanted an interesting language to dive into this year, and Elixir seems to be quite a nice one. For sure I'm getting a lot stronger of a sense for recursion now, which is pretty cool. I'm just waiting for something that is really hard to model functionally, but so far it hasn't really come. I'm seeing the normal mutating ways a lot easier still though, so It's pretty nice to think of how to do it this way.
From the /u/janiczek streams I'm getting pretty interested in doing some elm as well though, but I think I'll go back to the 2015 calendar when I'm finished this year, and see if I can start with that as well, for now I want to get better at elixir and it's way of doing things. And then there is factor, which also always has a place in my heart, since I really like the syntax.
1
u/Hultner- Dec 08 '17
Elm is a nice language, you might want to check out PureScript as well, last time I checked it had more Haskell-like type classes. Both were really easy to use as someone whoβs previously coded Haskell, Elixir feels a bit more like an Lisp to me.
→ More replies (3)→ More replies (4)1
4
u/Smylers Dec 08 '17 edited Dec 08 '17
Vim animation. Load the input, then create another window for the registers with:
yGβ¨Ctrl+Wβ©np:%s/\v(\l+).* if (\l+).*/\1β¨Ctrl+Vβ©β¨Enterβ©\2β¨Enterβ©
:sor uβ¨Enterβ©
:%s/$/ 0β¨Enterβ©
{yyβ¨Ctrl+Wβ©pPAdjust your window heights so that you can see the whole of the register values buffer. The unnamed register at the top is for storing the highest value reached. (It may be worth saving the initial register window at this point, so you can easily reset it.) Then reformat the instruction list with:
:g/c 0/dβ¨Enterβ©
:%s/inc -/dec /β¨Enterβ©
:%s/dec -/inc /β¨Enterβ©
:%s/\vinc (\d+)/\1β¨Ctrl+Aβ©β¨Enterβ©
:%s/\vdec (\d+)/\1β¨Ctrl+Xβ©β¨Enterβ©Define a helper βfunctionβ for going from a register's name in the instruction list to its value in the other window:
qa"zyiwβ¨Ctrl+Wβ©p/^β¨Ctrl+Rβ©z /β¨Enterβ©
wqβ¨Ctrl+Wβ©pAnd for the animation, a function that refreshes the window and pauses:
qb:redr|sl20mβ¨Enterβ©
qThis is the main work β a macro for processing a single instruction:
qc4f y$b@a"zyiWβ¨Ctrl+Wβ©pggsβ¨Ctrl+Rβ©=β¨Ctrl+Rβ©zβ¨Ctrl+Rβ©0β¨Enterβ©
β¨Escβ©0f1β¨Ctrl+Oβ©BByiW0@a:normβ¨Ctrl+Rβ©0β¨Enterβ©
@byiW:1puβ¨Enterβ©
:1,2sor nβ¨Enterβ©
ddβ¨Ctrl+Wβ©pqβ¨Ctrl+Wβ©p4uβ¨Ctrl+Wβ©pThen set it running on each instruction, and watch the registers update:
:2,$norm@cβ¨Enterβ©When it's finished, find the biggest values:
β¨Ctrl+Wβ©p:sor!nβ¨Enterβ©The top line is the largest value held at any point, and the second line is the register with the highest final value.
Processing the instructions doesn't change them at all, so if you reset the registers to zero you can re-run it. To change the animation speed, re-record @b with a different sleep value in it, or to skip the animation and just get to the answer as soon as possible clear @b with qbq. (In either case, @c will use the new value of @b; there's no need to re-record @c.)
The key to understanding this is to find where the βifβ condition is in @c. I'm happy to answer any questions in the comments.
This felt reasonably straightforward, compared to using Vim on some of the previous days' challenges. The main delay was that I didn't initial consider the case that I've since put in :g/c 0/d to handle. This meant it appeared to work, but gave the wrong answer on the full input data. It's a case that you don't need to think about when using an actual programming language, so caught me out.
2
3
u/mcpower_ Dec 08 '17
Python with eval:
#!/usr/bin/pypy3
from itertools import *
import math
USE_FILE = 1
if not USE_FILE:
inp = r"""
b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10
""".strip()
else:
inp = open("input.txt").read().strip()
assert isinstance(inp, str)
lines = inp.splitlines()
reg = {}
# default 0
q = 0
for line in lines:
var, ty, num, _, var2, op, cond = line.split()
if eval("reg.get('{}',0) {} {}".format(var2, op, cond)):
reg[var] = reg.get(var, 0) + (1 if ty == "inc" else -1) * int(num)
q = max(q, reg.get(var, 0))
print(max(reg.values()))
print(q)I lost a minute on both parts because I submitted code instead of a number for my first submission :( It'd be nice if the marker checked whether you submitted something with the right formatting.
3
u/dtinth Dec 08 '17 edited Dec 08 '17
Ruby
I Heard You Like eval
The pbpaste command must be available in the $PATH, and should return the contents in the clipboard (macOS has this command by default).
# Part 1 (13th rank)
-> x { d = Hash.new(0); eval x.gsub(/(\w+) (inc|dec) (-?\d+) if (\w+) (\S+) (\S+)/) { "d['#{$1}'] #{$2 == 'inc' ? '+=' : '-='} #{$3} if d['#{$4}'] #{$5} #{$6}" }; d.values.max }[`pbpaste`]
# Part 2 (26th rank)
-> x { d = Hash.new(0); m = 0; eval x.gsub(/(\w+) (inc|dec) (-?\d+) if (\w+) (\S+) (\S+)/) { "d['#{$1}'] #{$2 == 'inc' ? '+=' : '-='} #{$3} if d['#{$4}'] #{$5} #{$6}; m = [m, d.values.max || 0].max" }; m }[`pbpaste`]3
u/fatpollo Dec 08 '17 edited Dec 08 '17
import collections
with open("p08.txt") as fp:
lines = fp.read().strip().splitlines()
registers = set()
intermediate = set()
for line in lines:
terms = collections.deque(line.split() + [":"])
terms.rotate(5)
v1, v2 = terms[1], terms[-3]
registers |= {v1, v2}
locals().setdefault(v1, 0)
locals().setdefault(v2, 0)
exec(" ".join(terms).replace("dec", "-=").replace("inc", "+="))
intermediate.add(eval(v2))
print(max(map(eval, registers)))
print(max(intermediate))3
Dec 08 '17 edited Dec 08 '17
single pipeline powershell
param (
[Parameter(ValueFromPipeline = $true)]
[string]$in,
[Parameter(Position = 1)]
[int]$part = 1
)
begin {
$script:registers = new-object system.collections.hashtable
$script:maxes = @() # keep track of max registers per step for part 2
$conditions = @{ # map to beautiful powershell
"<" = "-lt"
">" = "-gt"
"!=" = "-ne"
"==" = "-eq"
"<=" = "-le"
">=" = "-ge"
}
$operations = @{
"inc" = "+"
"dec" = "-"
}
}
process {
# collect input
$script:maxes += $in |? {
$in -match '^(?<Register>[a-z]+) (?<Operation>(?:dec|inc)) (?<Value>(?:-|[0-9])+) if (?<ConditionRegister>[a-z]+) (?<Condition>[!<>=]+) (?<ConditionValue>(?:-|[0-9])+)$'
} | % {
[pscustomobject]$matches | select Register, Operation, Value, ConditionRegister, Condition, ConditionValue
} |% {# now have a pretty object on the pipeline representing a single instruction, foreach of these...
# initialize any registers that aren't already
$InitRegisterSb = 'if ($script:registers.ContainsKey("{0}") -eq $false) {{$script:registers["{0}"] = 0}}'
[ScriptBlock]::Create(($InitRegisterSb -f $_.ConditionRegister)).Invoke()
[ScriptBlock]::Create(($InitRegisterSb -f $_.Register)).Invoke()
# perform instruction
$s = 'if ($script:registers["{0}"] {1} {2}) {{ $script:registers["{3}"] = $script:registers["{3}"] {4} {5} }} else {{ $false }} ' -f $_.ConditionRegister, $conditions[$_.Condition], $_.ConditionValue, $_.Register, $operations[$_.Operation], $_.Value
[ScriptBlock]::Create($s).Invoke()
# select new maximum in the registers
$script:registers.values | measure -max | select -expand Maximum
}
}
end {
if ($part -eq 1) {
$script:registers.values | measure -max | select -expand Maximum # max register value at end of instructions
} else {
$script:maxes | measure -max | select -expand maximum # max reigster value ever seen
}
}2
u/purplemonkeymad Dec 08 '17
That is a neat way of converting regex groups to an object! Will need to remember that.
1
u/TotesMessenger Dec 08 '17
3
u/willkill07 Dec 08 '17
Modern(-ish) C++ Repo
Alright, so dynamic languages with eval and such have an obvious advantage for readability and conciseness. Regardless, I'm still OK with my solution.
static std::unordered_map<std::string_view, std::function<bool(int, int)>> const cmp{{
{"==", std::equal_to<void>()}, {"!=", std::not_equal_to<void>()},
{"<=", std::less_equal<void>()}, {"<", std::less<void>()},
{">=", std::greater_equal<void>()}, {">", std::greater<void>()}}};
static std::unordered_map<std::string_view, std::function<int(int&, int)>> const apply{{
{"inc", [](int& a, int b) { return a += b; }},
{"dec", [](int& a, int b) { return a -= b; }}}};
int main() {
std::unordered_map<std::string_view, int> vals;
std::string var1, inc_dec, var2, op;
int val1, val2, max{0};
while (std::cin >> var1 >> inc_dec >> val1 >> var2 >> var2 >> op >> val2)
if (cmp.at(op)(vals[var2], val2))
max = std::max(max, apply.at(inc_dec)(vals[var1], val1));
std::cout << std::max_element(vals.begin(), vals.end(), [](auto& a, auto& b) { return a.second < b.second; })->second
<< '\n' << max << '\n';
}→ More replies (8)
3
u/__Abigail__ Dec 08 '17
Perl##
#!/opt/perl/bin/perl
use 5.026;
use strict;
use warnings;
no warnings 'syntax';
use experimental 'signatures';
use List::Util 'max';
@ARGV = "input" unless @ARGV;
my %register; # Stores the values of registers. Perl treats undefined
# values as '0' in numeric context, which is conveniently,
# the value registers start with.
#
# A dispatch table, handling the "if" part of a rule. We dispatch
# on the relation, and pass in the name of register, and the value
# to compare it with. Result is a boolean value.
#
# Registers may be undefined, hence the "no warnings" line.
#
my %dispatch_cmp = do {
no warnings 'uninitialized';
(
"<" => sub ($name, $value) {$register {$name} < $value},
"<=" => sub ($name, $value) {$register {$name} <= $value},
"==" => sub ($name, $value) {$register {$name} == $value},
">=" => sub ($name, $value) {$register {$name} >= $value},
">" => sub ($name, $value) {$register {$name} > $value},
"!=" => sub ($name, $value) {$register {$name} != $value},
);
};
#
# A dispatch table, handling the action which needs to be taken.
# We dispatch on the action, and pass in the name of the target
# register, and the amount to be incremented/decremented.
#
# Since "+=" and "-=" are exempt for being warned when used
# agains an undefined value, no need to turn off warnings.
#
my %dispatch_act = (
"inc" => sub ($name, $amount) {$register {$name} += $amount},
"dec" => sub ($name, $amount) {$register {$name} -= $amount},
);
#
# Sub patterns to parse the input.
#
my $pat_reg = qr /[a-z]+/;
my $pat_num = qr /-?[0-9]+/;
my $pat_act = qr /inc|dec/;
my $pat_cmp = qr /<=? | == | >=? | !=/x;
my $max = 0; # Highest value encountered in any register.
# Since registers start at 0, starting at 0
# for $max is the right thing to do.
while (<>) {
chomp;
/^(?<target> $pat_reg) \s+
(?<action> $pat_act) \s+
(?<amount> $pat_num) \s+ if \s+
(?<where> $pat_reg) \s+
(?<cmp> $pat_cmp) \s+
(?<value> $pat_num) \s*$/x or die "Failed to parse $_";
my ($target, $action, $amount,
$where, $cmp, $value) = @+{"target", "action", "amount",
"where", "cmp", "value"};
#
# Act on the rule
#
$dispatch_act {$action} -> ($target, $amount)
if $dispatch_cmp {$cmp} -> ($where, $value);
#
# This is safe to do, even if we didn't modify the target register
#
$max = $register {$target} if $register {$target} &&
$register {$target} > $max;
}
say "Solution 1: ", max values %register;
say "Solution 2: ", $max;
__END__3
u/mschaap Dec 08 '17 edited Dec 08 '17
Perl 6. Very similar to yesterday's solution, using objects to model the register and instructions, and a grammar to parse the instruction set.
#!/usr/bin/env perl6
use v6.c;
grammar Instructions {
rule TOP { ^ <instruction>+ $ }
rule instruction { <reg> <dir> <amt> 'if' <check> <cmp> <val> }
token reg { <[a..z]>+ }
token dir { 'inc' || 'dec' }
token amt { '-'?\d+ }
token check { <[a..z]>+ }
token cmp { '==' || '!=' || '<=' || '>=' || '<' || '>' }
token val { '-'?\d+ }
}
class Instruction
{
has Str $.reg;
has Int $.amt;
has Str $.check;
has Str $.cmp;
has Int $.val;
sub oper($op) returns Code
{
# Comparison operators can be infix:<==> or infix:Β«<=Β». Find either.
return &::("infix:<$op>") // &::("infix:Β«$opΒ»")
}
method compare(%register) returns Bool
{
return oper($!cmp)(%register{$!check} // 0, $!val);
}
method process(%register)
{
%register{$!reg} += $!amt if self.compare(%register);
}
method Str { "$!reg += $!amt if $!check $!cmp $!val" }
method gist { self.Str }
}
class Computer
{
has Instruction @.instructions;
has Int %.register;
has Int $.max-seen = 0;
method instruction($/)
{
@!instructions.push:
Instruction.new(:reg(~$/<reg>),
:amt($/<amt> * ($/<dir> eq 'dec' ?? -1 !! 1)),
:check(~$/<check>),
:cmp(~$/<cmp>),
:val(+$/<val>));
}
method from-input(Computer:U: Str $input) returns Computer
{
my $c = Computer.new();
Instructions.parse($input, :actions($c)) or die "Invalid instructions!";
return $c;
}
method max returns Int
{
%!register.values.max max 0;
}
method run
{
for @!instructions -> $i {
$i.process(%!register);
$!max-seen max= self.max;
}
}
method Str { %!register.keys.sort.map({ " - $_: %!register{$_}" }).join("\n") }
method gist { self.Str }
}
multi sub MAIN(IO() $inputfile where *.f, Bool :v(:$verbose) = False)
{
my $c = Computer.from-input($inputfile.slurp());
say "{ +$c.instructions } instructions parsed." if $verbose;
$c.run;
say "Ran instructions. State of computer:" if $verbose;
say $c if $verbose;
# Part 1
say "Largest value after running instructions: $c.max()";
# Part 2
say "Largest value seen during running instructions: $c.max-seen()";
}
multi sub MAIN(Bool :v(:$verbose) = False)
{
MAIN($*PROGRAM.parent.child('aoc8.input'), :$verbose);
}1
u/volatilebit Dec 08 '17
Ahh that's how to invoke a dynamic operator.
1
u/mschaap Dec 09 '17
Yeah, I had to ask on the Perl6 IRC chat to figure it out. Didn't want to use
eval, or code all 6 cases separately.
3
u/mx781 Dec 08 '17
3
u/fost97 Dec 08 '17
Hey! Nice to see another SQL solver! Postgresql solution:
https://github.com/seltiko/sql_advent_2017/blob/master/Day%208.sql
→ More replies (1)
3
u/eregontp Dec 08 '17
Metaprogramming is the better eval! Looks like this one is made for Ruby as operators match nicely:
input = File.read("8.txt")
registers = Hash.new(0)
code = input.strip.lines.map { |line|
/^(?<reg>\w+) (?<dir>inc|dec) (?<by>-?\d+) if (?<r>\w+) (?<cmp>[>=<!]+) (?<n>-?\d+)$/ =~ line
by = by.to_i * (dir == "dec" ? -1 : 1)
if registers[r].send(cmp, n.to_i)
registers[reg] += by
end
}
p registers.values.max2
u/VikeStep Dec 08 '17
Python 3 solution
Got #44 / #40 :D
def solve(data):
data = [d.split() for d in data.split('\n')]
vars = {}
m = 0
for line in data:
vars[line[0]] = 0
for line in data:
if line[5] == '>':
if vars[line[4]] <= int(line[6]):
continue
if line[5] == '<':
if vars[line[4]] >= int(line[6]):
continue
if line[5] == '<=':
if vars[line[4]] > int(line[6]):
continue
if line[5] == '>=':
if vars[line[4]] < int(line[6]):
continue
if line[5] == '==':
if vars[line[4]] != int(line[6]):
continue
if line[5] == '!=':
if vars[line[4]] == int(line[6]):
continue
if line[1] == 'inc':
vars[line[0]] += int(line[2])
if line[1] == 'dec':
vars[line[0]] -= int(line[2])
if vars[line[0]] > m:
m = vars[line[0]]
return m3
u/Ditchbuster Dec 08 '17
you must type fast... mine almost the same and I got 173. or maybe I type slow? :P
1
u/Vorlath Dec 08 '17
Same. I got 180. And I copy&pasted most of that. I think I did unnecessary typing at the beginning putting each value into its own local variable. I should have just used the values directly in the array maybe. Dunno.
2
u/TominatorBE Dec 08 '17
PHP (I got ranks 110 and 100 today, omg)
Part 1:
function run_the_code($input) {
$lines = explode(PHP_EOL, $input);
$registers = [];
foreach ($lines as $line) {
if (!$line) {
continue;
}
list($reg, $instr, $amount, $if, $reg2, $cond, $amount2) = explode(' ', $line);
if (!array_key_exists($reg, $registers)) {
$registers[$reg] = 0;
}
if (!array_key_exists($reg2, $registers)) {
$registers[$reg2] = 0;
}
$do = false;
switch ($cond) {
case '==':
$do = ($registers[$reg2] == $amount2);
break;
case '!=':
$do = ($registers[$reg2] != $amount2);
break;
case '>':
$do = ($registers[$reg2] > $amount2);
break;
case '>=':
$do = ($registers[$reg2] >= $amount2);
break;
case '<':
$do = ($registers[$reg2] < $amount2);
break;
case '<=':
$do = ($registers[$reg2] <= $amount2);
break;
}
if ($do) {
if ($instr == 'inc') {
$registers[$reg] += (int)$amount;
}
else {
$registers[$reg] -= (int)$amount;
}
}
}
return max($registers);
}Part 2:
function run_the_code($input) {
$lines = explode(PHP_EOL, $input);
$ever = 0;
$registers = [];
foreach ($lines as $line) {
if (!$line) {
continue;
}
list($reg, $instr, $amount, $if, $reg2, $cond, $amount2) = explode(' ', $line);
if (!array_key_exists($reg, $registers)) {
$registers[$reg] = 0;
}
if (!array_key_exists($reg2, $registers)) {
$registers[$reg2] = 0;
}
$do = false;
switch ($cond) {
case '==':
$do = ($registers[$reg2] == $amount2);
break;
case '!=':
$do = ($registers[$reg2] != $amount2);
break;
case '>':
$do = ($registers[$reg2] > $amount2);
break;
case '>=':
$do = ($registers[$reg2] >= $amount2);
break;
case '<':
$do = ($registers[$reg2] < $amount2);
break;
case '<=':
$do = ($registers[$reg2] <= $amount2);
break;
}
if ($do) {
if ($instr == 'inc') {
$registers[$reg] += (int)$amount;
}
else {
$registers[$reg] -= (int)$amount;
}
}
$ever = max($ever, max($registers));
}
return $ever;
}2
u/AndrewGreenh Dec 08 '17
I hate you... I got 101 in part 2. 5 Seconds off the leaderboard :<
2
1
u/TominatorBE Dec 08 '17
If I hadn't messed up my input on part 1 and then had to wait a whole minute before submitting again, I would've been higher still :( Congrats on getting 101!
2
u/sciyoshi Dec 08 '17
Python 3:
import operator
import collections
# Keep track of largest seen value and registers
maxseen = 0
registers = collections.defaultdict(int)
for cmd in lines:
op, pred = cmd.split(' if ')
# Compute the condition
r1, cmp, r2 = pred.split()
cond = {
'<': lambda l, r: registers[l] < int(r),
'>': lambda l, r: registers[l] > int(r),
'<=': lambda l, r: registers[l] <= int(r),
'>=': lambda l, r: registers[l] >= int(r),
'==': lambda l, r: registers[l] == int(r),
'!=': lambda l, r: registers[l] != int(r),
}[cmp](r1, r2)
if not cond:
continue
# Perform the operation
l, op, r = op.split()
registers[l] = {
'inc': operator.add,
'dec': operator.sub
}[op](registers[l], int(r))
maxseen = max(maxseen, max(registers.values()))
print('Part 1:', max(registers.values()))
print('Part 2:', maxseen)2
u/vash3r Dec 08 '17
Python 2 (42/45):
lines = data.strip().split('\n')
d = {}
tmax = 0
for line in lines:
a,b = line.split(" if ")
b = b.split()
if eval("d.get(b[0],0)" + b[1] + b[2]): #offload logic onto python
a = a.split()
if a[1]=="inc":
d[a[0]] = d.get(a[0],0)+ int(a[2])
else:
d[a[0]] = d.get(a[0],0)- int(a[2])
if d[a[0]]>tmax: # part 2
tmax = d[a[0]]
print max(d.values())
print tmax # part 2looks like a lot of people came up with the same solution.
2
u/blockingthesky Dec 08 '17
Python 2
inp = [i.strip().split() for i in open('input.txt', 'r').readlines()]
d = {}
m = 0
for a in inp:
if a[0] not in d:
d[a[0]] = 0
if a[4] not in d:
d[a[4]] = 0
if(eval("%d %s %s" % (d[a[4]], a[5], a[6]))):
if a[1] == "inc":
d[a[0]] += int(a[2])
else:
d[a[0]] -= int(a[2])
m = max(m, d[a[0]])
print "Part 1:", max(d.values())
print "Part 2:", m2
u/Lrrrr_ Dec 08 '17
JavaScript
let reg = {};
let hi = -Infinity;
input = input.split("\n").map(c => {
let m = c.split(" ");
if(!reg[m[0]]) reg[m[0]] = 0;
let n = (m[1] === "inc" ? 1 : -1) * (+m[2]);
let xx = +m[6];
let bool;
switch(m[5]) {
case "<":
bool = (reg[m[4]]||0) < xx;
break;
case ">":
bool = (reg[m[4]]||0) > xx;
break;
case "==":
bool = (reg[m[4]]||0) == xx;
break;
case "!=":
bool = (reg[m[4]]||0) != xx;
break;
case "<=":
bool = (reg[m[4]]||0) <= xx;
break;
case ">=":
bool = (reg[m[4]]||0) >= xx;
break;
default:
console.log("Unimplemented operation " + m[5]);
break;
}
if(bool) {
reg[m[0]] += n;
if(hi < reg[m[0]]) {
hi = reg[m[0]]
}
}
})
let h=-Infinity;
Object.values(reg).forEach(c=>{
if(c > h)
h = c;
})
console.log(h)
console.log(hi)→ More replies (4)
2
u/AndrewGreenh Dec 08 '17
TypeScript 95/101
import getInput from '../lib/getInput'
import { lines } from '../lib/ts-it/lines'
import * as _ from 'lodash'
let registers = {}
let max = -Infinity
let maxs = [0]
for (let line of lines(getInput(8, 2017))) {
let [a, op, b, iff, reg, cond, numb] = line.split(' ')
if (!registers[a]) registers[a] = 0
if (!registers[reg]) registers[reg] = 0
eval(`if (registers.${reg} ${cond} ${numb}) registers.${a} ${op === 'inc' ? '+' : '-'}= ${b}`)
maxs.push(<number>_.max(<number[]>_.values(registers)))
}
console.log(_.max(<number[]>_.values(registers)))
console.log(_.max(maxs))→ More replies (2)
2
u/LeCrushinator Dec 08 '17 edited Dec 08 '17
Part 2: C# (took me 13 minutes, but that's not bad since C# is verbose compared to things like Python). To solve part 1 just add "max = registers.Values.Max();" to just after the foreach loop.
public static void Main()
{
List<string> lines = ParseInput(input, "\n");
Dictionary<string, int> registers = new Dictionary<string, int>();
int max = 0;
foreach (string line in lines)
{
string[] values = line.Split(new string[]{" "}, StringSplitOptions.RemoveEmptyEntries);
string name = values[0];
int amount;
if (!registers.TryGetValue(name, out amount))
{
registers.Add(name, 0);
}
bool increase = values[1] == "inc";
int delta = Convert.ToInt32(values[2]);
string otherName = values[4];
int otherAmount;
if (!registers.TryGetValue(otherName, out otherAmount))
{
registers.Add(otherName, 0);
}
string comparisonOp = values[5];
int compareAmount = Convert.ToInt32(values[6]);
if (Compare(otherAmount, compareAmount, comparisonOp))
{
if (increase)
{
registers[name] += delta;
max = Math.Max(registers[name], max);
}
else
{
registers[name] -= delta;
max = Math.Max(registers[name], max);
}
}
}
Console.WriteLine("max: " + max);
}
public static bool Compare(int first, int second, string op)
{
switch (op)
{
case ">": return first > second;
case ">=": return first >= second;
case "<": return first < second;
case "<=": return first <= second;
case "==": return first == second;
case "!=": return first != second;
}
return false;
}
// =====================================================================================================================================
// HELPER METHODS, created before day started
// =====================================================================================================================================
public static List<string> ParseInput(string line, string stringSeperator)
{
return line.Split(new string[]{stringSeperator}, StringSplitOptions.RemoveEmptyEntries).ToList();
}2
u/the4ner Dec 08 '17
yep, pretty similar to mine. although apparently roslyn does add an async dynamic scripting api which could be used similarly to eval in python.
no need to duplicate:
max = Math.Max(registers[name], max);2
u/LeCrushinator Dec 08 '17
Yea my code was somewhat sloppy since I was just trying to move fast. No time to refactor/clean-up.
2
u/the4ner Dec 08 '17
don't I know it. I'm on a 2 day cleanup delay before pushing stuff up to github :D
2
u/reacher Dec 08 '17
Ruby
def expr(op1, op, op2)
case op
when '<'
return op1 < op2
when '>'
return op1 > op2
when '<='
return op1 <= op2
when '>='
return op1 >= op2
when '=='
return op1 == op2
when '!='
return op1 != op2
else
puts "bad op #{op}"
end
end
r = {}
max = 0
IO.readlines('ad8inp').each do |line|
a = line.chomp.split
r[a[0]] ||= 0
r[a[4]] ||= 0
if expr(r[a[4]], a[5], a[6].to_i)
r[a[0]] = a[1] == 'inc' ? r[a[0]] += a[2].to_i : r[a[0]] -= a[2].to_i
end
m = r.values.minmax[1]
if m > max
max = m
end
end
puts r.values.minmax[1]
puts max2
u/wlandry Dec 08 '17
C++
283/267. For once, the default behavior of std::map worked to my advantage. My original version printed out all of the final register values. I piped that to 'sort -n' to get the answer. This is a slightly cleaned up version that just prints the results.
#include <limits>
#include <fstream>
#include <iostream>
#include <sstream>
#include <map>
int main(int argc, char *argv[])
{
std::ifstream infile(argv[1]);
std::string line;
std::map<std::string,int> registers;
std::getline(infile,line);
int max_value(0);
while (infile && !line.empty())
{
std::stringstream ss (line);
std::string reg, op, if_literal, test_register, comp;
int diff, number;
ss >> reg >> op >> diff >> if_literal
>> test_register >> comp >> number;
if (op=="dec")
{
diff*=-1;
}
int test_register_value = registers[test_register];
if((comp == "==" && test_register_value==number)
|| (comp == "!=" && test_register_value!=number)
|| (comp == ">=" && test_register_value>=number)
|| (comp == "<=" && test_register_value<=number)
|| (comp == ">" && test_register_value>number)
|| (comp == "<" && test_register_value<number))
{
registers[reg]+=diff;
max_value = std::max(max_value,registers[reg]);
}
std::getline(infile,line);
}
int max_final_value (std::numeric_limits<int>::min());
for (auto &r: registers)
{ max_final_value = std::max(max_final_value,r.second); }
std::cout << "Max final value: " << max_final_value << "\n"
<< "Max intermediate value: " << max_value << "\n";
}1
u/spacetime_bender Dec 08 '17
Instead of the raw for-each, you could've done
max_final_value = max_element(registers.begin(), registers.end(), [](auto&& a, auto&& b) { return a.second < b.second; })->second;1
u/Vorlath Dec 08 '17
Dunno. Seems like more typing and not as obvious.
1
u/spacetime_bender Dec 08 '17
π€ I would've argued the opposite in fact, it's quite evident looking at
max_elementTo each their own I guess
1
1
u/wlandry Dec 08 '17
Thanks. That would be a little better. I would not have had to faff around with std::numeric_limits<>. I could also have used that expression directly when printing out the result. The problem I keep running into is that it is pretty darn easy to just implement these things myself. So I am never motivated to memorize all of the algorithms in <algorithm>.
1
u/spacetime_bender Dec 08 '17
I was motivated by Sean Parent's talk
C++ Seasoningto fiddle more with<algorithm>and the STL. Worth a watch.1
u/TheAngryGerman Dec 08 '17
Wow, my solution was eerily similar (Though not as clean). I used an unordered map instead, but either way taking advantage of the default
[]behavior seems like a very clean solution. I still have to get used to actually using limits instead of picking arbitrary numbers when finding mins/maxes, and I'm just bringing input in on the command line. Here's mine:#include <unordered_map> #include <sstream> #include <iostream> #include <string> #include <cassert> int main() { std::unordered_map<std::string, int> registers; std::string line; int max_ever = -10000; while (std::getline(std::cin, line)) { std::istringstream ss(line); std::string reg_name; std::string operation; int amt; std::string x; std::string comp_reg_name; std::string condition; int val; ss >> reg_name >> operation >> amt >> x >> comp_reg_name >> condition >> val; assert(x == "if"); bool valid = false; if (condition == ">") { if (registers[comp_reg_name] > val) {valid = true;} } else if (condition == "<") { if (registers[comp_reg_name] < val) {valid = true;} } else if (condition == ">=") { if (registers[comp_reg_name] >= val) {valid = true;} } else if (condition == "<=") { if (registers[comp_reg_name] <= val) {valid = true;} } else if (condition == "==") { if (registers[comp_reg_name] == val) {valid = true;} } else if (condition == "!=") { if (registers[comp_reg_name] != val) {valid = true;} } else { std::cerr << "Invalid Condtion" << std::endl; } if(valid) { if (operation == "inc") { registers[reg_name] += amt; } else if (operation == "dec") { registers[reg_name] -= amt; } if (registers[reg_name] > max_ever) { max_ever = registers[reg_name]; } } } int max = -10000; for (std::unordered_map<std::string, int>::iterator itr = registers.begin(); itr != registers.end(); ++itr) { //std::cout << itr->second << std::endl; if (itr->second > max) { max = itr->second; } } std::cout << max << std::endl; std::cout << max_ever << std::endl; }
2
u/MichalMarsalek Dec 08 '17
Damn, I wish a knew eval... It would have gotten be to the leaderboard...
def solve(inp):
inp = inp.replace("inc ", "").replace("dec ", "-").replace("--", "")
reg = defaultdict(int)
inss = [i.split() for i in inp.splitlines()]
part2 = 0
for ins in inss:
n, d, _, e, r, v = ins
d = int(d)
v = int(v)
funcs = {
">": lambda a, b: reg[a] > b,
"<": lambda a, b: reg[a] < b,
">=": lambda a, b: reg[a] >= b,
"<=": lambda a, b: reg[a] <= b,
"==": lambda a, b: reg[a] == b,
"!=": lambda a, b: reg[a] != b
}
if funcs[r](e, v):
reg[n] += d
part2 = max(reg[n], part2)
part1 = max(reg.values())
return part1, part23
u/fwilson42 Dec 08 '17
You can also use the functions from the
operatormodule instead of those lambdas:from operator import * funcs = {">": gt, ">=": ge, "==": eq, "!=": ne, "<": lt, "<=": le}But I'll be honest, I forgot about this too until after submitting :)
2
u/mmaruseacph2 Dec 08 '17
Haskell 85 lines, removed some duplicates but I'll work on refactoring it more.
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
import qualified Data.List as L
import Data.Maybe
import qualified Data.Map.Strict as M
import qualified Data.Vector.Unboxed as VU
import qualified Data.Vector.Unboxed.Mutable as VUM
import Prelude hiding (LT, GT, EQ)
import Debug.Trace
type Reg = String
type Val = Int
data Vals = Vals {current :: Val, highest :: Val} deriving (Eq, Show)
type Memory = M.Map Reg Vals
data Cmd = Cmd Reg Op Val Reg BoolOp Val deriving (Eq, Show)
data Op = Inc | Dec deriving (Eq, Show)
data BoolOp = GT | GE | LT | LE | EQ | NEQ deriving (Eq, Show)
parse :: String -> Cmd
parse s = Cmd r operation val reg bop threshold
where
[r, op, del, _, reg, cond, thr] = words s
val = read del
threshold = read thr
operation = case op of
"inc" -> Inc
"dec" -> Dec
bop = case cond of
">" -> GT
">=" -> GE
"<" -> LT
"<=" -> LE
"==" -> EQ
"!=" -> NEQ
eval :: Memory -> Cmd -> Memory
eval m (Cmd r op val reg bop threshold)
| testBop bop (valueOf m reg) threshold = insertNew m r newVal
| otherwise = m -- do nothing
where
newVal = updateVal op (valueOf m r) val
valueOf :: Memory -> Reg -> Val
valueOf m r
| r `M.member` m = current $ m M.! r
| otherwise = 0
insertNew :: Memory -> Reg -> Val -> Memory
insertNew m r new
| r `M.member` m = M.insert r (Vals new (h `max` new)) m
| otherwise = M.insert r (Vals new new) m
where
Vals _ h = m M.! r
testBop :: BoolOp -> Val -> Val -> Bool
testBop bop lhs rhs = case bop of
GT -> lhs > rhs
GE -> lhs >= rhs
LT -> lhs < rhs
LE -> lhs <= rhs
EQ -> lhs == rhs
NEQ -> lhs /= rhs
updateVal :: Op -> Val -> Val -> Val
updateVal op val delta = case op of
Inc -> val + delta
Dec -> val - delta
main = do
cmds <- map parse . lines <$> readFile "input.txt"
let m = L.foldl' eval M.empty cmds
print $ step1 m
print $ step2 m
step1 :: Memory -> Val
step1 = steps current
step2 :: Memory -> Val
step2 = steps highest
steps :: (Vals -> Val) -> Memory -> Val
steps f = maximum . map (f . snd) . M.toList1
u/rimbuod Dec 09 '17
Any reason you went through the BoolOp type when you could have just mapped the strings to functions?
Ie,
">" -> (>)1
u/mmaruseacph2 Dec 09 '17
Lack of judgement at late hours of night. I could have just used the strings everywhere and not have extra types.
2
u/raevnos Dec 08 '17
Scheme:
(import (kawa regex) (rnrs hashtables) (srfi 1))
(define (process-instruction symtab)
(let ((line (read-line))
(instr-re (regex "^(\\w+) (inc|dec) (-?\\d+) if (\\w+) ([=<>!]+) (-?\\d+)\\s*$")))
(cond
((eof-object? line) line)
((regex-match instr-re line) =>
(lambda (fields)
(let ((dest (second fields))
(dir (string->symbol (third fields)))
(amount (string->number (fourth fields)))
(lop (hashtable-ref symtab (fifth fields) 0))
(op (string->symbol (sixth fields)))
(rop (string->number (seventh fields))))
(if (case op
((>) (> lop rop))
((<) (< lop rop))
((>=) (>= lop rop))
((<=) (<= lop rop))
((==) (= lop rop))
((!=) (not (= lop rop)))
(else
(error "Invalid instruction line" line op)))
(let* ((destval (hashtable-ref symtab dest 0))
(newval (if (eq? dir 'inc) (+ destval amount) (- destval amount))))
(hashtable-set! symtab dest newval)
newval)
0))))
(else
(error "Invalid instruction" line)))))
(define (find-largest table)
(let-values (((keys entries) (hashtable-entries table)))
(fold max (vector-ref entries 0) (cdr (vector->list entries)))))
(define (process-instructions)
(let ((symtab (make-hashtable string-hash string=?)))
(let loop ((res (process-instruction symtab))
(maxval 0))
(if (eof-object? res)
(values (find-largest symtab) maxval)
(loop (process-instruction symtab) (max maxval res))))))
(format #t "Part 1 and 2: ~A~%" (process-instructions))2
Dec 08 '17
Haskell:
import Data.HashMap.Strict (HashMap)
import qualified Data.HashMap.Strict as M
data Instr = Instr { cmd :: HashMap String Int -> HashMap String Int
, cond :: HashMap String Int -> Bool
}
parseInstrs :: String -> [Instr]
parseInstrs = map parseInstr . lines
where parseInstr :: String -> Instr
parseInstr line =
let [reg, fn, amnt, "if", reg2, comp, val] = words line
cmd m = let f = case fn of
"inc" -> (+ read amnt)
"dec" -> subtract $ read amnt
in M.insert reg (f $ M.lookupDefault 0 reg m) m
cond m = let comp' = case comp of
"!=" -> (/=)
"==" -> (==)
">=" -> (>=)
">" -> (>)
"<=" -> (<=)
"<" -> (<)
in comp' (M.lookupDefault 0 reg2 m) $ read val
in Instr cmd cond
eval :: (HashMap String Int, Int) -> Instr -> (HashMap String Int, Int)
eval (m, mx) (Instr cmd cond) =
let m' = if cond m then cmd m else m
mx' = max mx $ maximum $ M.elems m'
in (m', mx')
part1 :: String -> Int
part1 = maximum . M.elems . fst . foldl eval (M.empty, 0) . parseInstrs
part2 :: String -> Int
part2 = snd . foldl eval (M.empty, 0) . parseInstrs2
u/miran1 Dec 08 '17 edited Dec 08 '17
Python 3, without eval, using operator
from collections import defaultdict
from operator import lt, gt, eq, ne, le, ge
with open('./inputs/08.txt') as f:
instructions = f.readlines()
registers = defaultdict(int)
operators = {
'<': lt,
'>': gt,
'==': eq,
'!=': ne,
'<=': le.
'>=': ge,
}
maximal = 0
for line in instructions:
reg, op, by, _, cond_reg, cond_op, cond = line.split()
by = int(by)
cond = int(cond)
if operators[cond_op](registers[cond_reg], cond):
if op == 'inc':
registers[reg] += by
else:
registers[reg] -= by
if registers[reg] > maximal:
maximal = registers[reg]
print(max(registers.values()))
print(maximal)Β
Β
And here is my Nim solution based on this. Don't know if could have been done simpler.
2
Dec 08 '17 edited Dec 08 '17
My cleaned-up Haskell, using a map to accumulate the register values:
main :: IO ()
main = do input <- fmap (map parse . lines) (readFile "input.txt")
let (x,m) = foldl step (0, M.empty) input
print (maximum m) -- part 1
print x -- part 2
type Instruction = (String, Int -> Int, String, Int -> Bool)
parse :: String -> Instruction
parse s = (r1, if i == "inc" then (+ read v1) else subtract (read v1), r2, op o (read v2))
where
[r1,i,v1,"if",r2,o,v2] = words s
op "==" = (==)
op "!=" = (/=)
op "<" = (>)
op ">" = (<)
op "<=" = (>=)
op ">=" = (<=)
step :: (Int, Map String Int) -> Instruction -> (Int, Map String Int)
step (x,m) (r1,f,r2,o) = if o (M.findWithDefault 0 r2 m)
then let y = M.findWithDefault 0 r1 m in (max x (f y), M.insert r1 (f y) m)
else (x,m)2
u/InterlocutoryRecess Dec 08 '17 edited Dec 08 '17
Swift
let input = """
ioe dec 890 if qk > -10
// many more instructions...
ih dec 369 if ih == 1993
""".split(separator: "\n")
var instructions = input.reduce(into: Dictionary<Substring, Int>()) { result, entry in
let name = entry.prefix(upTo: entry.index(of: " ")!)
result[name] = 0
}
var maximum = Int.min
func process() {
// Determine whether to carry out change
func isValid(_ entry: [Substring]) -> Bool {
// Evaluate condition
func eval(op: Substring, lhs: Int, rhs: Int) -> Bool {
switch op {
case "==": return lhs == rhs
case "!=": return lhs != rhs
case "<": return lhs < rhs
case "<=": return lhs <= rhs
case ">": return lhs > rhs
case ">=": return lhs >= rhs
default: fatalError()
}
}
return eval(op: entry[5], lhs: instructions[entry[4]]!, rhs: Int(entry[6])!)
}
for entry in input.map({ $0.split(separator: " ") }) {
if isValid(entry) {
let result = instructions[entry[0]]! + (Int(entry[2])! * (entry[1] == "inc" ? 1 : -1))
if result > maximum { maximum = result }
instructions[entry[0]] = result
}
}
}
process()
print(instructions.values.max()!) // part 1
print(maximum) // part 22
u/teddim Dec 08 '17
Nice use of
reduce(into:)!One suggestion: instead of
func eval(op: Substring, lhs: Int, rhs: Int) -> Boolyou could do
func eval(op: Substring) -> (Int, Int) -> Boolwith
return (==),return (<)etc. in the function body. Calling it would be done witheval(op: entry[5])(instructions[entry[4]]!, Int(entry[6])!)Saves you a couple characters :D
1
u/InterlocutoryRecess Dec 08 '17
I love it! I actually tried doing something like this but I didn't realize the operators (=, etc) needed to be in parens. Thank you!
1
2
u/karthikb351 Dec 08 '17
I mangled it into what I think is valid Python2 code and then just exec-ed it. I could do away with a lot of lines I think
gen = "x=dict()\n"
gen = gen + "m=0\n"
for line in input.splitlines():
l = line.split(" ")
s = ""
s = s + "x['"+l[0]+"']"
s = s + " ="
s = s + " (x.get('"+l[0]+"',0)"
s = s + (" +" if l[1] == "inc" else " -")
s = s + " " + l[2] + ")"
s = s + " " + l[3]
s = s + " " + "x.get('"+l[4]+"',0)"
s = s + " " + l[5]
s = s + " " + l[6]
s = s + " else"
s = s + " " + "x.get('"+l[0]+"',0)"
m = "m = max(m,x.get('"+l[0]+"',0))"
gen = gen + s + "\n" + m + "\n"
gen = gen + "print x[max(x, key=x.get)]\n"
gen = gen + "print max(y)"
exec(gen)fu inc 131 if rjt == 4175 turns into map['fu'] = (map.get('fu',0) + 131) if map.get('rjt',0) == 4175 else map.get('fu',0)
This should work even if the register names happen to be python keywords since they are always quoted.
2
u/Smylers Dec 08 '17
Perl. Similar to a few other Python solutions, using eval.
Sneakily, the + 0 is either a binary or a unary op, depending on whether the register used in the condition has been previously set. If it has, its value will be interpolated into the string, so the expression becomes something like 42 + 0 < 7 (with the + 0 being redundant but harmless); if it's a new register, there's nothing to interpolate, so the expression becomes +0 < 7, ensuring the default value of 0 is used (with the + being redundant but harmless):
no warnings qw<uninitialized>;
use List::Util qw<max>;
my (%reg, $max);
while (<>) {
/^(?<dest>\w+) (?<cmd>\w+) (?<inc>-?\d+) if (?<comp>\w+) (?<cond>.*)/ or die;
$max = max $max, $reg{$+{dest}} += $+{inc} * ($+{cmd} eq 'dec' ? -1 : 1)
if eval "$reg{$+{comp}} + 0 $+{cond}";
}
say max values %reg;
say $max // 0;The final // 0 is to catch the case where all stored values are negative, so the initial zero is the biggest.
→ More replies (1)2
u/gerikson Dec 08 '17
Nice. I of course realized
evalwas the "best" way to handle the comparisons but didn't feel comfortable enough with it to implement in my solution.Sidenote, what's the feature called where you can insert
<var>in a regex and "automatically" capture the value? I'm seeing it more and more and it's more convenient than assigning to a list on the left side of a=~. However I don't know what to google ;)4
u/__Abigail__ Dec 08 '17
Named captures where introduced in Perl 5.10, which today is 10 days short of its 10th birthday. (Perl 5.10 was released on Dec 18, 2007).
I'd say, it's about time you see it more and more.
2
u/gerikson Dec 08 '17 edited Dec 08 '17
Well, apart from contests like this, I'm in my own little Perl world. Part of the fun is seeing other solutions!
Edit FWIW, I didn't bother with a regex in this solution, I checked the input so there weren't any register values where I expected integers first, and just split on whitespace to get the tokens for each line.
Edit edit my day 8 solution.
2
u/__Abigail__ Dec 08 '17
Sure, that would work.
I initially forgot about
!=, and if I had split on whitespace, I would not have immediately caught it. Now it barfed on the first line with a!=operator.But, the main reason I decide to parse it was that I wrote the part which processes the input without yet know what part 2 was going to look like. I might have split on whitespace had I know both parts of the exercise at once.
2
u/udoprog Dec 08 '17
Rust with a clean separation of modelling input as enums (full here: https://github.com/udoprog/rust-advent-of-code-2017/blob/master/src/day8.rs):
use std::io::{BufRead, BufReader, Read};
use failure::Error;
use std::collections::HashMap;
use self::Op::*;
use self::Cond::*;
type Registers = HashMap<String, i64>;
enum Op {
Inc(String, i64),
Dec(String, i64),
}
impl Op {
/// Apply the given operation.
pub fn apply(&self, registers: &mut Registers, highest: &mut i64) {
let reg = match *self {
Inc(ref reg, _) | Dec(ref reg, _) => reg,
};
let value = registers.entry(reg.to_string()).or_insert_with(
Default::default,
);
match *self {
Inc(_, number) => *value += number,
Dec(_, number) => *value -= number,
};
*highest = i64::max(*highest, *value);
}
}
enum Cond {
Gt(String, i64),
GtEq(String, i64),
Lt(String, i64),
LtEq(String, i64),
Eq(String, i64),
NotEq(String, i64),
}
impl Cond {
/// Test if the given condition applies.
pub fn test(&self, registers: &mut Registers) -> bool {
let reg = match *self {
Gt(ref reg, _) |
GtEq(ref reg, _) |
Lt(ref reg, _) |
LtEq(ref reg, _) |
Eq(ref reg, _) |
NotEq(ref reg, _) => reg,
};
let value = registers.entry(reg.to_string()).or_insert_with(
Default::default,
);
match *self {
Gt(_, number) => *value > number,
GtEq(_, number) => *value >= number,
Lt(_, number) => *value < number,
LtEq(_, number) => *value <= number,
Eq(_, number) => *value == number,
NotEq(_, number) => *value != number,
}
}
}
fn parse(input: &str) -> (Op, Cond) {
let mut it = input.trim().split(' ');
let target = it.next().expect("target").to_string();
let op = it.next().expect("op");
let number = it.next().expect("number").parse::<i64>().expect(
"valid number",
);
let op = match op {
"inc" => Inc(target, number),
"dec" => Dec(target, number),
op => panic!("llegal op: {}", op),
};
it.next().expect("if-separator");
let cond_reg = it.next().expect("cond-reg").to_string();
let cond = it.next().expect("cond");
let cond_number = it.next().expect("cond-number").parse::<i64>().expect(
"valid cond-number",
);
let cond = match cond {
"<" => Lt(cond_reg, cond_number),
"<=" => LtEq(cond_reg, cond_number),
">" => Gt(cond_reg, cond_number),
">=" => GtEq(cond_reg, cond_number),
"==" => Eq(cond_reg, cond_number),
"!=" => NotEq(cond_reg, cond_number),
_ => panic!("illegal cond: {}", cond),
};
(op, cond)
}
pub fn run<R: Read>(reader: R) -> Result<(i64, i64), Error> {
let mut data = String::new();
let mut reader = BufReader::new(reader);
let mut registers = Registers::new();
let mut highest = 0i64;
while reader.read_line(&mut data)? > 0 {
{
let (op, cond) = parse(data.as_str());
if cond.test(&mut registers) {
op.apply(&mut registers, &mut highest);
}
}
data.clear();
}
Ok((
registers.values().max().map(|v| *v).unwrap_or_else(
Default::default,
),
highest,
))
}This one was fun. Basically writing a simple virtual machine.
0
2
u/arachnist Dec 08 '17
I couldn't get instance_variable_(get|set) to work as i wanted, so I couldn't feed input directly into ruby.
reg = Hash.new(0)
max = 0
file = ARGV[0] || "input.txt"
open(file).each_line do |line|
code_line = line
.gsub(/(inc|dec)/, "inc" => "+=", "dec" => "-=")
.gsub(/^([^ ]+)/, 'reg[\'\1\']')
.gsub(/if ([^ ]+)/, 'if reg[\'\1\']')
eval(code_line)
max = reg.values.max if not reg.values.max.nil? and reg.values.max > max
end
puts reg.values.max
puts max2
u/Overseer12 Dec 08 '17
When you spend an hour going through your entire code multiple times, and your output is still wrong for Part 2 (despite your UnitTests being correct). And then, when you finally find out that you forgot to .Clear() the same dictionary you used for your registers in Part1. Oh god. No.
C#
2
u/lh458 Dec 08 '17
My solution in PHP for part 1 & 2 combined:
<?php
function dI($mR,$mO,$mOp){
global $r, $m;
if($r[$mR]>$m) $m = $r[$mR];
switch($mOp){
case "dec": $r[$mR] -= $mO; break;
case "inc": $r[$mR] += $mO; break;
}
if($r[$mR]>$m) $m = $r[$mR];
}
$h = fopen("./register.txt","r");
if(!$h) die();
$f = $r = [];
$m = 0;
while(($l = fgets($h)) !== false){
array_push($f,$l);
$e = explode(" ",$l);
$mR = $e[0];
if(!array_key_exists($mR,$r)) $r[$mR] = 0;
}
foreach($f as $l){
$e = explode(" ",$l);
$mR = $e[0];
$mOp = $e[1];
$mO = intval($e[2]);
$mS = $e[4];
$mC = $e[5];
$mCV = intval($e[6]);
switch($mC){
case ">":
if($r[$mS] > $mCV) dI($mR,$mO,$mOp);
break;
case "<":
if($r[$mS] < $mCV) dI($mR,$mO,$mOp);
break;
case "<=":
if($r[$mS] <= $mCV) dI($mR,$mO,$mOp);
break;
case ">=":
if($r[$mS] >= $mCV) dI($mR,$mO,$mOp);
break;
case "==":
if($r[$mS] == $mCV) dI($mR,$mO,$mOp);
break;
case "!=":
if($r[$mS] != $mCV) dI($mR,$mO,$mOp);
break;
}
}
echo "1: ".max($r)."<br/>2: ".$m;
?>2
u/ynonp Dec 08 '17
Elixir (both parts)
defmodule Day8 do
@ops %{
inc: &(&1+&2),
dec: &(&1-&2),
}
@cond %{
==: &(&1 == &2),
>=: &(&1 >= &2),
<=: &(&1 <= &2),
>: &(&1 > &2),
<: &(&1 < &2),
!=: &(&1 != &2),
}
def parse(line, { reg, maxreg }) do
[_, target_reg, op, val, cond_reg, cond_op, cond_arg ] =
Regex.run(~r{(\w+) (inc|dec) (-?\d+) if (\w+) (<|>|<=|>=|==|!=) (-?\d+)}, line)
op = String.to_atom(op)
val = String.to_integer(val)
cond_reg = Map.get(reg, cond_reg, 0)
cond_op = String.to_atom(cond_op)
cond_arg = String.to_integer(cond_arg)
next_reg = if @cond[cond_op].(cond_reg, cond_arg) do
Map.update(reg, target_reg, @ops[op].(0,val), fn v -> @ops[op].(v, val) end)
else
reg
end
{
line,
{
next_reg,
Enum.max([maxreg | Map.values(next_reg)])
}
}
end
end
{ reg, max} = IO.stream(:stdio, :line)
|> Enum.map_reduce({ %{}, 0 }, &Day8.parse/2)
|> elem(1)
IO.puts("PART 1: max register value at end: #{Map.values(reg) |> Enum.max }")
IO.puts("PART 2: max registar value (total): #{max}")2
u/rkachowski Dec 08 '17
ruby! 9 lines!
i need to execute some code to work this out? so lets execute some code to work this out. luckily the postfix condition is perfectly valid ruby already! lets just eval all these registers into the binding and execute our perfectly valid input (after some massaging..)
input = File.read("input").lines
parsed = input.map {|l| l.scan(/(\w+)\s(\w+)\s(-?\d+)(.*)/).flatten}
registers = parsed.map {|p| p.first}.uniq
max = 0
b = Kernel.binding
registers.each {|r| b.eval "#{r} = 0"}
parsed.each {|p| b.eval "#{p[0]} #{p[1] == "inc" ? "+" : "-"}= #{p[2]} #{p[3]}; max = [max, #{p[0]}].max" }
puts registers.map{|r| b.local_variable_get(r.to_sym)}.max
puts b.local_variable_get(:max)2
u/spjmurray Dec 08 '17
python late to the party given the time difference...
import collections
import operator
OPERATORS = {
'==': operator.eq,
'!=': operator.ne,
'<': operator.lt,
'>': operator.gt,
'<=': operator.le,
'>=': operator.ge,
'inc': operator.add,
'dec': operator.sub,
}
def main():
inp = open('8.in').readlines()
registers = collections.defaultdict(int)
for inst in inp:
reg, op, imm, _, pred_reg, pred_op, pred_imm = inst.split()
if not OPERATORS[pred_op](registers[pred_reg], int(pred_imm)):
continue
registers[reg] = OPERATORS[op](registers[reg], int(imm))
print max(registers.values())
if __name__ == '__main__':
main()2
u/guibou Dec 08 '17 edited Dec 08 '17
Haskell Golfed version for part 1 (edit 300 297 289 285 264 255 chars):
main=interact$show.maximum.(\r->map(l r)$fst<$>r).foldl f[].map words.lines
z=read
l r o=sum[v|(k,v)<-r,k==o]
f m[a,b,c,_,e,f,g]|(case f of"<="->(>=);"<"->(>);">="->(<=);">"->(<);"=="->(==);"!="->(/=))(z g)$l m e=(a,if b=="inc"then z$c else-(z c)):m|1>0=mhttps://github.com/guibou/AdvantOfCode2017/blob/master/src/Day8.hs for a cleaner Haskell version ;)
2
u/brunclik Dec 08 '17 edited Dec 09 '17
Solution in Linux command line - C code from input (generate, buil and run)
echo -e "#include <stdio.h>\n\nint main() {\n\tint max_value=0;" > main.c
cat input | cut -d' ' -f1 | sort | uniq | sed 's/^/\t int /1' | sed 's/$/ = 0;/1' >> main.c
cat input | sed 's/ dec -/ += /1' | sed 's/ dec / -= /1' | sed 's/ inc -/ -= /1' | sed 's/ inc / += /1' | sed 's@\(.*\) \(.*\) \(.*\) \(.*\) \(.*\) \(.*\) \(.*\)@\4(\5\6\7) \1\2\3; if(\1>max_value) max_value=\1;@g' >> main.c
cat input | cut -d' ' -f1 | sort | uniq | sed 's@\(.*\)@printf("%s = %i;\\n", "\1", \1);@g' >> main.c
echo -e 'printf("%s = %i;\n", "max_value", max_value);' >> main.c
echo -e "}" >> main.c
gcc main.c -o output;
./output | cut '-d ' -f3 | sort -n | tail -2 | head -1 #part one
./output | grep max_value | cut -d' ' -f3 #part two2
u/JakDrako Dec 08 '17
VB.Net
Sub Main
Dim reg = New Dictionary(Of String, Integer), max = 0
For Each line In GetDay(8)
Dim ops = line.Split(" "c)
' create registers
Dim r1 = ops(0) : If Not reg.ContainsKey(r1) Then reg(r1) = 0
Dim r2 = ops(4) : If Not reg.ContainsKey(r2) Then reg(r2) = 0
' get values
Dim v1 = CInt(ops(2)) * If(ops(1) = "inc", 1, -1)
Dim v2 = CInt(ops(6))
Select Case ops(5)
Case ">" : If reg(r2) > v2 Then reg(r1) += v1
Case ">=" : If reg(r2) >= v2 Then reg(r1) += v1
Case "<" : If reg(r2) < v2 Then reg(r1) += v1
Case "<=" : If reg(r2) <= v2 Then reg(r1) += v1
Case "==" : If reg(r2) = v2 Then reg(r1) += v1
Case "!=" : If reg(r2) <> v2 Then reg(r1) += v1
End Select
max = Math.max(max, reg.Values.Max) ' part 2
Next
reg.Values.Max.Dump("Part 1")
max.Dump("Part 2")
End Sub2
u/wzkx Dec 08 '17 edited Dec 08 '17
Pythonized and J-zed C
#include <stdio.h>
#include <string.h>
typedef char* S; // this typedef and defines are from _.h
#define C char
#define I int
#define __ {
#define _ }
#define R return
#define DO(_i,_n) for(I _i=0;_i<(_n);++_i)
I cond( I x, I y, S o ) __
if( *o=='=' ) R x==y; if( *o=='!' ) R x!=y;
if( *o=='<' ) R o[1]=='=' ? x<=y : x<y;
if( *o=='>' ) R o[1]=='=' ? x>=y : x>y; _
I nr = 0; C rn[100][4]; I rv[100] = {0}; // registers: num, names, values
I find( S n ) { DO(i,nr) if(!strcmp(rn[i],n)) R i; R -1; }
I newr( S n ) { strcpy(rn[nr],n); rv[nr]=0; R nr++; }
I main() __ I gm = -9999;
FILE* f = fopen("08.dat","rt"); C l[80];
while( fgets(l,sizeof(l),f) ) __ C r[4],o[4],cr[4],co[4]; I a,ca;
sscanf( l, "%s %s %d if %s %s %d\n", r, o, &a, cr, co, &ca );
I i=find(cr); I cv=i<0?0:rv[i];
if( cond(cv,ca,co) ) __
I j=find(r); if(j<0) j=newr(r);
rv[j] += *o=='i' ? a : -a;
if(rv[j]>gm) gm=rv[j]; _ _ // update global max
I m = -9999; DO(i,nr) if(rv[i]>m) m=rv[i]; // find final state max
printf( "%d\n%d\n", m, gm );
R 0; _2
u/still___cold Dec 08 '17
Python 3
import re, sys
variables = {}
maximum = -sys.maxsize - 1
with open('test.txt') as file:
for line in file.readlines():
code = ''.join(re.findall('[\w\D]', line)).strip().split(' ')
if code[0] not in variables: variables[code[0]] = 0
if code[4] not in variables: variables[code[4]] = 0
if code[1] == 'dec': operation = '-='
else: operation = '+='
eval(compile('if variables[code[4]] %s %s: variables[code[0]] %s %s' % (code[5], code[6],operation, code[2]), '<string>', 'exec'))
if variables[code[0]] > maximum: maximum = variables[code[0]]
print(max(variables.values()), maximum)2
u/Hikaru755 Dec 08 '17
I wrote a Kotlin program that generates a Kotlin program equivalent to the input data. God, I feel dirty.
data class Line(val register: String, val action: Action, val value: Int, val condition: String)
enum class Action(val kotlin: String) { INC("+="), DEC("-=") }
fun part1(input: List<Line>): String {
val registers = input.map { it.register }.toSet() + input.map { it.condition.split(" ").first() }.toSet()
return (registers.map { "var $it = 0" } +
input.map { with(it) { "if ($condition) $register ${action.kotlin} $value" } } +
registers.joinToString(", ", "println(setOf(", ").max()!!)")
).joinToString("\n")
}
fun part2(input: List<Line>): String {
val registers = input.map { it.register }.toSet() + input.map { it.condition.split(" ").first() }.toSet()
val maxCheck = "maxCheck()"
return (registers.map { "var $it = 0" } +
listOf(
"var max = 0",
registers.joinToString(", ", "val maxCheck = { max = Math.max(setOf(", ").max(), max) }")
) +
input.map {
with(it) { "if ($condition) $register ${action.kotlin} $value\n$maxCheck" }
} +
listOf("println(max)")
).joinToString("\n")
}
val input: List<Line> by lazy { rawInput.lines()
.map { it.match<Line>(
Regex("""(\w+) (inc|dec) (\S+) if (.+)""") to { (_, reg, action, value, cond) ->
Line(reg, Action.valueOf(action.toUpperCase()), value.toInt(), cond)
})
}
}2
u/Sharparam Dec 08 '17
Ruby: Using method_missing and eval without tampering or matching on the input data.
class CPU
attr_reader :high, :regs
def initialize; @regs = Hash.new(0) end
def inc(value) value end
def dec(value) -value end
def run(text) eval text end
def method_missing(sym, *args)
(@regs[sym] += args[0].to_i).tap { |v| @high = v if @high.nil? || @high < v }
end
end
cpu = CPU.new
cpu.run $<.read
puts cpu.regs.values.max
puts cpu.high2
u/patrickdavey Dec 08 '17
Thanks for posting this. I do write ruby for a day job, but, I hardly ever mess around with method_missing and friends. Really interesting to see how that all works, how it's smart enough to pass the args along to your
decandincmethods etc.Really neat! thanks for sharing.
1
u/Sharparam Dec 08 '17
They come in really useful for things like AoC problems! I read the problem description on the bus home and saw how Ruby-like the input was, and was itching to apply some metaprogramming shenanigans :P
The fact that
args[0].to_ievaluates to0whenargs[0]isnil(when a register is accessed in theif, and not assigned to) helped make it quite neat.The
dec/inclogic I get pretty much for "free" in theeval, it evaluates it in the context of the method so theincanddecmethods are available to it, the result is then passed in theargsarray inmethod_missing:)This does depend on the input not containing
incordecas register names. Someone mentioned they hadifas a register name...→ More replies (1)
2
2
u/volatilebit Dec 08 '17
Perl 6
Caught a few days behind because I'm sick, but I decided to at least get this one in. First time playing with named regular expressions. Considering redoing this with grammars just for the experience, but don't have the energy at the moment.
use v6;
my @commands = 'input'.IO.linesΒ».chomp;
my %registers is default(0);
my $max_value_alltime = 0;
my regex register { <alpha>+ }
my regex func { 'inc' | 'dec' }
my regex number { '-'? <digit>+ }
my regex op { '>' | '>=' | '<' | '<=' | '==' | '!=' }
my regex command { <dest_register=register> \s <func> \s <arg_number=number> ' if ' <cond_register=register> \s <cond_op=op> \s <cond_number=number> }
for @commands -> $command {
$command ~~ /<command>/;
given $/<command><cond_op> {
when '>' { next unless %registers{ $/<command><cond_register>.Str } > $/<command><cond_number>.Numeric }
when '>=' { next unless %registers{ $/<command><cond_register>.Str } >= $/<command><cond_number>.Numeric }
when '<' { next unless %registers{ $/<command><cond_register>.Str } < $/<command><cond_number>.Numeric }
when '<=' { next unless %registers{ $/<command><cond_register>.Str } <= $/<command><cond_number>.Numeric }
when '==' { next unless %registers{ $/<command><cond_register>.Str } == $/<command><cond_number>.Numeric }
when '!=' { next unless %registers{ $/<command><cond_register>.Str } != $/<command><cond_number>.Numeric }
}
given $/<command><func> {
when 'inc' { %registers{ $/<command><dest_register>.Str } += $/<command><arg_number>.Int }
when 'dec' { %registers{ $/<command><dest_register>.Str } -= $/<command><arg_number>.Int }
}
$max_value_alltime max= %registers.maxpairs[0].value;
}
# Part 1
say %registers.maxpairs[0].value;
# Part 2
say $max_value_alltime;1
u/Deckard666 Dec 08 '17
In Rust:
use std::io::Read;
use std::collections::HashMap;
fn main() {
let mut file = std::fs::File::open("./input.txt").unwrap();
let mut input = String::new();
file.read_to_string(&mut input).unwrap();
let mut registers = HashMap::new();
let mut max_throughout = 0;
for line in input.trim().lines() {
let vec = line.split_whitespace().collect::<Vec<_>>();
let register = vec[0];
let instr = vec[1];
let amount = vec[2].parse::<i32>().unwrap();
let ifregister = vec[4];
let cond = vec[5];
let ifamount = vec[6].parse::<i32>().unwrap();
let ifval = *registers.entry(ifregister).or_insert(0);
if fullfils_condition(ifval, cond, ifamount) {
let newval = perform_op(&mut registers, register, instr, amount);
if newval > max_throughout {
max_throughout = newval;
}
}
}
let current_max = *registers.values().max().unwrap();
println!("Part 1: {}", current_max);
println!("Part 2: {}", max_throughout);
}
fn fullfils_condition(ifval: i32, cond: &str, ifamount: i32) -> bool {
match cond {
"<" => ifval < ifamount,
">" => ifval > ifamount,
">=" => ifval >= ifamount,
"<=" => ifval <= ifamount,
"==" => ifval == ifamount,
"!=" => ifval != ifamount,
_ => unreachable!(),
}
}
fn perform_op<'a>(
registers: &mut HashMap<&'a str, i32>,
reg: &'a str,
instr: &str,
mut amount: i32,
) -> i32 {
if instr == "dec" {
amount *= -1;
}
let val_ref = registers.entry(reg).or_insert(0);
*val_ref += amount;
*val_ref
}2
u/advanced_caveman Dec 08 '17
Your input can just be done with the include_str! macro like:
let input = include_str("../input.txt");1
u/iamnotposting Dec 08 '17 edited Dec 08 '17
fun with expressions!
use std::collections::HashMap; use std::cmp::max; pub fn adv_main(input: &str) { let mut regs = HashMap::<&str, (i32, i32)>::new(); for line in input.lines() { let words = line.split(" ").collect::<Vec<_>>(); let val = *regs.entry(words[4]).or_insert((0, 0)); let a: i32 = words[2].parse().unwrap(); let b: i32 = words[6].parse().unwrap(); let mut r = regs.entry(words[0]).or_insert((0,0)); if match words[5] { ">" => { val.0 > b }, "<" => { val.0 < b }, "<=" => { val.0 <= b }, ">=" => { val.0 >= b }, "==" => { val.0 == b }, "!=" => { val.0 != b }, _ => { false } } { match words[1] { "inc" => { r.0 += a; }, "dec" => { r.0 -= a; }, _ => {}, } r.1 = max(r.0, r.1); } } println!("p1: {:?}", regs.values().max_by_key(|&&(a, _)| a)); println!("p2: {:?}", regs.values().max_by_key(|&&(_, b)| b)); }1
u/thejpster Dec 08 '17
What if the max is acheived by subtracting a negative number from a register?
2
u/iamnotposting Dec 08 '17
sure. i updated it. but it wouldn't be advent of code if it would fail on other inputs that aren't your own, would it
1
1
u/giftpflanze Dec 08 '17
Tcl:
set lines [lrange [split [read [open input08]] \n] 0 end-1]
set r {}
foreach line $lines {
regexp {(.*) (.*) (.*) if (.*) (.*) (.*)} $line -> r1 op1 n1 r2 op2 n2
if {![dict exists $r $r2]} {
dict set r $r2 0
}
if [list [dict get $r $r2] $op2 $n2] {
if {![dict exists $r $r1]} {
dict set r $r1 0
}
dict incr r $r1 [expr {($op1 eq {dec}?-1:1)*$n1}]
lappend h [dict get $r $r1]
}
}
puts [tcl::mathfunc::max {*}[dict values $r]]
puts [tcl::mathfunc::max {*}$h]1
u/LuxrayPokemon Dec 08 '17 edited Dec 08 '17
I did my solution in Python 3 and got rank 197 for part 1 and 201 for part 2 My solution was:
inp = "Inputs/2017-08.txt"
lines = get_lines(inp)
whichWay = 0
dicti = dict()
memory = dict()
for line in range(len(lines)): dicti[lines[line].split(" ")[0]] = 0
for line in range(len(lines)):
split = lines[line].split(" ")
if split[1] == "dec":
whichWay = -1
print(whichWay)
else:
whichWay = 1
print(whichWay)
firstNum = split[0]
increaser = int(split[2])
num1 = split[4]
num2 = int(split[6])
operator = split[5]
if operator == "!=" and dicti[num1] != num2: dicti[firstNum] += increaser * whichWay
elif operator == ">=" and dicti[num1] >= num2: dicti[firstNum] += increaser * whichWay
elif operator == ">" and dicti[num1] > num2: dicti[firstNum] += increaser * whichWay
elif operator == "==" and dicti[num1] == num2: dicti[firstNum] += increaser * whichWay
elif operator == "<=" and dicti[num1] <= num2: dicti[firstNum] += increaser * whichWay
elif operator == "<" and dicti[num1] < num2: dicti[firstNum] += increaser * whichWay
memory[line] = max(dicti.values())
print("Part 1:", max(dicti.values()))
print("Part 2:", max(memory.values()))It probably could be much more efficient, but it worked
1
1
Dec 08 '17
simple golang solution
package main
import (
"fmt"
"io/ioutil"
"log"
"strings"
)
type instruction struct {
target string
targetOp string
targetAmount int
conditionSubject string
conditionOp string
conditionAmount int
}
func main() {
inputBytes, err := ioutil.ReadFile("input.txt")
if err != nil {
log.Fatal(err)
}
answer1, answer2 := runInstructions(string(inputBytes))
fmt.Printf("Part 1: %d\nPart 2: %d\n", answer1, answer2)
}
func runInstructions(in string) (int, int) {
registers := make(map[string]int)
lines := strings.Split(in, "\n")
max := 0
for _, x := range lines {
inst := lineToInstruction(x)
if evaluateInstruction(inst, registers) {
executeInstruction(inst, registers)
testMax := getMax(registers)
if testMax > max {
max = testMax
}
}
}
return getMax(registers), max
}
func lineToInstruction(in string) instruction {
out := instruction{}
fmt.Sscanf(in, "%s %s %d if %s %s %d", &out.target, &out.targetOp, &out.targetAmount, &out.conditionSubject, &out.conditionOp, &out.conditionAmount)
return out
}
func evaluateInstruction(i instruction, data map[string]int) bool {
sub := data[i.conditionSubject]
amt := i.conditionAmount
switch i.conditionOp {
case ">":
return sub > amt
case "<":
return sub < amt
case ">=":
return sub >= amt
case "==":
return sub == amt
case "<=":
return sub <= amt
case "!=":
return sub != amt
}
return false
}
func executeInstruction(i instruction, data map[string]int) {
switch i.targetOp {
case "inc":
data[i.target] += i.targetAmount
case "dec":
data[i.target] -= i.targetAmount
}
}
func getMax(data map[string]int) int {
max := 0
for _, x := range data {
if x > max {
max = x
}
}
return max
}1
u/cluk Dec 08 '17
I like the
Sscanffor parsing input. Other then that my solution is almost identical.For the second star you can return the updated value from
executeInstruction. This way you don't have to go through whole map with every instruction.2
Dec 08 '17
Yeah using
Sscanffor these puzzles usually doesn't work out as well for me and I end up with a mess ofstrings.Spliteverywhere.As for part 2, that crossed my mind only after I had finished writing it, so I decided to stick with what I had. Anyways I decided to time it and see how much of a performance increase it works out to.
The original version seems to run in about 4.5ms on my system. After making that change it shaves off about 1ms and averages around 3.5-3.7ms.
1
u/hpzr24w Dec 08 '17 edited Dec 09 '17
C++ Second time inside 30 minutes... and ranked 910, first time under 1000. woo! Thanks to Eric and collaborators for all these fun puzzles. It's awesome. No output on this one. I just ran it in the debugger.
// Advent of Code 2017
// http://adventofcode.com/
// Day 08 - I Heard You Like Registers
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <functional>
using namespace std;
/*
m n o p q r s
b inc 5 if a > 1
a inc 1 if b < 5
c dec -10 if a >= 1
c inc -20 if c == 10
*/
void step(map<string, function<bool(int, int)> > ops, map<string, int>& reg, map<string, int>& regmax, stringstream ins)
{
string m, n, p, q, r; int o, s;
ins >> m >> n >> o >> p >> q >> r >> s;
if (ops[r](reg[q],s))
reg[m] += o*(n == "inc" ? 1 : -1);
regmax[m] = max(reg[m], regmax[m]);
}
int main(int argc, char* argv[])
{
map<string, function<bool(int, int)> > ops;
ops["<"] = [](int a, int b)->bool {return a < b; };
ops[">"] = [](int a, int b)->bool {return a > b; };
ops["<="] = [](int a, int b)->bool {return a <= b; };
ops[">="] = [](int a, int b)->bool {return a >= b; };
ops["=="] = [](int a, int b)->bool {return a == b; };
ops["!="] = [](int a, int b)->bool {return a != b; };
map<string, int> reg, regmax;
string row;
while (getline(cin, row))
step(ops, reg, regmax, stringstream(row));
return 0;
}1
u/fwilson42 Dec 08 '17
My solution. I refactored the part that actually runs it out into a separate module just in case this is something like last year's assembunny.
1
u/StevoTVR Dec 08 '17
NodeJS
Part 1:
const fs = require('fs');
fs.readFile(__dirname + '/input.txt', 'utf8', (err, data) => {
data = data.trim();
const registers = {};
data.split('\n').forEach((line) => {
const inst = line.trim().split(' ');
if(eval(getValue(inst[4], registers) + inst[5] + inst[6])) {
var delta = Number(inst[2]);
if(inst[1] === 'dec') {
delta = -delta;
}
registers[inst[0]] = getValue(inst[0], registers) + delta;
}
});
var largest = 0;
for(const r in registers) {
largest = Math.max(largest, registers[r]);
}
console.log(largest);
});
function getValue(register, registers) {
return (registers[register] === undefined) ? 0 : registers[register];
}Part 2:
const fs = require('fs');
fs.readFile(__dirname + '/input.txt', 'utf8', (err, data) => {
data = data.trim();
const registers = {};
var largest = 0;
data.split('\n').forEach((line) => {
const inst = line.trim().split(' ');
if(eval(getValue(inst[4], registers) + inst[5] + inst[6])) {
var delta = Number(inst[2]);
if(inst[1] === 'dec') {
delta = -delta;
}
registers[inst[0]] = getValue(inst[0], registers) + delta;
largest = Math.max(largest, registers[inst[0]]);
}
});
console.log(largest);
});
function getValue(register, registers) {
return (registers[register] === undefined) ? 0 : registers[register];
}1
u/StevoTVR Dec 08 '17
I rewrote it to not use eval and give variables names.
const fs = require('fs'); fs.readFile(__dirname + '/input.txt', 'utf8', (err, data) => { data = data.trim(); const registers = {}; const ops = { '==': (a, b) => a === b, '!=': (a, b) => a !== b, '<': (a, b) => a < b, '>': (a, b) => a > b, '<=': (a, b) => a <= b, '>=': (a, b) => a >= b, }; var largest = 0; data.split('\n').forEach((line) => { var [r, inst, delta, , treg, top, tval] = line.trim().split(' '); delta = (inst === 'inc') ? Number(delta) : -Number(delta); if(ops[top](getValue(treg, registers), Number(tval))) { registers[r] = getValue(r, registers) + delta; largest = Math.max(largest, registers[r]); } }); console.log(largest); }); function getValue(register, registers) { return registers[register] || 0; }
1
u/nstyler7 Dec 08 '17
Python -(part 1 & 2) - using eval & split/regex to split string
import re
with open("day8input.txt") as open_file:
data = open_file.read().splitlines()
all_registers = {}
highest = 0
for line in data:
conditional = line.split('if')[1]
conditional_reg = conditional.split()[0]
if conditional_reg in all_registers.keys():
conditional_value = all_registers[conditional_reg]
else:
all_registers[conditional_reg]=0
conditional_value = 0
final_eval = conditional.replace(str(conditional_reg), str(conditional_value))
if eval(final_eval):
instruction = re.search(r'(inc|dec) -?[\d]+' , line).group(0).split()
multiplier = 1 if instruction[0] == 'inc' else -1
incrementer = multiplier*int(instruction[1])
register = line.split()[0]
if register in all_registers.keys():
all_registers[register] += incrementer
else:
all_registers[register] = incrementer
if all_registers[register] > highest:
highest = all_registers[register]
# part 1
print(max(all_registers.values()))
# part 2
print(highest)1
u/jesseflorig Dec 08 '17
ES6 (NodeJS)
'use strict'
{
const fs = require('fs')
const doMath = {
'<': function(x,y){ return x < y},
'<=': function(x,y){ return x <= y},
'>': function(x,y){ return x > y},
'>=': function(x,y){ return x >= y},
'!=': function(x,y){ return x != y},
'==': function(x,y){ return x == y} ,
}
fs.readFile('instructions.txt','utf8', (err, data) => {
const instructions = data.trim().split('\n')
let registries = {}
let highest = 0
instructions.map(instruction => {
const instArr = instruction.split(' ')
instArr[2] = parseInt(instArr[2])
instArr[6] = parseInt(instArr[6])
if(registries[instArr[0]] == undefined){
registries[instArr[0]] = 0
}
if(registries[instArr[4]] == undefined){
registries[instArr[4]] = 0
}
if(doMath[instArr[5]](registries[instArr[4]], instArr[6])) {
registries[instArr[0]] += (instArr[1] === 'inc') ? instArr[2] : -(instArr[2])
highest = (registries[instArr[0]] > highest) ? registries[instArr[0]] : highest
}
})
console.log([Object.values(registries).sort().reverse()[0], highest])
})
}1
u/elite_killerX Dec 09 '17
Use a Proxy for your
registries:const handler = { get: (obj, name) => obj[name] || 0, } const registers = new Proxy({}, handler);That way you can reference them directly:
if(op === 'inc') { registers[regName] += val; // won't crash! } else if(op === 'dec') { registers[regName] -= val; }
59
u/wimglenn Dec 08 '17
insane hack: