Compare commits

..

7 Commits

Author SHA1 Message Date
Bananymous d824449ddb AOC2023: Use quick sort in solution 2023-12-07 11:55:28 +02:00
Bananymous 8aa137bdfe BAN: implement quick sort and test for it 2023-12-07 11:55:28 +02:00
Bananymous d37b59b2df BAN: Fix simple iterator operator--() 2023-12-07 11:55:28 +02:00
Bananymous 412aa05feb BAN: implement exchange sort and test for it 2023-12-07 11:55:28 +02:00
Bananymous 44358a9182 BAN: add value_type to iterators 2023-12-07 10:15:18 +02:00
Bananymous 8516f04467 AOC2023: optimize hand score calculation 2023-12-07 09:26:17 +02:00
Bananymous 045a96009e BAN: implement basic swap
This will be improved, currently just works on general type T and
moves values between arguments.
2023-12-07 09:26:17 +02:00
7 changed files with 175 additions and 53 deletions

View File

@ -8,6 +8,9 @@ namespace BAN
template<typename T, typename Container, bool CONST>
class IteratorSimpleGeneral
{
public:
using value_type = T;
public:
IteratorSimpleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
@ -56,7 +59,8 @@ namespace BAN
IteratorSimpleGeneral& operator--()
{
ASSERT(m_pointer);
return --m_pointer;
--m_pointer;
return *this;
}
IteratorSimpleGeneral operator--(int)
{
@ -102,6 +106,8 @@ namespace BAN
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
using value_type = T;
public:
IteratorDoubleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>

57
BAN/include/BAN/Sort.h Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include <BAN/Swap.h>
#include <BAN/Traits.h>
namespace BAN
{
template<typename It, typename Comp = less<typename It::value_type>>
void sort_exchange(It begin, It end, Comp comp = {})
{
for (It lhs = begin; lhs != end; ++lhs)
for (It rhs = lhs; ++rhs != end;)
if (!comp(*lhs, *rhs))
swap(*lhs, *rhs);
}
namespace detail
{
template<typename It, typename Comp>
It sort_quick_partition(It begin, It end, Comp comp)
{
It pivot = end; --pivot;
It it1 = begin;
for (It it2 = begin; it2 != pivot; ++it2)
{
if (comp(*it2, *pivot))
{
swap(*it1, *it2);
++it1;
}
}
swap(*it1, *pivot);
return it1;
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort_quick(It begin, It end, Comp comp = {})
{
{
It it = begin;
if (it == end || ++it == end)
return;
}
It mid = detail::sort_quick_partition(begin, end, comp);
sort_quick(begin, mid, comp);
sort_quick(++mid, end, comp);
}
}

16
BAN/include/BAN/Swap.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include <BAN/Move.h>
namespace BAN
{
template<typename T>
void swap(T& lhs, T& rhs)
{
T tmp = move(lhs);
lhs = move(rhs);
rhs = move(tmp);
}
}

View File

@ -28,6 +28,7 @@ set(USERSPACE_PROJECTS
test
test-globals
test-framebuffer
test-sort
touch
u8sum
whoami

View File

@ -1,4 +1,5 @@
#include <BAN/Vector.h>
#include <BAN/Sort.h>
#include <BAN/String.h>
#include <ctype.h>
@ -62,44 +63,40 @@ i64 hand_score(const Hand& hand, bool joker)
{
if (isdigit(c))
cnt[c - '0' + 0]++;
else if (c == 'J')
else if (joker && c == 'J')
joker_count++;
else
cnt[c - 'A' + 10]++;
}
if (!joker)
i64 freq_max1 = 0;
i64 freq_max2 = 0;
for (size_t i = 0; i < 36; i++)
{
cnt['J' - 'A' + 10] = joker_count;
joker_count = 0;
if (cnt[i] > freq_max1)
{
freq_max2 = freq_max1;
freq_max1 = cnt[i];
}
else if (cnt[i] > freq_max2)
{
freq_max2 = cnt[i];
}
}
freq_max1 += joker_count;
for (size_t i = 0; i < 36; i++)
if (cnt[i] + joker_count >= 5)
return 6'000'000 + hand_score_no_type(hand, joker);
for (size_t i = 0; i < 36; i++)
if (cnt[i] + joker_count >= 4)
return 5'000'000 + hand_score_no_type(hand, joker);
for (size_t i = 0; i < 36; i++)
for (size_t j = 0; j < 36; j++)
if (i != j && cnt[i] + joker_count >= 3 && cnt[j] >= 2)
return 4'000'000 + hand_score_no_type(hand, joker);
for (size_t i = 0; i < 36; i++)
if (cnt[i] + joker_count >= 3)
return 3'000'000 + hand_score_no_type(hand, joker);
for (size_t i = 0; i < 36; i++)
for (size_t j = 0; j < 36; j++)
if (i != j && cnt[i] + joker_count >= 2 && cnt[j] >= 2)
return 2'000'000 + hand_score_no_type(hand, joker);
for (size_t i = 0; i < 36; i++)
if (cnt[i] + joker_count >= 2)
return 1'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 5)
return 6'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 4)
return 5'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 3 && freq_max2 == 2)
return 4'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 3)
return 3'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 2 && freq_max2 == 2)
return 2'000'000 + hand_score_no_type(hand, joker);
if (freq_max1 == 2)
return 1'000'000 + hand_score_no_type(hand, joker);
return hand_score_no_type(hand, joker);
}
@ -113,33 +110,21 @@ i64 puzzle(FILE* fp, bool joker)
BAN::StringView line(buffer);
if (line.size() < 7)
continue;
Hand hand;
hand.hand = line.substring(0, 5);
hand.bid = parse_i64(line.substring(6));
MUST(hands.push_back(hand));
MUST(hands.emplace_back(
line.substring(0, 5),
parse_i64(line.substring(6))
));
}
// Very slow sorting algorithm
for (size_t i = 0; i < hands.size(); i++)
{
i64 l_score = hand_score(hands[i], joker);
for (size_t j = i + 1; j < hands.size(); j++)
{
i64 r_score = hand_score(hands[j], joker);
if (r_score > l_score)
{
Hand tmp = BAN::move(hands[i]);
hands[i] = BAN::move(hands[j]);
hands[j] = BAN::move(tmp);
l_score = r_score;
}
BAN::sort_quick(hands.begin(), hands.end(),
[joker] (const Hand& lhs, const Hand& rhs) {
return hand_score(lhs, joker) < hand_score(rhs, joker);
}
}
);
i64 score = 0;
for (size_t i = 0; i < hands.size(); i++)
score += (hands.size() - i) * hands[i].bid;
score += (i + 1) * hands[i].bid;
return score;
}

View File

@ -0,0 +1,16 @@
cmake_minimum_required(VERSION 3.26)
project(test-sort CXX)
set(SOURCES
main.cpp
)
add_executable(test-sort ${SOURCES})
target_compile_options(test-sort PUBLIC -O2 -g)
target_link_libraries(test-sort PUBLIC libc)
add_custom_target(test-sort-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/test-sort ${BANAN_BIN}/
DEPENDS test-sort
)

View File

@ -0,0 +1,41 @@
#include <BAN/Vector.h>
#include <BAN/Sort.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
template<typename T>
bool is_sorted(BAN::Vector<T>& vec)
{
for (size_t i = 0; i < vec.size() - 1; i++)
if (vec[i] > vec[i + 1])
return false;
return true;
}
#define CURRENT_NS() ({ timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts); ts.tv_sec * 1'000'000'000 + ts.tv_nsec; })
#define TEST(name, function, count) do { \
BAN::Vector<int> ivec(count, 0); \
for (int& i : ivec) \
i = rand() % 100; \
uint64_t start_ns = CURRENT_NS(); \
function(ivec.begin(), ivec.end()); \
uint64_t end_ns = CURRENT_NS(); \
uint64_t dur_us = (end_ns - start_ns) / 1000; \
printf(name " (" #count "): %s\n", is_sorted(ivec) ? "success" : "fail"); \
printf(" took %" PRIu64 ".%03" PRIu64 " ms\n", dur_us / 1000, dur_us % 1000); \
} while (0)
int main()
{
srand(time(0));
TEST("exchange sort", BAN::sort_exchange, 100);
TEST("exchange sort", BAN::sort_exchange, 1000);
TEST("exchange sort", BAN::sort_exchange, 10000);
TEST("quick sort", BAN::sort_quick, 100);
TEST("quick sort", BAN::sort_quick, 1000);
TEST("quick sort", BAN::sort_quick, 10000);
}