2019 day 2
This commit is contained in:
@@ -12,3 +12,16 @@ aoc-c : res=4975039
|
|||||||
time: 0:00.00 real, 0.00 user, 0.00 sys
|
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||||
context-switch: 0+1, page-faults: 0+89
|
context-switch: 0+1, page-faults: 0+89
|
||||||
|
|
||||||
|
=========================================
|
||||||
|
================= day02 =================
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
+++++++++++++++++ part 1
|
||||||
|
aoc-c : res=3790689
|
||||||
|
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||||
|
context-switch: 0+1, page-faults: 0+88
|
||||||
|
|
||||||
|
+++++++++++++++++ part 2
|
||||||
|
aoc-c : res=6533
|
||||||
|
time: 0:00.00 real, 0.00 user, 0.00 sys
|
||||||
|
context-switch: 0+1, page-faults: 0+88
|
||||||
|
1
2019/day02/EXAMPLE.txt
Normal file
1
2019/day02/EXAMPLE.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1,9,10,3,2,3,11,0,99,30,40,50
|
1
2019/day02/EXAMPLE2.txt
Normal file
1
2019/day02/EXAMPLE2.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1,0,0,0,99
|
1
2019/day02/EXAMPLE3.txt
Normal file
1
2019/day02/EXAMPLE3.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2,3,0,3,99
|
1
2019/day02/EXAMPLE4.txt
Normal file
1
2019/day02/EXAMPLE4.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2,4,4,5,99,0
|
1
2019/day02/EXAMPLE5.txt
Normal file
1
2019/day02/EXAMPLE5.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1,1,1,4,99,5,6,0,99
|
1
2019/day02/INPUT.txt
Normal file
1
2019/day02/INPUT.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
1,0,0,3,1,1,2,3,1,3,4,3,1,5,0,3,2,1,13,19,1,9,19,23,2,13,23,27,2,27,13,31,2,31,10,35,1,6,35,39,1,5,39,43,1,10,43,47,1,5,47,51,1,13,51,55,2,55,9,59,1,6,59,63,1,13,63,67,1,6,67,71,1,71,10,75,2,13,75,79,1,5,79,83,2,83,6,87,1,6,87,91,1,91,13,95,1,95,13,99,2,99,13,103,1,103,5,107,2,107,10,111,1,5,111,115,1,2,115,119,1,119,6,0,99,2,0,14,0
|
77
2019/day02/Makefile
Normal file
77
2019/day02/Makefile
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# AOC daily Makefile - GNU make only.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2021 Bruno Raoult ("br")
|
||||||
|
# Licensed under the GNU General Public License v3.0 or later.
|
||||||
|
# Some rights reserved. See COPYING.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along with this
|
||||||
|
# program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
#
|
||||||
|
|
||||||
|
INPUT := INPUT.txt
|
||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
CC := gcc
|
||||||
|
|
||||||
|
LIB := aoc_$(shell uname -m)
|
||||||
|
INCDIR := ../include
|
||||||
|
LIBDIR := ../lib
|
||||||
|
LDFLAGS := -L$(LIBDIR)
|
||||||
|
#LDLIB := -l$(LIB) -lm
|
||||||
|
LDLIB := -l$(LIB)
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH = $(LIBDIR)
|
||||||
|
|
||||||
|
CFLAGS += -std=gnu99
|
||||||
|
CFLAGS += -O2
|
||||||
|
CFLAGS += -g
|
||||||
|
# for gprof
|
||||||
|
#CFLAGS += -pg
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wextra
|
||||||
|
CFLAGS += -march=native
|
||||||
|
# Next one may be useful for valgrind (some invalid instructions)
|
||||||
|
# CFLAGS += -mno-tbm
|
||||||
|
CFLAGS += -Wmissing-declarations
|
||||||
|
CFLAGS += -Wno-unused-result
|
||||||
|
|
||||||
|
CFLAGS += -DDEBUG_DEBUG # activate general debug (debug.c)
|
||||||
|
CFLAGS += -DDEBUG_POOL # memory pools management
|
||||||
|
|
||||||
|
TIME := \time -f "\ttime: %E real, %U user, %S sys\n\tcontext-switch:\t%c+%w, page-faults: %F+%R\n"
|
||||||
|
export PATH := .:$(PATH)
|
||||||
|
|
||||||
|
.PHONY: clean all compile assembly memcheck memcheck1 memcheck2 ex1 ex2
|
||||||
|
|
||||||
|
all: ex1 ex2
|
||||||
|
|
||||||
|
memcheck: memcheck1
|
||||||
|
|
||||||
|
memcheck1:
|
||||||
|
@valgrind -q -s --track-origins=yes aoc-c -p 1 < $(INPUT)
|
||||||
|
|
||||||
|
memcheck2:
|
||||||
|
@valgrind -q -s --track-origins=yes aoc-c -p 2 < $(INPUT)
|
||||||
|
|
||||||
|
compile: aoc-c
|
||||||
|
|
||||||
|
assembly: aoc-c.s
|
||||||
|
|
||||||
|
ex1: aoc-c
|
||||||
|
@$(TIME) aoc-c -p 1 < $(INPUT)
|
||||||
|
|
||||||
|
ex2: aoc-c
|
||||||
|
@$(TIME) aoc-c -p 2 < $(INPUT)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@rm -f aoc-c core* vgcore* gmon.out aoc-c.s
|
||||||
|
|
||||||
|
.c:
|
||||||
|
@echo compiling $<
|
||||||
|
@$(CC) $(CFLAGS) $(LDFLAGS) -I $(INCDIR) $< $(LDLIB) -o $@
|
||||||
|
|
||||||
|
.c.s:
|
||||||
|
@echo generating $@
|
||||||
|
@$(CC) -S -fverbose-asm $(CFLAGS) -I $(INCDIR) $< -o $@
|
159
2019/day02/README.org
Normal file
159
2019/day02/README.org
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
** --- Day 2: 1202 Program Alarm ---
|
||||||
|
On the way to your
|
||||||
|
[[https://en.wikipedia.org/wiki/Gravity_assist][gravity assist]] around
|
||||||
|
the Moon, your ship computer beeps angrily about a
|
||||||
|
"[[https://www.hq.nasa.gov/alsj/a11/a11.landing.html#1023832][1202
|
||||||
|
program alarm]]". On the radio, an Elf is already explaining how to
|
||||||
|
handle the situation: "Don't worry, that's perfectly norma--" The ship
|
||||||
|
computer [[https://en.wikipedia.org/wiki/Halt_and_Catch_Fire][bursts
|
||||||
|
into flames]].
|
||||||
|
|
||||||
|
You notify the Elves that the computer's
|
||||||
|
[[https://en.wikipedia.org/wiki/Magic_smoke][magic smoke]] seems to have
|
||||||
|
escaped. "That computer ran /Intcode/ programs like the gravity assist
|
||||||
|
program it was working on; surely there are enough spare parts up there
|
||||||
|
to build a new Intcode computer!"
|
||||||
|
|
||||||
|
An Intcode program is a list of
|
||||||
|
[[https://en.wikipedia.org/wiki/Integer][integers]] separated by commas
|
||||||
|
(like =1,0,0,3,99=). To run one, start by looking at the first integer
|
||||||
|
(called position =0=). Here, you will find an /opcode/ - either =1=,
|
||||||
|
=2=, or =99=. The opcode indicates what to do; for example, =99= means
|
||||||
|
that the program is finished and should immediately halt. Encountering
|
||||||
|
an unknown opcode means something went wrong.
|
||||||
|
|
||||||
|
Opcode =1= /adds/ together numbers read from two positions and stores
|
||||||
|
the result in a third position. The three integers /immediately after/
|
||||||
|
the opcode tell you these three positions - the first two indicate the
|
||||||
|
/positions/ from which you should read the input values, and the third
|
||||||
|
indicates the /position/ at which the output should be stored.
|
||||||
|
|
||||||
|
For example, if your Intcode computer encounters =1,10,20,30=, it should
|
||||||
|
read the values at positions =10= and =20=, add those values, and then
|
||||||
|
overwrite the value at position =30= with their sum.
|
||||||
|
|
||||||
|
Opcode =2= works exactly like opcode =1=, except it /multiplies/ the two
|
||||||
|
inputs instead of adding them. Again, the three integers after the
|
||||||
|
opcode indicate /where/ the inputs and outputs are, not their values.
|
||||||
|
|
||||||
|
Once you're done processing an opcode, /move to the next one/ by
|
||||||
|
stepping forward =4= positions.
|
||||||
|
|
||||||
|
For example, suppose you have the following program:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
1,9,10,3,2,3,11,0,99,30,40,50
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
For the purposes of illustration, here is the same program split into
|
||||||
|
multiple lines:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
1,9,10,3,
|
||||||
|
2,3,11,0,
|
||||||
|
99,
|
||||||
|
30,40,50
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
The first four integers, =1,9,10,3=, are at positions =0=, =1=, =2=, and
|
||||||
|
=3=. Together, they represent the first opcode (=1=, addition), the
|
||||||
|
positions of the two inputs (=9= and =10=), and the position of the
|
||||||
|
output (=3=). To handle this opcode, you first need to get the values at
|
||||||
|
the input positions: position =9= contains =30=, and position =10=
|
||||||
|
contains =40=. /Add/ these numbers together to get =70=. Then, store
|
||||||
|
this value at the output position; here, the output position (=3=) is
|
||||||
|
/at/ position =3=, so it overwrites itself. Afterward, the program looks
|
||||||
|
like this:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
1,9,10,70,
|
||||||
|
2,3,11,0,
|
||||||
|
99,
|
||||||
|
30,40,50
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
Step forward =4= positions to reach the next opcode, =2=. This opcode
|
||||||
|
works just like the previous, but it multiplies instead of adding. The
|
||||||
|
inputs are at positions =3= and =11=; these positions contain =70= and
|
||||||
|
=50= respectively. Multiplying these produces =3500=; this is stored at
|
||||||
|
position =0=:
|
||||||
|
|
||||||
|
#+BEGIN_EXAMPLE
|
||||||
|
3500,9,10,70,
|
||||||
|
2,3,11,0,
|
||||||
|
99,
|
||||||
|
30,40,50
|
||||||
|
#+END_EXAMPLE
|
||||||
|
|
||||||
|
Stepping forward =4= more positions arrives at opcode =99=, halting the
|
||||||
|
program.
|
||||||
|
|
||||||
|
Here are the initial and final states of a few more small programs:
|
||||||
|
|
||||||
|
- =1,0,0,0,99= becomes =2,0,0,0,99= (=1 + 1 = 2=).
|
||||||
|
- =2,3,0,3,99= becomes =2,3,0,6,99= (=3 * 2 = 6=).
|
||||||
|
- =2,4,4,5,99,0= becomes =2,4,4,5,99,9801= (=99 * 99 = 9801=).
|
||||||
|
- =1,1,1,4,99,5,6,0,99= becomes =30,1,1,4,2,5,6,0,99=.
|
||||||
|
|
||||||
|
Once you have a working computer, the first step is to restore the
|
||||||
|
gravity assist program (your puzzle input) to the "1202 program alarm"
|
||||||
|
state it had just before the last computer caught fire. To do this,
|
||||||
|
/before running the program/, replace position =1= with the value =12=
|
||||||
|
and replace position =2= with the value =2=. /What value is left at
|
||||||
|
position =0=/ after the program halts?
|
||||||
|
|
||||||
|
Your puzzle answer was =3790689=.
|
||||||
|
|
||||||
|
** --- Part Two ---
|
||||||
|
"Good, the new computer seems to be working correctly! /Keep it nearby/
|
||||||
|
during this mission - you'll probably use it again. Real Intcode
|
||||||
|
computers support many more features than your new one, but we'll let
|
||||||
|
you know what they are as you need them."
|
||||||
|
|
||||||
|
"However, your current priority should be to complete your gravity
|
||||||
|
assist around the Moon. For this mission to succeed, we should settle on
|
||||||
|
some terminology for the parts you've already built."
|
||||||
|
|
||||||
|
Intcode programs are given as a list of integers; these values are used
|
||||||
|
as the initial state for the computer's /memory/. When you run an
|
||||||
|
Intcode program, make sure to start by initializing memory to the
|
||||||
|
program's values. A position in memory is called an /address/ (for
|
||||||
|
example, the first value in memory is at "address 0").
|
||||||
|
|
||||||
|
Opcodes (like =1=, =2=, or =99=) mark the beginning of an /instruction/.
|
||||||
|
The values used immediately after an opcode, if any, are called the
|
||||||
|
instruction's /parameters/. For example, in the instruction =1,2,3,4=,
|
||||||
|
=1= is the opcode; =2=, =3=, and =4= are the parameters. The instruction
|
||||||
|
=99= contains only an opcode and has no parameters.
|
||||||
|
|
||||||
|
The address of the current instruction is called the /instruction
|
||||||
|
pointer/; it starts at =0=. After an instruction finishes, the
|
||||||
|
instruction pointer increases by /the number of values in the
|
||||||
|
instruction/; until you add more instructions to the computer, this is
|
||||||
|
always =4= (=1= opcode + =3= parameters) for the add and multiply
|
||||||
|
instructions. (The halt instruction would increase the instruction
|
||||||
|
pointer by =1=, but it halts the program instead.)
|
||||||
|
|
||||||
|
"With terminology out of the way, we're ready to proceed. To complete
|
||||||
|
the gravity assist, you need to /determine what pair of inputs produces
|
||||||
|
the output =19690720=/."
|
||||||
|
|
||||||
|
The inputs should still be provided to the program by replacing the
|
||||||
|
values at addresses =1= and =2=, just like before. In this program, the
|
||||||
|
value placed in address =1= is called the /noun/, and the value placed
|
||||||
|
in address =2= is called the /verb/. Each of the two input values will
|
||||||
|
be between =0= and =99=, inclusive.
|
||||||
|
|
||||||
|
Once the program has halted, its output is available at address =0=,
|
||||||
|
also just like before. Each time you try a pair of inputs, make sure you
|
||||||
|
first /reset the computer's memory to the values in the program/ (your
|
||||||
|
puzzle input) - in other words, don't reuse memory from a previous
|
||||||
|
attempt.
|
||||||
|
|
||||||
|
Find the input /noun/ and /verb/ that cause the program to produce the
|
||||||
|
output =19690720=. /What is =100 * noun + verb=?/ (For example, if
|
||||||
|
=noun=12= and =verb=2=, the answer would be =1202=.)
|
||||||
|
|
||||||
|
Your puzzle answer was =6533=.
|
||||||
|
|
||||||
|
Both parts of this puzzle are complete! They provide two gold stars: **
|
150
2019/day02/aoc-c.c
Normal file
150
2019/day02/aoc-c.c
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/* aoc-c.c: Advent of Code 2019, day 2 parts 1 & 2
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Bruno Raoult ("br")
|
||||||
|
* Licensed under the GNU General Public License v3.0 or later.
|
||||||
|
* Some rights reserved. See COPYING.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with this
|
||||||
|
* program. If not, see <https://www.gnu.org/licenses/gpl-3.0-standalone.html>.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later <https://spdx.org/licenses/GPL-3.0-or-later.html>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ADD = 1,
|
||||||
|
MUL = 2,
|
||||||
|
RET = 99
|
||||||
|
} opcode_t;
|
||||||
|
|
||||||
|
#define MAXOPS 1024
|
||||||
|
struct program {
|
||||||
|
int length; /* total program length */
|
||||||
|
int cur; /* current position */
|
||||||
|
int ops[MAXOPS]; /* should really be dynamic */
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OP(p) ((p)->ops + (p)->cur)
|
||||||
|
|
||||||
|
#define A1(p) ((p)->ops + *((p)->ops + (p)->cur + 1))
|
||||||
|
#define A2(p) ((p)->ops + *((p)->ops + (p)->cur + 2))
|
||||||
|
#define A3(p) ((p)->ops + *((p)->ops + (p)->cur + 3))
|
||||||
|
|
||||||
|
static int run(struct program *prog)
|
||||||
|
{
|
||||||
|
while (1) {
|
||||||
|
opcode_t opcode = *OP(prog);
|
||||||
|
switch (opcode) {
|
||||||
|
case ADD:
|
||||||
|
*A3(prog) = *A1(prog) + *A2(prog);
|
||||||
|
break;
|
||||||
|
case MUL:
|
||||||
|
*A3(prog) = *A1(prog) * *A2(prog);
|
||||||
|
break;
|
||||||
|
case RET:
|
||||||
|
return prog->ops[0];
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "wrong opcode %d at %d.\n", opcode, prog->cur);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
prog->cur += 4;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct program *parse()
|
||||||
|
{
|
||||||
|
size_t alloc = 0;
|
||||||
|
ssize_t buflen;
|
||||||
|
char *buf = NULL, *token;
|
||||||
|
int input;
|
||||||
|
struct program *prog = NULL;
|
||||||
|
|
||||||
|
if ((buflen = getline(&buf, &alloc, stdin)) <= 0) {
|
||||||
|
fprintf(stderr, "error reading file.\n");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(prog = calloc(1, sizeof(struct program)))) {
|
||||||
|
fprintf(stderr, "cannot allocate program.\n");
|
||||||
|
goto freebuf;
|
||||||
|
}
|
||||||
|
for (token = strtok(buf, ","); token; token = strtok(NULL, ",")) {
|
||||||
|
if (prog->length >= MAXOPS - 1) {
|
||||||
|
fprintf(stderr, "overflow !\n");
|
||||||
|
free(prog);
|
||||||
|
prog = NULL;
|
||||||
|
goto freebuf;
|
||||||
|
}
|
||||||
|
input=atoi(token);
|
||||||
|
prog->ops[prog->length++] = input;
|
||||||
|
}
|
||||||
|
freebuf:
|
||||||
|
free(buf);
|
||||||
|
end:
|
||||||
|
return prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int part1(struct program *p)
|
||||||
|
{
|
||||||
|
p->ops[1] = 12;
|
||||||
|
p->ops[2] = 2;
|
||||||
|
|
||||||
|
return run(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int part2(struct program *p)
|
||||||
|
{
|
||||||
|
struct program work;
|
||||||
|
|
||||||
|
for (int noun = 0; noun < 100; ++noun) {
|
||||||
|
for (int verb = 0; verb < 100; ++verb) {
|
||||||
|
work = *p;
|
||||||
|
work.ops[1] = noun;
|
||||||
|
work.ops[2] = verb;
|
||||||
|
if (run(&work) == 19690720)
|
||||||
|
return noun * 100 + verb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int usage(char *prg)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: %s [-d debug_level] [-p part]\n", prg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int ac, char **av)
|
||||||
|
{
|
||||||
|
int opt, part = 1;
|
||||||
|
struct program *p;
|
||||||
|
|
||||||
|
while ((opt = getopt(ac, av, "d:p:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'd':
|
||||||
|
debug_level_set(atoi(optarg));
|
||||||
|
break;
|
||||||
|
case 'p': /* 1 or 2 */
|
||||||
|
part = atoi(optarg);
|
||||||
|
if (part < 1 || part > 2)
|
||||||
|
return usage(*av);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return usage(*av);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < ac)
|
||||||
|
return usage(*av);
|
||||||
|
p = parse();
|
||||||
|
printf("%s : res=%d\n", *av, part == 1? part1(p): part2(p));
|
||||||
|
|
||||||
|
exit (0);
|
||||||
|
}
|
Reference in New Issue
Block a user