Compare commits
No commits in common. "3963afe3434fa1b766d0c314d6c8d7dff8459b48" and "f46240e879a3e39fefc28a7c0f4ee667ab18856f" have entirely different histories.
3963afe343
...
f46240e879
|
@ -7,7 +7,10 @@
|
||||||
namespace BAN
|
namespace BAN
|
||||||
{
|
{
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>, bool STABLE = true>
|
template<typename Container>
|
||||||
|
class HashMapIterator;
|
||||||
|
|
||||||
|
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
||||||
class HashMap
|
class HashMap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -32,12 +35,12 @@ namespace BAN
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HashMap() = default;
|
HashMap() = default;
|
||||||
HashMap(const HashMap<Key, T, HASH, STABLE>&);
|
HashMap(const HashMap<Key, T, HASH>&);
|
||||||
HashMap(HashMap<Key, T, HASH, STABLE>&&);
|
HashMap(HashMap<Key, T, HASH>&&);
|
||||||
~HashMap();
|
~HashMap();
|
||||||
|
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(const HashMap<Key, T, HASH, STABLE>&);
|
HashMap<Key, T, HASH>& operator=(const HashMap<Key, T, HASH>&);
|
||||||
HashMap<Key, T, HASH, STABLE>& operator=(HashMap<Key, T, HASH, STABLE>&&);
|
HashMap<Key, T, HASH>& operator=(HashMap<Key, T, HASH>&&);
|
||||||
|
|
||||||
ErrorOr<void> insert(const Key&, const T&);
|
ErrorOr<void> insert(const Key&, const T&);
|
||||||
ErrorOr<void> insert(const Key&, T&&);
|
ErrorOr<void> insert(const Key&, T&&);
|
||||||
|
@ -74,26 +77,26 @@ namespace BAN
|
||||||
friend iterator;
|
friend iterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(const HashMap<Key, T, HASH, STABLE>& other)
|
HashMap<Key, T, HASH>::HashMap(const HashMap<Key, T, HASH>& other)
|
||||||
{
|
{
|
||||||
*this = other;
|
*this = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::HashMap(HashMap<Key, T, HASH, STABLE>&& other)
|
HashMap<Key, T, HASH>::HashMap(HashMap<Key, T, HASH>&& other)
|
||||||
{
|
{
|
||||||
*this = move(other);
|
*this = move(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>::~HashMap()
|
HashMap<Key, T, HASH>::~HashMap()
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(const HashMap<Key, T, HASH, STABLE>& other)
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(const HashMap<Key, T, HASH>& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = other.m_buckets;
|
m_buckets = other.m_buckets;
|
||||||
|
@ -101,8 +104,8 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
HashMap<Key, T, HASH, STABLE>& HashMap<Key, T, HASH, STABLE>::operator=(HashMap<Key, T, HASH, STABLE>&& other)
|
HashMap<Key, T, HASH>& HashMap<Key, T, HASH>::operator=(HashMap<Key, T, HASH>&& other)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
m_buckets = move(other.m_buckets);
|
m_buckets = move(other.m_buckets);
|
||||||
|
@ -111,21 +114,21 @@ namespace BAN
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, const T& value)
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, const T& value)
|
||||||
{
|
{
|
||||||
return insert(key, move(T(value)));
|
return insert(key, move(T(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::insert(const Key& key, T&& value)
|
ErrorOr<void> HashMap<Key, T, HASH>::insert(const Key& key, T&& value)
|
||||||
{
|
{
|
||||||
return emplace(key, move(value));
|
return emplace(key, move(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::emplace(const Key& key, Args&&... args)
|
ErrorOr<void> HashMap<Key, T, HASH>::emplace(const Key& key, Args&&... args)
|
||||||
{
|
{
|
||||||
ASSERT(!contains(key));
|
ASSERT(!contains(key));
|
||||||
TRY(rebucket(m_size + 1));
|
TRY(rebucket(m_size + 1));
|
||||||
|
@ -137,15 +140,15 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::reserve(size_type size)
|
ErrorOr<void> HashMap<Key, T, HASH>::reserve(size_type size)
|
||||||
{
|
{
|
||||||
TRY(rebucket(size));
|
TRY(rebucket(size));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
void HashMap<Key, T, HASH, STABLE>::remove(const Key& key)
|
void HashMap<Key, T, HASH>::remove(const Key& key)
|
||||||
{
|
{
|
||||||
if (empty()) return;
|
if (empty()) return;
|
||||||
auto& bucket = get_bucket(key);
|
auto& bucket = get_bucket(key);
|
||||||
|
@ -160,15 +163,15 @@ namespace BAN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
void HashMap<Key, T, HASH, STABLE>::clear()
|
void HashMap<Key, T, HASH>::clear()
|
||||||
{
|
{
|
||||||
m_buckets.clear();
|
m_buckets.clear();
|
||||||
m_size = 0;
|
m_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key)
|
T& HashMap<Key, T, HASH>::operator[](const Key& key)
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
ASSERT(!empty());
|
||||||
auto& bucket = get_bucket(key);
|
auto& bucket = get_bucket(key);
|
||||||
|
@ -178,8 +181,8 @@ namespace BAN
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
const T& HashMap<Key, T, HASH, STABLE>::operator[](const Key& key) const
|
const T& HashMap<Key, T, HASH>::operator[](const Key& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!empty());
|
ASSERT(!empty());
|
||||||
const auto& bucket = get_bucket(key);
|
const auto& bucket = get_bucket(key);
|
||||||
|
@ -189,8 +192,8 @@ namespace BAN
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
bool HashMap<Key, T, HASH, STABLE>::contains(const Key& key) const
|
bool HashMap<Key, T, HASH>::contains(const Key& key) const
|
||||||
{
|
{
|
||||||
if (empty()) return false;
|
if (empty()) return false;
|
||||||
const auto& bucket = get_bucket(key);
|
const auto& bucket = get_bucket(key);
|
||||||
|
@ -200,20 +203,20 @@ namespace BAN
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
bool HashMap<Key, T, HASH, STABLE>::empty() const
|
bool HashMap<Key, T, HASH>::empty() const
|
||||||
{
|
{
|
||||||
return m_size == 0;
|
return m_size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
typename HashMap<Key, T, HASH, STABLE>::size_type HashMap<Key, T, HASH, STABLE>::size() const
|
typename HashMap<Key, T, HASH>::size_type HashMap<Key, T, HASH>::size() const
|
||||||
{
|
{
|
||||||
return m_size;
|
return m_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
ErrorOr<void> HashMap<Key, T, HASH, STABLE>::rebucket(size_type bucket_count)
|
ErrorOr<void> HashMap<Key, T, HASH>::rebucket(size_type bucket_count)
|
||||||
{
|
{
|
||||||
if (m_buckets.size() >= bucket_count)
|
if (m_buckets.size() >= bucket_count)
|
||||||
return {};
|
return {};
|
||||||
|
@ -222,21 +225,16 @@ namespace BAN
|
||||||
Vector<LinkedList<Entry>> new_buckets;
|
Vector<LinkedList<Entry>> new_buckets;
|
||||||
if (new_buckets.resize(new_bucket_count).is_error())
|
if (new_buckets.resize(new_bucket_count).is_error())
|
||||||
return Error::from_errno(ENOMEM);
|
return Error::from_errno(ENOMEM);
|
||||||
|
|
||||||
if constexpr(STABLE)
|
// NOTE: We have to copy the old entries to the new entries and not move
|
||||||
|
// since we might run out of memory half way through.
|
||||||
|
for (auto& bucket : m_buckets)
|
||||||
{
|
{
|
||||||
// NOTE: We have to copy the old entries to the new entries and not move
|
for (Entry& entry : bucket)
|
||||||
// since we might run out of memory half way through.
|
|
||||||
for (auto& bucket : m_buckets)
|
|
||||||
{
|
{
|
||||||
for (Entry& entry : bucket)
|
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
|
||||||
{
|
if (new_buckets[bucket_index].push_back(entry).is_error())
|
||||||
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
|
return Error::from_errno(ENOMEM);
|
||||||
if constexpr(STABLE)
|
|
||||||
TRY(new_buckets[bucket_index].push_back(entry));
|
|
||||||
else
|
|
||||||
TRY(new_buckets[bucket_index].push_back(BAN::move(entry)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,27 +242,20 @@ namespace BAN
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key)
|
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Key, typename T, typename HASH, bool STABLE>
|
template<typename Key, typename T, typename HASH>
|
||||||
const LinkedList<typename HashMap<Key, T, HASH, STABLE>::Entry>& HashMap<Key, T, HASH, STABLE>::get_bucket(const Key& key) const
|
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
|
||||||
{
|
{
|
||||||
ASSERT(!m_buckets.empty());
|
ASSERT(!m_buckets.empty());
|
||||||
auto index = HASH()(key) % m_buckets.size();
|
auto index = HASH()(key) % m_buckets.size();
|
||||||
return m_buckets[index];
|
return m_buckets[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unstable hash map moves values between container during rebucketing.
|
|
||||||
// This means that if insertion to map fails, elements could be in invalid state
|
|
||||||
// and that container is no longer usable. This is better if either way you are
|
|
||||||
// going to stop using the hash map after insertion fails.
|
|
||||||
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
|
|
||||||
using HashMapUnstable = HashMap<Key, T, HASH, false>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,7 @@ int memcmp(const void* s1, const void* s2, size_t n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((optimize("-O0")))
|
void* memcpy(void* dstp, const void* srcp, size_t n)
|
||||||
void* memcpy(void* __restrict__ dstp, const void* __restrict__ srcp, size_t n)
|
|
||||||
{
|
{
|
||||||
unsigned char* dst = static_cast<unsigned char*>(dstp);
|
unsigned char* dst = static_cast<unsigned char*>(dstp);
|
||||||
const unsigned char* src = static_cast<const unsigned char*>(srcp);
|
const unsigned char* src = static_cast<const unsigned char*>(srcp);
|
||||||
|
@ -46,7 +45,6 @@ void* memmove(void* destp, const void* srcp, size_t n)
|
||||||
return destp;
|
return destp;
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((optimize("-O0")))
|
|
||||||
void* memset(void* s, int c, size_t n)
|
void* memset(void* s, int c, size_t n)
|
||||||
{
|
{
|
||||||
unsigned char* p = static_cast<unsigned char*>(s);
|
unsigned char* p = static_cast<unsigned char*>(s);
|
||||||
|
@ -146,7 +144,6 @@ char* strndup(const char* str, size_t size)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__attribute__((optimize("-O0")))
|
|
||||||
size_t strlen(const char* str)
|
size_t strlen(const char* str)
|
||||||
{
|
{
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
|
@ -183,7 +183,7 @@ int execve(const char* pathname, char* const argv[], char* const envp[])
|
||||||
int execvp(const char* file, char* const argv[])
|
int execvp(const char* file, char* const argv[])
|
||||||
{
|
{
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
const char* pathname = NULL;
|
const char* pathname = file;
|
||||||
|
|
||||||
// do path resolution if file doesn't contain /
|
// do path resolution if file doesn't contain /
|
||||||
if (strchr(file, '/') == nullptr)
|
if (strchr(file, '/') == nullptr)
|
||||||
|
@ -218,16 +218,6 @@ int execvp(const char* file, char* const argv[])
|
||||||
cur++;
|
cur++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
pathname = file;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pathname)
|
|
||||||
{
|
|
||||||
errno = ENOENT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return execve(pathname, argv, environ);
|
return execve(pathname, argv, environ);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ set(AOC2023_PROJECTS
|
||||||
day12
|
day12
|
||||||
day13
|
day13
|
||||||
day14
|
day14
|
||||||
day15
|
|
||||||
day16
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023)
|
set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023)
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.26)
|
|
||||||
|
|
||||||
project(aoc2023_day15 CXX)
|
|
||||||
|
|
||||||
set(SOURCES
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(aoc2023_day15 ${SOURCES})
|
|
||||||
target_compile_options(aoc2023_day15 PUBLIC -O2 -g)
|
|
||||||
target_link_libraries(aoc2023_day15 PUBLIC libc ban)
|
|
||||||
|
|
||||||
add_dependencies(aoc2023_day15 libc-install ban-install)
|
|
||||||
|
|
||||||
add_custom_target(aoc2023_day15-install
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day15 ${BANAN_AOC2023_BIN}/day15
|
|
||||||
DEPENDS aoc2023_day15
|
|
||||||
DEPENDS aoc2023_always
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(aoc2023 aoc2023_day15)
|
|
||||||
add_dependencies(aoc2023-install aoc2023_day15-install)
|
|
|
@ -1,150 +0,0 @@
|
||||||
#include <BAN/Array.h>
|
|
||||||
#include <BAN/LinkedList.h>
|
|
||||||
#include <BAN/String.h>
|
|
||||||
#include <BAN/StringView.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
using i8 = int8_t;
|
|
||||||
using i16 = int16_t;
|
|
||||||
using i32 = int32_t;
|
|
||||||
using i64 = int64_t;
|
|
||||||
|
|
||||||
using u8 = uint8_t;
|
|
||||||
using u16 = uint16_t;
|
|
||||||
using u32 = uint32_t;
|
|
||||||
using u64 = uint64_t;
|
|
||||||
|
|
||||||
i64 parse_i64(BAN::StringView string)
|
|
||||||
{
|
|
||||||
i64 result = 0;
|
|
||||||
for (char c : string)
|
|
||||||
result = (result * 10) + (c - '0');
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Vector<BAN::StringView> parse_instructions(FILE* fp)
|
|
||||||
{
|
|
||||||
static BAN::String line;
|
|
||||||
|
|
||||||
char buffer[128];
|
|
||||||
while (fgets(buffer, sizeof(buffer), fp))
|
|
||||||
{
|
|
||||||
BAN::StringView buffer_sv(buffer);
|
|
||||||
MUST(line.append(buffer_sv));
|
|
||||||
if (buffer_sv.back() == '\n')
|
|
||||||
{
|
|
||||||
line.pop_back();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MUST(line.sv().split(','));
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 calculate_hash(BAN::StringView string)
|
|
||||||
{
|
|
||||||
i64 result = 0;
|
|
||||||
for (char c : string)
|
|
||||||
result = ((result + c) * 17) % 256;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 puzzle1(FILE* fp)
|
|
||||||
{
|
|
||||||
auto instructions = parse_instructions(fp);
|
|
||||||
|
|
||||||
i64 result = 0;
|
|
||||||
for (auto insn : instructions)
|
|
||||||
result += calculate_hash(insn);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 puzzle2(FILE* fp)
|
|
||||||
{
|
|
||||||
struct Entry
|
|
||||||
{
|
|
||||||
BAN::String label;
|
|
||||||
i64 focal_length;
|
|
||||||
};
|
|
||||||
using Box = BAN::LinkedList<Entry>;
|
|
||||||
|
|
||||||
auto instructions = parse_instructions(fp);
|
|
||||||
|
|
||||||
BAN::Array<Box, 256> boxes;
|
|
||||||
|
|
||||||
for (auto insn : instructions)
|
|
||||||
{
|
|
||||||
if (insn.back() == '-')
|
|
||||||
{
|
|
||||||
auto label = insn.substring(0, insn.size() - 1);
|
|
||||||
i64 hash = calculate_hash(label);
|
|
||||||
|
|
||||||
for (auto it = boxes[hash].begin(); it != boxes[hash].end(); it++)
|
|
||||||
{
|
|
||||||
if (it->label == label)
|
|
||||||
{
|
|
||||||
boxes[hash].remove(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto temp = MUST(insn.split('='));
|
|
||||||
|
|
||||||
auto label = temp[0];
|
|
||||||
auto focal_length = parse_i64(temp[1]);
|
|
||||||
i64 hash = calculate_hash(label);
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
for (auto it = boxes[hash].begin(); it != boxes[hash].end(); it++)
|
|
||||||
{
|
|
||||||
if (it->label == label)
|
|
||||||
{
|
|
||||||
it->focal_length = focal_length;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
MUST(boxes[hash].emplace_back(label, focal_length));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 result = 0;
|
|
||||||
for (size_t i = 0; i < boxes.size(); i++)
|
|
||||||
{
|
|
||||||
size_t slot = 0;
|
|
||||||
for (auto it = boxes[i].begin(); it != boxes[i].end(); it++, slot++)
|
|
||||||
result += (i + 1) * (slot + 1) * it->focal_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
const char* file_path = "/usr/share/aoc2023/day15_input.txt";
|
|
||||||
|
|
||||||
if (argc >= 2)
|
|
||||||
file_path = argv[1];
|
|
||||||
|
|
||||||
FILE* fp = fopen(file_path, "r");
|
|
||||||
if (fp == nullptr)
|
|
||||||
{
|
|
||||||
perror("fopen");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
|
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
|
|
||||||
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 3.26)
|
|
||||||
|
|
||||||
project(aoc2023_day16 CXX)
|
|
||||||
|
|
||||||
set(SOURCES
|
|
||||||
main.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(aoc2023_day16 ${SOURCES})
|
|
||||||
target_compile_options(aoc2023_day16 PUBLIC -O2 -g)
|
|
||||||
target_link_libraries(aoc2023_day16 PUBLIC libc ban)
|
|
||||||
|
|
||||||
add_dependencies(aoc2023_day16 libc-install ban-install)
|
|
||||||
|
|
||||||
add_custom_target(aoc2023_day16-install
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day16 ${BANAN_AOC2023_BIN}/day16
|
|
||||||
DEPENDS aoc2023_day16
|
|
||||||
DEPENDS aoc2023_always
|
|
||||||
)
|
|
||||||
|
|
||||||
add_dependencies(aoc2023 aoc2023_day16)
|
|
||||||
add_dependencies(aoc2023-install aoc2023_day16-install)
|
|
|
@ -1,232 +0,0 @@
|
||||||
#include <BAN/HashSet.h>
|
|
||||||
#include <BAN/StringView.h>
|
|
||||||
#include <BAN/Vector.h>
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
using i8 = int8_t;
|
|
||||||
using i16 = int16_t;
|
|
||||||
using i32 = int32_t;
|
|
||||||
using i64 = int64_t;
|
|
||||||
|
|
||||||
using u8 = uint8_t;
|
|
||||||
using u16 = uint16_t;
|
|
||||||
using u32 = uint32_t;
|
|
||||||
using u64 = uint64_t;
|
|
||||||
|
|
||||||
enum class Tile { Empty, PositiveMirror, NegativeMirror, HorizontalSplitter, VerticalSplitter };
|
|
||||||
enum class Direction { North, South, East, West };
|
|
||||||
|
|
||||||
using Grid = BAN::Vector<BAN::Vector<Tile>>;
|
|
||||||
|
|
||||||
struct Position
|
|
||||||
{
|
|
||||||
i64 y;
|
|
||||||
i64 x;
|
|
||||||
Direction dir;
|
|
||||||
|
|
||||||
bool operator==(const Position& other) const
|
|
||||||
{
|
|
||||||
return x == other.x && y == other.y && dir == other.dir;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct PositionHash
|
|
||||||
{
|
|
||||||
BAN::hash_t operator()(Position position) const
|
|
||||||
{
|
|
||||||
return BAN::hash<i64>()((position.y << 32) | position.x) ^ BAN::hash<i8>()(static_cast<i8>(position.dir));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Grid parse_grid(FILE* fp)
|
|
||||||
{
|
|
||||||
Grid grid;
|
|
||||||
|
|
||||||
auto char_to_tile =
|
|
||||||
[](char c)
|
|
||||||
{
|
|
||||||
if (c == '.')
|
|
||||||
return Tile::Empty;
|
|
||||||
if (c == '/')
|
|
||||||
return Tile::PositiveMirror;
|
|
||||||
if (c == '\\')
|
|
||||||
return Tile::NegativeMirror;
|
|
||||||
if (c == '-')
|
|
||||||
return Tile::HorizontalSplitter;
|
|
||||||
if (c == '|')
|
|
||||||
return Tile::VerticalSplitter;
|
|
||||||
ASSERT_NOT_REACHED();
|
|
||||||
};
|
|
||||||
|
|
||||||
char buffer[128];
|
|
||||||
while (fgets(buffer, sizeof(buffer), fp))
|
|
||||||
{
|
|
||||||
BAN::StringView line(buffer);
|
|
||||||
ASSERT(line.back() == '\n');
|
|
||||||
line = line.substring(0, line.size() - 1);
|
|
||||||
if (line.empty())
|
|
||||||
break;
|
|
||||||
|
|
||||||
MUST(grid.emplace_back(line.size()));
|
|
||||||
for (size_t i = 0; i < line.size(); i++)
|
|
||||||
grid.back()[i] = char_to_tile(line[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
BAN::Vector<Position> get_next_positions(Position position, const Grid& grid)
|
|
||||||
{
|
|
||||||
auto tile = grid[position.y][position.x];
|
|
||||||
|
|
||||||
BAN::Vector<Position> next_positions;
|
|
||||||
|
|
||||||
switch (tile)
|
|
||||||
{
|
|
||||||
case Tile::Empty:
|
|
||||||
switch (position.dir)
|
|
||||||
{
|
|
||||||
case Direction::North: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
|
|
||||||
case Direction::South: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
|
|
||||||
case Direction::West: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
|
|
||||||
case Direction::East: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Tile::PositiveMirror:
|
|
||||||
switch (position.dir)
|
|
||||||
{
|
|
||||||
case Direction::North: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
|
|
||||||
case Direction::South: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
|
|
||||||
case Direction::West: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
|
|
||||||
case Direction::East: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Tile::NegativeMirror:
|
|
||||||
switch (position.dir)
|
|
||||||
{
|
|
||||||
case Direction::North: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
|
|
||||||
case Direction::South: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
|
|
||||||
case Direction::West: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
|
|
||||||
case Direction::East: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Tile::HorizontalSplitter:
|
|
||||||
switch (position.dir)
|
|
||||||
{
|
|
||||||
case Direction::North:
|
|
||||||
case Direction::South:
|
|
||||||
MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West));
|
|
||||||
MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East));
|
|
||||||
break;
|
|
||||||
case Direction::West: MUST(next_positions.emplace_back(position.y, position.x - 1, Direction::West)); break;
|
|
||||||
case Direction::East: MUST(next_positions.emplace_back(position.y, position.x + 1, Direction::East)); break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Tile::VerticalSplitter:
|
|
||||||
switch (position.dir)
|
|
||||||
{
|
|
||||||
case Direction::North: MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North)); break;
|
|
||||||
case Direction::South: MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South)); break;
|
|
||||||
case Direction::West:
|
|
||||||
case Direction::East:
|
|
||||||
MUST(next_positions.emplace_back(position.y - 1, position.x, Direction::North));
|
|
||||||
MUST(next_positions.emplace_back(position.y + 1, position.x, Direction::South));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < next_positions.size();)
|
|
||||||
{
|
|
||||||
if (next_positions[i].y < 0 || next_positions[i].y >= (i64)grid.size())
|
|
||||||
next_positions.remove(i);
|
|
||||||
else if (next_positions[i].x < 0 || next_positions[i].x >= (i64)grid.front().size())
|
|
||||||
next_positions.remove(i);
|
|
||||||
else
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return next_positions;
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 count_energized_tiles(const Grid& grid, Position start)
|
|
||||||
{
|
|
||||||
BAN::HashSet<Position, PositionHash> visited;
|
|
||||||
BAN::HashSet<Position, PositionHash> energized;
|
|
||||||
|
|
||||||
BAN::Vector<Position> current_positions;
|
|
||||||
MUST(current_positions.push_back(start));
|
|
||||||
MUST(visited.insert(current_positions.front()));
|
|
||||||
|
|
||||||
while (!current_positions.empty())
|
|
||||||
{
|
|
||||||
auto position = current_positions.back();
|
|
||||||
current_positions.pop_back();
|
|
||||||
|
|
||||||
MUST(energized.insert({ position.y, position.x, Direction::North }));
|
|
||||||
|
|
||||||
auto next_positions = get_next_positions(position, grid);
|
|
||||||
for (auto next : next_positions)
|
|
||||||
{
|
|
||||||
if (visited.contains(next))
|
|
||||||
continue;
|
|
||||||
MUST(visited.insert(next));
|
|
||||||
MUST(current_positions.push_back(next));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return energized.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 puzzle1(FILE* fp)
|
|
||||||
{
|
|
||||||
auto grid = parse_grid(fp);
|
|
||||||
return count_energized_tiles(grid, { 0, 0, Direction::East });
|
|
||||||
}
|
|
||||||
|
|
||||||
i64 puzzle2(FILE* fp)
|
|
||||||
{
|
|
||||||
auto grid = parse_grid(fp);
|
|
||||||
|
|
||||||
i64 max_energized = 0;
|
|
||||||
|
|
||||||
for (i64 y = 0; y < (i64)grid.size(); y++)
|
|
||||||
{
|
|
||||||
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { y, 0, Direction::East }));
|
|
||||||
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { y, (i64)grid.front().size() - 1, Direction::West }));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i64 x = 0; x < (i64)grid.front().size(); x++)
|
|
||||||
{
|
|
||||||
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { 0, x, Direction::South }));
|
|
||||||
max_energized = BAN::Math::max(max_energized, count_energized_tiles(grid, { (i64)grid.size() - 1, x, Direction::North }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return max_energized;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
const char* file_path = "/usr/share/aoc2023/day16_input.txt";
|
|
||||||
|
|
||||||
if (argc >= 2)
|
|
||||||
file_path = argv[1];
|
|
||||||
|
|
||||||
FILE* fp = fopen(file_path, "r");
|
|
||||||
if (fp == nullptr)
|
|
||||||
{
|
|
||||||
perror("fopen");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("puzzle1: %" PRId64 "\n", puzzle1(fp));
|
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_SET);
|
|
||||||
|
|
||||||
printf("puzzle2: %" PRId64 "\n", puzzle2(fp));
|
|
||||||
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
day*_input.txt
|
|
File diff suppressed because one or more lines are too long
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
wget --no-cookies --header "Cookie: session=$AOC_SESSION" https://adventofcode.com/2023/day/$1/input -O day$1_input.txt
|
|
Loading…
Reference in New Issue