This commit is contained in:
Christian
2023-11-07 16:15:01 +01:00
parent 87ee53385e
commit bb4471f2db
8 changed files with 5381 additions and 1 deletions

305
src/Days/D20.c Normal file
View File

@@ -0,0 +1,305 @@
#include <stddef.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#define max(a,b) \
({ \
__typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; \
})
///////////////////
// AVL-TREE NODE //
///////////////////
typedef struct Node {
struct Node *parent;
struct Node *leftChild;
struct Node *rightChild;
int32_t size;
int32_t height;
int64_t value;
} Node;
////////////////////////////////
// NULL-SAFE NODE DATA ACCESS //
////////////////////////////////
int32_t height(Node *node)
{
return node == NULL ? 0 : node->height;
}
int32_t size(Node *node)
{
return node == NULL ? 0 : node->size;
}
int balance(Node *node)
{
return node == NULL ? 0 : height(node->leftChild) - height(node->rightChild);
}
///////////
// RESET //
///////////
void resetHeight(Node *node)
{
node->height = 1 + max(height(node->leftChild), height(node->rightChild));
}
void resetSize(Node *node)
{
node->size = 1 + size(node->leftChild) + size(node->rightChild);
}
///////////////////
// AVL-ROTATIONS //
///////////////////
Node *rotateL(Node *root)
{
assert(root);
assert(root->rightChild);
Node *newRoot = root->rightChild;
Node *transfer = newRoot->leftChild;
newRoot->leftChild = root;
root->rightChild = transfer;
newRoot->parent = root->parent;
root->parent = newRoot;
if (transfer != NULL) transfer->parent = root;
resetSize(root);
resetSize(newRoot);
resetHeight(root);
resetHeight(newRoot);
return newRoot;
}
Node *rotateR(Node *root)
{
assert(root);
assert(root->leftChild);
Node *newRoot = root->leftChild;
Node *transfer = newRoot->rightChild;
newRoot->rightChild = root;
root->leftChild = transfer;
newRoot->parent = root->parent;
root->parent = newRoot;
if (transfer != NULL) transfer->parent = root;
resetSize(root);
resetSize(newRoot);
resetHeight(root);
resetHeight(newRoot);
return newRoot;
}
///////////////////
// MODIFICATIONS //
///////////////////
Node *insert_pos_rec(Node *root, int pos, Node *newNode, Node *parent)
{
assert(0 <= pos && (!root || pos <= root->size));
if (root == NULL) {
assert(pos == 0);
newNode->leftChild = NULL;
newNode->rightChild = NULL;
if (parent != NULL) newNode->parent = parent;
resetSize(newNode);
resetHeight(newNode);
return newNode;
}
if (pos <= size(root->leftChild))
root->leftChild = insert_pos_rec(root->leftChild, pos, newNode, root);
else
root->rightChild = insert_pos_rec(root->rightChild, pos - size(root->leftChild) - 1,
newNode, root);
resetSize(root);
resetHeight(root);
int bal = balance(root);
if (bal > 1) {
if (pos > size(root->leftChild->leftChild))
root->leftChild = rotateL(root->leftChild);
root = rotateR(root);
}
if (bal < -1) {
int posUpd = pos - size(root->leftChild) - 1;
if (posUpd <= size(root->rightChild->leftChild))
root->rightChild = rotateR(root->rightChild);
root = rotateL(root);
}
return root;
}
Node *insert_pos(Node *root, int pos, Node *newNode)
{
return insert_pos_rec(root, pos, newNode, NULL);
}
Node *delete_pos_rec(Node *root, int pos, Node **victim)
{
assert(root);
assert(0 <= pos && (!root || pos <= root->size));
if (pos < size(root->leftChild))
root->leftChild = delete_pos_rec(root->leftChild, pos, victim);
else if (pos > size(root->leftChild))
root->rightChild = delete_pos_rec(root->rightChild, pos - size(root->leftChild) - 1, victim);
else {
*victim = root;
if (root->leftChild == NULL) return root->rightChild;
if (root->rightChild == NULL) return root->leftChild;
Node *replacement;
root->rightChild = delete_pos_rec(root->rightChild, 0, &replacement);
replacement->leftChild = root->leftChild;
replacement->rightChild = root->rightChild;
replacement->parent = root->parent;
root = replacement;
}
if (root->leftChild) root->leftChild->parent = root;
if (root->rightChild) root->rightChild->parent = root;
resetSize(root);
resetHeight(root);
int bal = balance(root);
if (bal > 1) {
if (balance(root->leftChild) < 0)
root->leftChild = rotateL(root->leftChild);
root = rotateR(root);
}
if (bal < -1) {
if (balance(root->rightChild) > 0)
root->rightChild = rotateR(root->rightChild);
root = rotateL(root);
}
return root;
}
Node *delete_pos(Node *root, int pos, Node **victim)
{
return delete_pos_rec(root, pos, victim);
}
int wrap(long long n, int mod)
{
return (n % mod + mod) % mod;
}
//////////////
// QUERYING //
//////////////
Node *node_at_position(Node *root, int pos)
{
assert(root);
assert(0 <= pos && pos <= root->size);
if (pos < size(root->leftChild))
return node_at_position(root->leftChild, pos);
else if (pos > size(root->leftChild))
return node_at_position(root->rightChild, pos - size(root->leftChild) - 1);
else
return root;
}
int32_t position_of_node(Node *node) {
int32_t pos = size(node->leftChild);
for (; node->parent; node = node->parent)
if (node->parent->rightChild == node)
pos += size(node->parent->leftChild) + 1;
return pos;
}
/////////////
// FFI API //
/////////////
typedef struct CyclicList {
Node *root;
Node *nodes;
} CyclicList;
int32_t position_of_nth_value(CyclicList *cl, int32_t n) {
assert(0 <= n && n < cl->root->size);
return position_of_node(&cl->nodes[n]);
}
int64_t value_at_position(CyclicList *cl, int32_t pos) {
return node_at_position(cl->root, wrap(pos, cl->root->size))->value;
}
CyclicList *cyclic_list_from_array(int64_t *values, int numValues) {
CyclicList* cl = malloc(sizeof(CyclicList));
cl->root = NULL;
cl->nodes = (Node *) malloc(sizeof(Node) * numValues);
for (int i = 0; i < numValues; i++)
cl->nodes[i].value = values[i];
for (int i = 0; i < numValues; i++)
cl->root = insert_pos(cl->root, i, &cl->nodes[i]);
return cl;
}
void mix(CyclicList *cl, int32_t rounds) {
Node *victim;
int length = cl->root->size;
for (int j = 0; j < rounds; j++) {
for (int i = 0; i < length; i++) {
int idx = position_of_node(&cl->nodes[i]);
cl->root = delete_pos(cl->root, idx, &victim);
int newIdx = wrap(idx + victim->value, length - 1);
cl->root = insert_pos(cl->root, newIdx, victim);
}
}
}

69
src/Days/D20.hs Normal file
View File

@@ -0,0 +1,69 @@
{-# LANGUAGE ImportQualifiedPost #-}
module Days.D20 where
import Common
import Data.Int (Int32, Int64)
import Data.Maybe (fromJust)
import Data.Vector.Storable qualified as Vector
import Foreign qualified
import Parse
import System.IO.Unsafe (unsafePerformIO)
-- Dummy types for FFI
data CyclicList = CyclicList
foreign import ccall unsafe "cyclic_list_from_array"
cMkCyclicList ::
Foreign.Ptr Int64 ->
Int32 ->
Foreign.Ptr CyclicList
foreign import ccall unsafe "mix"
cMix ::
Foreign.Ptr CyclicList ->
Int32 ->
IO ()
foreign import ccall unsafe "position_of_nth_value"
cPositionOfNthValue ::
Foreign.Ptr CyclicList ->
Int32 ->
Int32
foreign import ccall unsafe "value_at_position"
cValueAtPosition ::
Foreign.Ptr CyclicList ->
Int32 ->
Int64
parser :: Parser [Int]
parser = someLines int
decrypt :: Int -> [Int] -> [Int64]
decrypt rounds numbers =
let iv = Vector.fromList $ map (fromIntegral :: Int -> Int64) numbers
zeroIndex = fromJust $ Vector.elemIndex 0 iv
(dataPtr, dataLen) = Vector.unsafeToForeignPtr0 iv
groveOffsets = [1000, 2000, 3000]
in unsafePerformIO $
Foreign.withForeignPtr
dataPtr
( \ptr -> do
let cycList = cMkCyclicList ptr (fromIntegral dataLen)
cMix cycList (fromIntegral rounds)
let zeroPos = cPositionOfNthValue cycList (fromIntegral zeroIndex)
return $ map (cValueAtPosition cycList . (+ zeroPos)) groveOffsets
)
part1 :: [Int] -> Int64
part1 = sum . decrypt 1
decryptionKey :: Int
decryptionKey = 811589153
part2 :: [Int] -> Int64
part2 = sum . decrypt 10 . map (* decryptionKey)
day :: Day
day = parsecDay parser (definitive . part1, definitive . part2)