silly
parent
20360912dd
commit
a3b5939ec0
|
@ -2,21 +2,20 @@
|
|||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug-addrsan/_deps/freetype-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug-addrsan/_deps/freetype-src/subprojects/dlg" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug-addrsan/_deps/imgui-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/freetype-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/freetype-src/subprojects/dlg" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/glfw3-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imgui-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/freetype-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/freetype-src/subprojects/dlg" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/glfw3-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-release/_deps/imgui-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo-addrsan/_deps/freetype-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo-addrsan/_deps/freetype-src/subprojects/dlg" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo-addrsan/_deps/glfw3-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo-addrsan/_deps/imgui-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo/_deps/freetype-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo/_deps/freetype-src/subprojects/dlg" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo/_deps/glfw3-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-relwithdebinfo/_deps/imgui-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/blt-with-graphics" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/blt-with-graphics/libraries/BLT" vcs="Git" />
|
||||
|
|
|
@ -49,7 +49,7 @@ macro(blt_add_project name source type)
|
|||
project(skyscrapers-ga)
|
||||
endmacro()
|
||||
|
||||
project(skyscrapers-ga VERSION 0.0.4)
|
||||
project(skyscrapers-ga VERSION 0.0.5)
|
||||
|
||||
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
|
||||
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
#pragma once
|
||||
/*
|
||||
* Copyright (C) 2024 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GENETIC_ALGORITHM_H
|
||||
#define GENETIC_ALGORITHM_H
|
||||
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
#include <skyscrapers.h>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
struct individual_t
|
||||
{
|
||||
solution_t solution;
|
||||
blt::i32 fitness = std::numeric_limits<blt::i32>::max();
|
||||
|
||||
individual_t(solution_t solution, const blt::i32 fitness): solution(std::move(solution)), fitness(fitness)
|
||||
{
|
||||
}
|
||||
|
||||
void replace(const problem_t& problem, const solution_t& new_solution)
|
||||
{
|
||||
solution = new_solution;
|
||||
fitness = solution.fitness(problem);
|
||||
}
|
||||
};
|
||||
|
||||
class genetic_algorithm
|
||||
{
|
||||
public:
|
||||
genetic_algorithm(problem_t problem, const blt::i32 individual_count, const double crossover_rate = 0.8, const double mutation_rate = 0.1):
|
||||
crossover_rate(crossover_rate), mutation_rate(mutation_rate), m_problem(std::move(problem))
|
||||
{
|
||||
for (blt::i32 i = 0; i < individual_count; i++)
|
||||
{
|
||||
solution_t solution{problem.board_size};
|
||||
solution.init(problem);
|
||||
individuals.emplace_back(solution, solution.fitness(m_problem));
|
||||
}
|
||||
}
|
||||
|
||||
void run_step();
|
||||
|
||||
[[nodiscard]] solution_t select(blt::i32 k = 5) const;
|
||||
|
||||
static std::pair<solution_t, solution_t> crossover(const individual_t& first, const individual_t& second);
|
||||
|
||||
static solution_t mutate(const individual_t& individual);
|
||||
|
||||
private:
|
||||
double crossover_rate, mutation_rate;
|
||||
problem_t m_problem;
|
||||
std::vector<individual_t> individuals;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //GENETIC_ALGORITHM_H
|
|
@ -47,7 +47,7 @@ namespace sky
|
|||
right.reserve(board_size);
|
||||
}
|
||||
|
||||
void print();
|
||||
void print() const;
|
||||
|
||||
[[nodiscard]] blt::i32 min() const // NOLINT
|
||||
{
|
||||
|
@ -56,11 +56,45 @@ namespace sky
|
|||
|
||||
[[nodiscard]] blt::i32 max() const
|
||||
{
|
||||
return board_size + 1;
|
||||
return board_size;
|
||||
}
|
||||
};
|
||||
|
||||
blt::expected<problem_t, problem_t::error_t> problem_from_file(std::string_view path);
|
||||
|
||||
struct solution_t
|
||||
{
|
||||
blt::i32 board_size;
|
||||
std::vector<blt::i32> board_data;
|
||||
|
||||
explicit solution_t(const blt::i32 board_size): board_size(board_size)
|
||||
{
|
||||
board_data.resize(board_size * board_size);
|
||||
}
|
||||
|
||||
void init(const problem_t& problem);
|
||||
|
||||
// checks to see if the row contains duplicates. zero means all good
|
||||
[[nodiscard]] blt::i32 row_incorrect_count(blt::i32 row) const;
|
||||
// checks to see if the arrows are correct for this row
|
||||
[[nodiscard]] blt::i32 row_view_count(const problem_t& problem, blt::i32 row) const;
|
||||
[[nodiscard]] blt::i32 column_incorrect_count(blt::i32 column) const;
|
||||
[[nodiscard]] blt::i32 column_view_count(const problem_t& problem, blt::i32 column) const;
|
||||
|
||||
[[nodiscard]] blt::i32 fitness(const problem_t& problem) const;
|
||||
|
||||
[[nodiscard]] blt::i32 get(const blt::i32 row, const blt::i32 column) const
|
||||
{
|
||||
return board_data[row * board_size + column];
|
||||
}
|
||||
};
|
||||
|
||||
problem_t make_test_problem();
|
||||
|
||||
solution_t make_test_solution();
|
||||
solution_t make_test_solution_bad1();
|
||||
solution_t make_test_solution_bad2();
|
||||
solution_t make_test_solution_bad3();
|
||||
}
|
||||
|
||||
#endif //SKYSCRAPERS_H
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
BOARD_SIZE: 3
|
||||
|
||||
2 1 2
|
||||
2 2
|
||||
3 1
|
||||
1 2
|
||||
1 3 2
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* <Short Description>
|
||||
* Copyright (C) 2025 Brett Terpstra
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <genetic_algorithm.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/std/random.h>
|
||||
|
||||
namespace sky {
|
||||
void genetic_algorithm::run_step()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
solution_t genetic_algorithm::select(const blt::i32 k) const
|
||||
{
|
||||
thread_local blt::hashset_t<blt::size_t> selected_indexes;
|
||||
thread_local blt::random::random_t random{std::random_device{}()};
|
||||
selected_indexes.clear();
|
||||
|
||||
blt::size_t index = 0;
|
||||
blt::i32 best_fitness = std::numeric_limits<blt::i32>::max();
|
||||
|
||||
for (blt::i32 i = 0; i < k; ++i)
|
||||
{
|
||||
blt::size_t point;
|
||||
do
|
||||
{
|
||||
point = random.get_u64(0, individuals.size());
|
||||
} while (selected_indexes.contains(point));
|
||||
selected_indexes.insert(point);
|
||||
if (individuals[point].fitness < best_fitness)
|
||||
{
|
||||
index = point;
|
||||
best_fitness = individuals[point].fitness;
|
||||
}
|
||||
}
|
||||
return individuals[index].solution;
|
||||
}
|
||||
|
||||
std::pair<solution_t, solution_t> genetic_algorithm::crossover(const individual_t& first, const individual_t& second)
|
||||
{
|
||||
}
|
||||
|
||||
solution_t genetic_algorithm::mutate(const individual_t& individual)
|
||||
{
|
||||
}
|
||||
}
|
13
src/main.cpp
13
src/main.cpp
|
@ -67,5 +67,16 @@ int main(int argc, const char** argv)
|
|||
auto& problem_d = problem.value();
|
||||
problem_d.print();
|
||||
|
||||
blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1));
|
||||
const auto test = sky::make_test_problem();
|
||||
auto sol = sky::make_test_solution();
|
||||
|
||||
test.print();
|
||||
BLT_TRACE(sol.fitness(test));
|
||||
|
||||
BLT_TRACE(sky::make_test_solution_bad1().fitness(test));
|
||||
BLT_TRACE(sky::make_test_solution_bad2().fitness(test));
|
||||
BLT_TRACE(sky::make_test_solution_bad3().fitness(test));
|
||||
|
||||
|
||||
// blt::gfx::init(blt::gfx::window_data{"My Sexy Window", init, update, destroy}.setSyncInterval(1));
|
||||
}
|
|
@ -18,11 +18,13 @@
|
|||
#include <skyscrapers.h>
|
||||
|
||||
#include <blt/fs/loader.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/std/random.h>
|
||||
|
||||
namespace sky
|
||||
{
|
||||
void problem_t::print()
|
||||
void problem_t::print() const
|
||||
{
|
||||
BLT_TRACE("Board Size: %d", board_size);
|
||||
BLT_TRACE_STREAM << "\t";
|
||||
|
@ -107,4 +109,183 @@ namespace sky
|
|||
|
||||
return problem;
|
||||
}
|
||||
|
||||
void solution_t::init(const problem_t& problem)
|
||||
{
|
||||
blt::random::random_t random{std::random_device{}()};
|
||||
for (auto& v : board_data)
|
||||
v = random.get_i32(problem.min(), problem.max() + 1);
|
||||
}
|
||||
|
||||
blt::i32 solution_t::row_incorrect_count(const blt::i32 row) const
|
||||
{
|
||||
thread_local std::vector<blt::i32> value_counts;
|
||||
value_counts.resize(board_size);
|
||||
std::memset(value_counts.data(), 0, sizeof(blt::i32) * board_size);
|
||||
|
||||
for (blt::i32 column = 0; column < board_size; column++)
|
||||
++value_counts[get(row, column) - 1];
|
||||
|
||||
blt::i32 sum = 0;
|
||||
for (const auto v : value_counts)
|
||||
sum += std::abs(v - 1);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
blt::i32 solution_t::row_view_count(const problem_t& problem, const blt::i32 row) const
|
||||
{
|
||||
blt::i32 sees_left = 0;
|
||||
blt::i32 sees_right = 0;
|
||||
|
||||
blt::i32 highest_left = 0;
|
||||
blt::i32 highest_right = 0;
|
||||
|
||||
for (blt::i32 column = 0; column < board_size; column++)
|
||||
{
|
||||
if (get(row, column) > highest_left)
|
||||
{
|
||||
++sees_left;
|
||||
highest_left = get(row, column);
|
||||
}
|
||||
}
|
||||
|
||||
for (blt::i32 column = board_size - 1; column >= 0; column--)
|
||||
{
|
||||
if (get(row, column) > highest_right)
|
||||
{
|
||||
++sees_right;
|
||||
highest_right = get(row, column);
|
||||
}
|
||||
}
|
||||
|
||||
const auto left = problem.left[row];
|
||||
const auto right = problem.right[row];
|
||||
|
||||
return std::abs(left - sees_left) + std::abs(right - sees_right);
|
||||
}
|
||||
|
||||
blt::i32 solution_t::column_view_count(const problem_t& problem, blt::i32 column) const
|
||||
{
|
||||
blt::i32 sees_top = 0;
|
||||
blt::i32 sees_bottom = 0;
|
||||
|
||||
blt::i32 highest_top = 0;
|
||||
blt::i32 highest_bottom = 0;
|
||||
|
||||
for (blt::i32 row = 0; row < board_size; row++)
|
||||
{
|
||||
if (get(row, column) > highest_top)
|
||||
{
|
||||
++sees_top;
|
||||
highest_top = get(row, column);
|
||||
}
|
||||
}
|
||||
|
||||
for (blt::i32 row = board_size - 1; row >= 0; row--)
|
||||
{
|
||||
if (get(row, column) > highest_bottom)
|
||||
{
|
||||
++sees_bottom;
|
||||
highest_bottom = get(row, column);
|
||||
}
|
||||
}
|
||||
|
||||
const auto top = problem.top[column];
|
||||
const auto bottom = problem.bottom[column];
|
||||
|
||||
return std::abs(top - sees_top) + std::abs(bottom - sees_bottom);
|
||||
}
|
||||
|
||||
blt::i32 solution_t::column_incorrect_count(const blt::i32 column) const
|
||||
{
|
||||
thread_local std::vector<blt::i32> value_counts;
|
||||
value_counts.resize(board_size);
|
||||
std::memset(value_counts.data(), 0, sizeof(blt::i32) * board_size);
|
||||
|
||||
for (blt::i32 row = 0; row < board_size; row++)
|
||||
++value_counts[get(row, column) - 1];
|
||||
|
||||
blt::i32 sum = 0;
|
||||
for (const auto v : value_counts)
|
||||
sum += std::abs(v - 1);
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
blt::i32 solution_t::fitness(const problem_t& problem) const
|
||||
{
|
||||
blt::i32 fitness = 0;
|
||||
for (blt::i32 i = 0; i < board_size; i++)
|
||||
{
|
||||
fitness += row_incorrect_count(i);
|
||||
fitness += row_view_count(problem, i);
|
||||
fitness += column_incorrect_count(i);
|
||||
fitness += column_view_count(problem, i);
|
||||
}
|
||||
return fitness;
|
||||
}
|
||||
|
||||
problem_t make_test_problem()
|
||||
{
|
||||
problem_t problem{3};
|
||||
problem.top = {2, 1, 2};
|
||||
problem.bottom = {1, 3, 2};
|
||||
problem.left = {2, 3, 1};
|
||||
problem.right = {2, 1, 2};
|
||||
|
||||
return problem;
|
||||
}
|
||||
|
||||
solution_t make_test_solution()
|
||||
{
|
||||
solution_t solution{3};
|
||||
|
||||
solution.board_data = {
|
||||
2, 3, 1,
|
||||
1, 2, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
solution_t make_test_solution_bad1()
|
||||
{
|
||||
solution_t solution{3};
|
||||
|
||||
solution.board_data = {
|
||||
2, 3, 1,
|
||||
1, 2, 3,
|
||||
1, 1, 2
|
||||
};
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
solution_t make_test_solution_bad2()
|
||||
{
|
||||
solution_t solution{3};
|
||||
|
||||
solution.board_data = {
|
||||
1, 3, 2,
|
||||
1, 2, 3,
|
||||
3, 1, 2
|
||||
};
|
||||
|
||||
return solution;
|
||||
}
|
||||
|
||||
solution_t make_test_solution_bad3()
|
||||
{
|
||||
solution_t solution{3};
|
||||
|
||||
solution.board_data = {
|
||||
3, 2, 1,
|
||||
1, 3, 2,
|
||||
3, 2, 1
|
||||
};
|
||||
|
||||
return solution;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue