#include "aoc.h" #include "iccmp.h" #include "list.h" #include "maxint.h" #include "util.h" #include #include #include #include struct packet { struct maxint x, y; size_t src_ip, dst_ip; struct list_link link; }; static struct packet nat_packet; static bool nat_avail = false; void feed_input(struct icc *icc, mi_ul imm) { while (icc->state != ICC_HALT) { if (icc->state == ICC_INPUT) { mi_setv(&icc->in, imm, MI_POS); icc_step_inst(icc); break; } icc_step_inst(icc); } } void free_packet(void *p) { struct packet *packet; packet = p; mi_deinit(&packet->x); mi_deinit(&packet->y); free(packet); } bool recv_packet(struct list *queues, struct maxint *val, int state, size_t ip) { static struct packet *packet; struct list_link *link; char buf[64]; aoc_debug("INPUT %i\n", ip); if (list_empty(&queues[ip])) { mi_setv(val, 1, MI_NEG); return false; } else { switch(state) { case 0: link = list_front(&queues[ip]); packet = LIST_UPCAST(link, struct packet, link); aoc_debug("%i <- %i (", packet->src_ip, packet->dst_ip); mi_dec(&packet->x, buf, sizeof(buf), 0); aoc_debug("%s, ", buf); mi_dec(&packet->y, buf, sizeof(buf), 0); aoc_debug("%s)\n", buf); mi_set(val, &packet->x); break; case 1: mi_set(val, &packet->y); list_link_pop(&packet->link); free_packet(packet); break; } return true; } } void send_packet(struct list *queues, struct maxint *val, int state, size_t ip) { static struct packet *packet; size_t dst; char buf[64]; aoc_debug("OUTPUT %i\n", ip); switch (state) { case 0: dst = (size_t) mi_cast_ul(val); if (dst == 255) { packet = &nat_packet; } else { packet = malloc(sizeof(struct packet)); mi_init(&packet->x); mi_init(&packet->y); } packet->src_ip = ip; packet->dst_ip = dst; packet->link = LIST_LINK_INIT; break; case 1: mi_set(&packet->x, val); break; case 2: mi_set(&packet->y, val); if (packet->dst_ip != 255) { assert(packet->dst_ip < 50); list_insert_back(&queues[packet->dst_ip], &packet->link); } else { nat_avail = true; } aoc_debug("%i <- %i (", packet->dst_ip, packet->src_ip); mi_dec(&packet->x, buf, sizeof(buf), 0); aoc_debug("%s, ", buf); mi_dec(&packet->y, buf, sizeof(buf), 0); aoc_debug("%s)\n", buf); break; } } bool nic_tick(struct icc *icc, struct list *queues, size_t ip) { int out_state, in_state; bool idle, done; done = false; idle = true; in_state = 0; out_state = 0; while (!done && icc->state != ICC_HALT) { switch (icc->state) { case ICC_INPUT: idle &= !recv_packet(queues, &icc->in, in_state, ip); in_state = (in_state + 1) % 2; if (!in_state) done = true; break; case ICC_OUTPUT: send_packet(queues, &icc->out, out_state, ip); out_state = (out_state + 1) % 3; idle = false; break; defualt: assert(icc->state == ICC_RUN); } icc_step_inst(icc); } assert(in_state == 0 && out_state == 0); return idle; } void part1(void) { struct list queues[50]; struct icc icc[50]; char buf[64]; size_t i; for (i = 0; i < 50; i++) { list_init(&queues[i]); icc_init(&icc[i]); icc_parse_inst(&icc[i], aoc.input, aoc.input_size); feed_input(&icc[i], (mi_ul) i); } mi_init(&nat_packet.x); mi_setv(&nat_packet.x, 0, MI_POS); mi_init(&nat_packet.y); mi_setv(&nat_packet.y, 0, MI_POS); while (!nat_avail) { aoc_debug("-- TICK --\n"); for (i = 0; i < 50; i++) nic_tick(&icc[i], queues, i); } mi_dec(&nat_packet.y, buf, sizeof(buf), 0); aoc.answer = aprintf("%s", buf); aoc.solution = "20225"; mi_deinit(&nat_packet.x); mi_deinit(&nat_packet.y); for (i = 0; i < 50; i++) { list_free_items(&queues[i], free_packet, LIST_OFFSET(struct packet, link)); icc_deinit(&icc[i]); } } void part2(void) { struct list queues[256]; struct icc icc[50]; struct packet *packet; size_t answer; size_t last; bool idle; size_t i; for (i = 0; i < 50; i++) { list_init(&queues[i]); icc_init(&icc[i]); icc_parse_inst(&icc[i], aoc.input, aoc.input_size); feed_input(&icc[i], (mi_ul) i); } mi_init(&nat_packet.x); mi_setv(&nat_packet.x, 0, MI_POS); mi_init(&nat_packet.y); mi_setv(&nat_packet.y, 0, MI_POS); last = SIZE_MAX; while (1) { aoc_debug("-- TICK --\n"); idle = true; for (i = 0; i < 50; i++) idle &= nic_tick(&icc[i], queues, i); if (idle) { assert(nat_avail); packet = malloc(sizeof(struct packet)); mi_init(&packet->x); mi_set(&packet->x, &nat_packet.x); mi_init(&packet->y); mi_set(&packet->y, &nat_packet.y); packet->dst_ip = nat_packet.dst_ip; packet->src_ip = nat_packet.src_ip; packet->link = LIST_LINK_INIT; list_insert_back(&queues[0], &packet->link); if (mi_cast_ul(&packet->y) == last) { answer = last; break; } last = mi_cast_ul(&packet->y); } } aoc.answer = aprintf("%lu", answer); aoc.solution = "14348"; mi_deinit(&nat_packet.x); mi_deinit(&nat_packet.y); for (i = 0; i < 50; i++) { list_free_items(&queues[i], free_packet, LIST_OFFSET(struct packet, link)); icc_deinit(&icc[i]); } }