422 lines
14 KiB
C
422 lines
14 KiB
C
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <limits.h>
|
||
|
|
|
||
|
|
#define CODE_LEN 4
|
||
|
|
#define CODES 5
|
||
|
|
#define CODE_MAX_LEN 16*1024
|
||
|
|
#define sgn(a) ((a) < 0 ? -1 : ((a) > 0 ? 1 : 0))
|
||
|
|
#define min(a,b) ((a) < (b) ? (a) : (b))
|
||
|
|
#define abs(a) ((a) < 0 ? -(a) : (a))
|
||
|
|
|
||
|
|
typedef enum {
|
||
|
|
NUMERIC,
|
||
|
|
DIRECTIONAL
|
||
|
|
} panel_type;
|
||
|
|
|
||
|
|
typedef struct node {
|
||
|
|
struct node *children[11];
|
||
|
|
uint64_t value;
|
||
|
|
uint64_t value2;
|
||
|
|
char key;
|
||
|
|
uint8_t is_leaf;
|
||
|
|
} node_t;
|
||
|
|
|
||
|
|
|
||
|
|
typedef struct layer {
|
||
|
|
panel_type type;
|
||
|
|
struct layer *next_layer;
|
||
|
|
int current_position[2];
|
||
|
|
int id;
|
||
|
|
node_t *trie;
|
||
|
|
} layer_t;
|
||
|
|
|
||
|
|
const int numeric_panel[][2] = {
|
||
|
|
{3, 1}, // 0
|
||
|
|
{2, 0}, // 1
|
||
|
|
{2, 1}, // 2
|
||
|
|
{2, 2}, // 3
|
||
|
|
{1, 0}, // 4
|
||
|
|
{1, 1}, // 5
|
||
|
|
{1, 2}, // 6
|
||
|
|
{0, 0}, // 7
|
||
|
|
{0, 1}, // 8
|
||
|
|
{0, 2}, // 9
|
||
|
|
{3, 2}, // A
|
||
|
|
};
|
||
|
|
|
||
|
|
const int directional_panel[][2] = {
|
||
|
|
{0, 1}, // UP
|
||
|
|
{1, 0}, // LEFT
|
||
|
|
{1, 1}, // DOWN
|
||
|
|
{1, 2}, // RIGHT
|
||
|
|
{0, 2}, // A
|
||
|
|
};
|
||
|
|
|
||
|
|
#define UP 0
|
||
|
|
#define LEFT 1
|
||
|
|
#define DOWN 2
|
||
|
|
#define RIGHT 3
|
||
|
|
|
||
|
|
#define d2c(a) ((a) == UP ? '^' : ((a) == LEFT ? '<' : ((a) == DOWN ? 'v' : ((a) == RIGHT ? '>' : 'A'))))
|
||
|
|
|
||
|
|
layer_t* create_numeric_layer() {
|
||
|
|
layer_t *layer = calloc(1, sizeof(layer[0]));
|
||
|
|
layer->type = NUMERIC;
|
||
|
|
layer->next_layer = NULL;
|
||
|
|
layer->current_position[0] = numeric_panel[10][0];
|
||
|
|
layer->current_position[1] = numeric_panel[10][1];
|
||
|
|
layer->trie = calloc(1, sizeof(node_t));
|
||
|
|
return layer;
|
||
|
|
}
|
||
|
|
|
||
|
|
layer_t* create_directional_layer() {
|
||
|
|
layer_t *layer = calloc(1, sizeof(layer[0]));
|
||
|
|
layer->type = DIRECTIONAL;
|
||
|
|
layer->next_layer = NULL;
|
||
|
|
layer->current_position[0] = directional_panel[4][0];
|
||
|
|
layer->current_position[1] = directional_panel[4][1];
|
||
|
|
layer->trie = calloc(1, sizeof(node_t));
|
||
|
|
return layer;
|
||
|
|
}
|
||
|
|
|
||
|
|
int c2n(char code) {
|
||
|
|
if (code == 'A') {
|
||
|
|
return 10;
|
||
|
|
}
|
||
|
|
|
||
|
|
return code - 48;
|
||
|
|
}
|
||
|
|
|
||
|
|
node_t* create_node() {
|
||
|
|
node_t *node = calloc(1, sizeof(node[0]));
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
node_t* search(node_t* root, int* word, int len) {
|
||
|
|
node_t* node = root;
|
||
|
|
for (int i = 0; i < len; i++) {
|
||
|
|
if (node->children[word[i]] == NULL) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
node = node->children[word[i]];
|
||
|
|
}
|
||
|
|
return node;
|
||
|
|
}
|
||
|
|
|
||
|
|
void insert(node_t* root, int* word, int len, uint64_t value, int value2) {
|
||
|
|
node_t* node = root;
|
||
|
|
for (int i = 0; i < len; i++) {
|
||
|
|
if (node->children[word[i]] == NULL) {
|
||
|
|
node->children[word[i]] = create_node();
|
||
|
|
}
|
||
|
|
node = node->children[word[i]];
|
||
|
|
}
|
||
|
|
node->value = value;
|
||
|
|
node->value2 = value2;
|
||
|
|
node->is_leaf = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
void free_node(node_t* node) {
|
||
|
|
for (int i = 0; i < 11; i++) {
|
||
|
|
if (node->children[i] != NULL) {
|
||
|
|
free_node(node->children[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
free(node);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t process_layer(layer_t *layer, int *code, uint64_t code_len, int *new_code, uint64_t new_code_len);
|
||
|
|
uint64_t process_layer2(layer_t *layer, int* code, uint64_t code_len);
|
||
|
|
int coords_to_idx(layer_t *layer, int coords[2]);
|
||
|
|
uint64_t cost_of_activation(layer_t *layer, int button);
|
||
|
|
|
||
|
|
int main() {
|
||
|
|
char c;
|
||
|
|
|
||
|
|
char codes[CODES][CODE_LEN];
|
||
|
|
int code_count = 0, character_count = 0;
|
||
|
|
|
||
|
|
while ((c = getchar()) != EOF) {
|
||
|
|
codes[code_count][character_count++] = c;
|
||
|
|
if (c != '\n') {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
character_count = 0;
|
||
|
|
code_count++;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create Layers
|
||
|
|
layer_t **layers = calloc(26, sizeof(layer_t*));
|
||
|
|
// First is the numeric panel
|
||
|
|
layers[0] = create_numeric_layer();
|
||
|
|
layers[0]->id = 0;
|
||
|
|
// Create directional layers
|
||
|
|
for (int i = 1; i < 26; i++) {
|
||
|
|
layers[i] = create_directional_layer();
|
||
|
|
layers[i]->id = i;
|
||
|
|
}
|
||
|
|
// Link layers
|
||
|
|
for (int i = 0; i < 25; i++) {
|
||
|
|
layers[i]->next_layer = layers[i+1];
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t sum = 0;
|
||
|
|
for (int i = 0; i < code_count; i++) {
|
||
|
|
// Convert code chars to int
|
||
|
|
int code_encoded[4];
|
||
|
|
for (int j = 0; j < 4; j++) {
|
||
|
|
code_encoded[j] = c2n(codes[i][j]);
|
||
|
|
}
|
||
|
|
|
||
|
|
int *ccode = calloc(CODE_MAX_LEN, sizeof(ccode[0]));
|
||
|
|
//uint64_t a = process_layer(layers[0], code_encoded, 4, ccode, 0);
|
||
|
|
int code_encoded2[5];
|
||
|
|
for (int j = 0; j < 4; j++) {
|
||
|
|
code_encoded2[j+1] = c2n(codes[i][j]);
|
||
|
|
}
|
||
|
|
code_encoded2[0] = 10;
|
||
|
|
uint64_t a = process_layer2(layers[0], code_encoded2, 5);
|
||
|
|
free(ccode);
|
||
|
|
int b;
|
||
|
|
sscanf(codes[i], "%d", &b);
|
||
|
|
sum += a * (uint64_t)b;
|
||
|
|
}
|
||
|
|
printf("%lu\n", sum);
|
||
|
|
|
||
|
|
for (int i = 0; i < 26; i++) {
|
||
|
|
free_node(layers[i]->trie);
|
||
|
|
free(layers[i]);
|
||
|
|
}
|
||
|
|
free(layers);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t process_layer(layer_t *layer, int *code, uint64_t code_len, int *new_code, uint64_t new_code_len) {
|
||
|
|
if (code_len == 0) {
|
||
|
|
if (layer->next_layer == NULL) {
|
||
|
|
return new_code_len;
|
||
|
|
}
|
||
|
|
int *ccode = calloc(CODE_MAX_LEN, sizeof(ccode[0]));
|
||
|
|
uint64_t result = process_layer(layer->next_layer, new_code, new_code_len, ccode, 0);
|
||
|
|
free(ccode);
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
int current_position[2];
|
||
|
|
current_position[0] = layer->current_position[0];
|
||
|
|
current_position[1] = layer->current_position[1];
|
||
|
|
|
||
|
|
int (*panel)[2] = layer->type == NUMERIC ? numeric_panel : directional_panel;
|
||
|
|
// Check if we are on the right button
|
||
|
|
if (current_position[0] == panel[code[0]][0] && current_position[1] == panel[code[0]][1]) {
|
||
|
|
// Click button
|
||
|
|
new_code[new_code_len] = 4;
|
||
|
|
return process_layer(layer, code + 1, code_len - 1, new_code, new_code_len+1);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t ncl = new_code_len;
|
||
|
|
uint64_t value1 = UINT64_MAX, value2 = UINT64_MAX;
|
||
|
|
// Try going in each direction towards the next button
|
||
|
|
if (current_position[0] != panel[code[0]][0]) {
|
||
|
|
// Up or down
|
||
|
|
if (current_position[0] - panel[code[0]][0] > 0) {
|
||
|
|
for (int i = 0; i < current_position[0] - panel[code[0]][0]; i++) {
|
||
|
|
new_code[new_code_len++] = UP;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
for (int i = 0; i < panel[code[0]][0] - current_position[0]; i++) {
|
||
|
|
new_code[new_code_len++] = DOWN;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
layer->current_position[0] = panel[code[0]][0];
|
||
|
|
// Cannot go to empty space
|
||
|
|
if ((layer->type == NUMERIC && layer->current_position[0] == 3 && layer->current_position[1] == 0) || (layer->type == DIRECTIONAL && layer->current_position[0] == 0 && layer->current_position[1] == 0)) {
|
||
|
|
} else {
|
||
|
|
value1 = process_layer(layer, code, code_len, new_code, new_code_len);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
layer->current_position[0] = current_position[0];
|
||
|
|
layer->current_position[1] = current_position[1];
|
||
|
|
new_code_len = ncl;
|
||
|
|
|
||
|
|
if (current_position[1] != panel[code[0]][1]) {
|
||
|
|
// Up or down
|
||
|
|
if (current_position[1] - panel[code[0]][1] > 0) {
|
||
|
|
for (int i = 0; i < current_position[1] - panel[code[0]][1]; i++) {
|
||
|
|
new_code[new_code_len++] = LEFT;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
for (int i = 0; i < panel[code[0]][1] - current_position[1]; i++) {
|
||
|
|
new_code[new_code_len++] = RIGHT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
layer->current_position[1] = panel[code[0]][1];
|
||
|
|
// Cannot go to empty space
|
||
|
|
if ((layer->type == NUMERIC && layer->current_position[0] == 3 && layer->current_position[1] == 0) || (layer->type == DIRECTIONAL && layer->current_position[0] == 0 && layer->current_position[1] == 0)) {
|
||
|
|
} else {
|
||
|
|
value2 = process_layer(layer, code, code_len, new_code, new_code_len);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
layer->current_position[0] = current_position[0];
|
||
|
|
layer->current_position[1] = current_position[1];
|
||
|
|
|
||
|
|
|
||
|
|
uint64_t value = min(value1, value2);
|
||
|
|
|
||
|
|
return value;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t process_layer2(layer_t *layer, int* code, uint64_t code_len) {
|
||
|
|
uint64_t sum = 0;
|
||
|
|
if (layer == NULL) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
int (*panel)[2] = layer->type == NUMERIC ? numeric_panel : directional_panel;
|
||
|
|
int current_position[2];
|
||
|
|
int button_count = layer->type == NUMERIC ? 11 : 5;
|
||
|
|
|
||
|
|
// Build cache for each combination
|
||
|
|
if (layer->trie->children[0] == NULL) {
|
||
|
|
for (int i = 0; i < button_count; i++) {
|
||
|
|
for (int j = 0; j < button_count; j++) {
|
||
|
|
int combination[2] = {i, j};
|
||
|
|
int start1[2] = {panel[i][0], panel[i][1]};
|
||
|
|
int start2[2] = {panel[i][0], panel[i][1]};
|
||
|
|
int end[2] = {panel[j][0], panel[j][1]};
|
||
|
|
|
||
|
|
int last_action1 = 4;
|
||
|
|
// X first, Y second
|
||
|
|
uint64_t distance1 = 0;
|
||
|
|
while (start1[0] != end[0]) {
|
||
|
|
int dir = sgn(end[0] - start1[0]);
|
||
|
|
start1[0] += dir;
|
||
|
|
if ((layer->type == NUMERIC && start1[0] == 3 && start1[1] == 0) || (layer->type == DIRECTIONAL && start1[0] == 0 && start1[1] == 0)) {
|
||
|
|
distance1 = UINT64_MAX;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
int subcombination[2];
|
||
|
|
subcombination[0] = last_action1;
|
||
|
|
if (dir == -1) {
|
||
|
|
subcombination[1] = UP;
|
||
|
|
last_action1 = UP;
|
||
|
|
} else {
|
||
|
|
subcombination[1] = DOWN;
|
||
|
|
last_action1 = DOWN;
|
||
|
|
}
|
||
|
|
distance1 += process_layer2(layer->next_layer, subcombination, 2);
|
||
|
|
}
|
||
|
|
if (distance1 != UINT64_MAX) {
|
||
|
|
while (start1[1] != end[1]) {
|
||
|
|
int dir = sgn(end[1] - start1[1]);
|
||
|
|
start1[1] += dir;
|
||
|
|
int subcombination[2];
|
||
|
|
subcombination[0] = last_action1;
|
||
|
|
if (dir == -1) {
|
||
|
|
subcombination[1] = LEFT;
|
||
|
|
last_action1 = LEFT;
|
||
|
|
} else {
|
||
|
|
subcombination[1] = RIGHT;
|
||
|
|
last_action1 = RIGHT;
|
||
|
|
}
|
||
|
|
distance1 += process_layer2(layer->next_layer, subcombination, 2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (distance1 != UINT64_MAX) {
|
||
|
|
int activatecombination[2] = {last_action1, 4};
|
||
|
|
distance1 += process_layer2(layer->next_layer, activatecombination, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
int last_action2 = 4;
|
||
|
|
// Y first, X second
|
||
|
|
uint64_t distance2 = 0;
|
||
|
|
while (start2[1] != end[1]) {
|
||
|
|
int dir = sgn(end[1] - start2[1]);
|
||
|
|
start2[1] += dir;
|
||
|
|
if ((layer->type == NUMERIC && start2[0] == 3 && start2[1] == 0) || (layer->type == DIRECTIONAL && start2[0] == 0 && start2[1] == 0)) {
|
||
|
|
distance2 = UINT64_MAX;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
int subcombination[2];
|
||
|
|
subcombination[0] = last_action2;
|
||
|
|
if (dir == -1) {
|
||
|
|
subcombination[1] = LEFT;
|
||
|
|
last_action2 = LEFT;
|
||
|
|
} else {
|
||
|
|
subcombination[1] = RIGHT;
|
||
|
|
last_action2 = RIGHT;
|
||
|
|
}
|
||
|
|
distance2 += process_layer2(layer->next_layer, subcombination, 2);
|
||
|
|
}
|
||
|
|
if (distance2 != UINT64_MAX) {
|
||
|
|
while (start2[0] != end[0]) {
|
||
|
|
int dir = sgn(end[0] - start2[0]);
|
||
|
|
start2[0] += dir;
|
||
|
|
int subcombination[2];
|
||
|
|
subcombination[0] = last_action2;
|
||
|
|
if (dir == -1) {
|
||
|
|
subcombination[1] = UP;
|
||
|
|
last_action2 = UP;
|
||
|
|
} else {
|
||
|
|
subcombination[1] = DOWN;
|
||
|
|
last_action2 = DOWN;
|
||
|
|
}
|
||
|
|
distance2 += process_layer2(layer->next_layer, subcombination, 2);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (distance2 != UINT64_MAX) {
|
||
|
|
int activatecombination[2] = {last_action2, 4};
|
||
|
|
distance2 += process_layer2(layer->next_layer, activatecombination, 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t distance = distance1;
|
||
|
|
int last_action = last_action1;
|
||
|
|
if (distance1 > distance2) {
|
||
|
|
distance = distance2;
|
||
|
|
last_action = last_action2;
|
||
|
|
}
|
||
|
|
|
||
|
|
//printf("Layer %i: cost from %i to %i is %lu\n", layer->id, i, j, distance);
|
||
|
|
insert(layer->trie, combination, 2, distance, last_action);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
for (uint64_t i = 1; i < code_len; i++) {
|
||
|
|
int combination[2] = {code[i-1], code[i]};
|
||
|
|
node_t *node = search(layer->trie, combination, 2);
|
||
|
|
sum += node->value;
|
||
|
|
}
|
||
|
|
|
||
|
|
return sum;
|
||
|
|
}
|
||
|
|
|
||
|
|
int coords_to_idx(layer_t *layer, int coords[2]) {
|
||
|
|
int idx;
|
||
|
|
int (*panel)[2] = layer->type == NUMERIC ? numeric_panel : directional_panel;
|
||
|
|
for (idx = 0; idx < (layer->type == NUMERIC ? 11 : 5); idx++) {
|
||
|
|
if (coords[0] == panel[idx][0] && coords[1] == panel[idx][1]) {
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return idx;
|
||
|
|
}
|
||
|
|
|
||
|
|
uint64_t cost_of_activation(layer_t *layer, int button) {
|
||
|
|
if (layer == NULL) {
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Build cache if not present
|
||
|
|
if (layer->trie->children[0] == NULL) {
|
||
|
|
process_layer2(layer, NULL, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
int combination[2] = {button, 4};
|
||
|
|
node_t *node = search(layer->trie, combination, 2);
|
||
|
|
|
||
|
|
return node->value + cost_of_activation(layer->next_layer, node->value2);
|
||
|
|
}
|