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

View File

@@ -27,6 +27,7 @@ library
hs-source-dirs: src hs-source-dirs: src
c-sources: c-sources:
src/Days/D08.c src/Days/D08.c
src/Days/D20.c
exposed-modules: exposed-modules:
Lib Lib
other-modules: other-modules:
@@ -53,6 +54,7 @@ library
Days.D17 Days.D17
Days.D18 Days.D18
Days.D19 Days.D19
Days.D20
build-depends: build-depends:
bytestring bytestring
, either , either

View File

@@ -27,6 +27,7 @@ paths =
, "./data/17.in" , "./data/17.in"
, "./data/18.in" , "./data/18.in"
, "./data/19.in" , "./data/19.in"
, "./data/20.in"
] ]
solutions :: [(Int, Day, FilePath)] solutions :: [(Int, Day, FilePath)]

View File

@@ -26,6 +26,7 @@ paths =
, "./data/17.in" , "./data/17.in"
, "./data/18.in" , "./data/18.in"
, "./data/19.in" , "./data/19.in"
, "./data/20.in"
] ]
solutions :: [(Integer, [Day], FilePath)] solutions :: [(Integer, [Day], FilePath)]

5000
data/20.in Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
{ {
devShells = forAllSystems (pkgs: with pkgs; { devShells = forAllSystems (pkgs: with pkgs; {
default = mkShell { default = (mkShell.override { stdenv = llvmPackages_16.stdenv; }) {
buildInputs = [ ghc cabal-install haskell-language-server ]; buildInputs = [ ghc cabal-install haskell-language-server ];
}; };
}); });

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)

View File

@@ -31,6 +31,7 @@ import Days.D16 qualified as D16
import Days.D17 qualified as D17 import Days.D17 qualified as D17
import Days.D18 qualified as D18 import Days.D18 qualified as D18
import Days.D19 qualified as D19 import Days.D19 qualified as D19
import Days.D20 qualified as D20
import Data.ByteString.Char8 qualified as BS import Data.ByteString.Char8 qualified as BS
import Data.Text.IO qualified as T import Data.Text.IO qualified as T
@@ -62,4 +63,5 @@ days =
, [D17.day] , [D17.day]
, [D18.day] , [D18.day]
, [D19.day] , [D19.day]
, [D20.day]
] ]