Day 20
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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
5000
data/20.in
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
305
src/Days/D20.c
Normal 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
69
src/Days/D20.hs
Normal 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)
|
||||||
@@ -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]
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user