-
-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add more game of life implementations and tests
- Loading branch information
Showing
11 changed files
with
962 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
*~ | ||
callgrind.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
#!/bin/bash | ||
|
||
# This script will time each executable in a directory 5 times, average the times, and report the average timed run for each executable | ||
|
||
|
||
# Loop through all executables in the directory | ||
for executable in *; do | ||
|
||
# Skip any files that have an extension | ||
if [[ "$executable" == *.* ]]; then | ||
continue | ||
fi | ||
|
||
# Skip any files that do not have executable bit set | ||
if [[ ! -x "$executable" ]]; then | ||
continue | ||
fi | ||
|
||
# Get the file name | ||
filename=$(basename "$executable") | ||
|
||
# Print the executable name | ||
echo "Executable: $filename" | ||
|
||
# Create a variable to hold the total time | ||
total_time=0 | ||
total_ram=0 | ||
|
||
# Loop five times | ||
for i in {1..5}; do | ||
# Time the executable and save the output to a variable | ||
run_time=$(/usr/bin/time -f "%e %M" "./$executable" 2>&1 1>/dev/null ) | ||
# Extract the time from the output | ||
time=$(echo "$run_time" | awk '{print $1}') | ||
ram=$(echo "$run_time" | awk '{print $2}') | ||
# Add the time to the total | ||
total_time=$(echo "$total_time + $time" | bc) | ||
total_ram=$(echo "$total_ram + $ram" | bc) | ||
done | ||
|
||
# Calculate the average time | ||
average_time=$(echo "$total_time / 5" | bc -l) | ||
average_ram=$(echo "$total_ram / 5" | bc -l) | ||
|
||
# Print the average time | ||
echo "Average time: $average_time" | ||
echo "Average RAM usage: $average_ram" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#!/bin/bash | ||
|
||
# Bash script to compile each c++ file into its own executable | ||
|
||
# Loop over each file in the directory | ||
for file in *.cpp | ||
do | ||
# Compile file into an executable, using output filename as the cpp filename | ||
g++ $file -o ${file%.cpp} -O3 -march=native -std=c++23 | ||
done |
137 changes: 137 additions & 0 deletions
137
python/conway_game_of_life/larger_tests/life-constexpr-initial-state.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
#include <algorithm> | ||
#include <array> | ||
#include <cstdio> | ||
#include <type_traits> | ||
#include <vector> | ||
#include <fmt/format.h> | ||
|
||
#include "parameters.hpp" | ||
|
||
// necessary to keep the same algorithm as Python | ||
constexpr auto floor_modulo(auto dividend, auto divisor) | ||
{ | ||
return ((dividend % divisor) + divisor) % divisor; | ||
} | ||
|
||
using index_t = std::make_signed_t<std::size_t>; | ||
|
||
struct Point | ||
{ | ||
index_t x; | ||
index_t y; | ||
|
||
[[nodiscard]] constexpr Point operator+(Point rhs) const | ||
{ | ||
return Point{ x + rhs.x, y + rhs.y }; | ||
} | ||
}; | ||
|
||
|
||
// if we wanted to push this further, we would make the width and height compile-time constants | ||
// that is for a future episode. | ||
template<std::size_t Width, std::size_t Height> | ||
struct Automata | ||
{ | ||
|
||
constexpr auto width() const | ||
{ | ||
return Width; | ||
} | ||
|
||
constexpr auto height() const | ||
{ | ||
return Height; | ||
} | ||
|
||
std::array<bool, 9> born; | ||
std::array<bool, 9> survives; | ||
|
||
std::array<bool, Width * Height> data{}; | ||
|
||
constexpr Automata(std::array<bool, 9> born_, std::array<bool, 9> survives_) | ||
: born(born_), survives(survives_) {} | ||
|
||
[[nodiscard]] constexpr std::size_t index(Point p) const | ||
{ | ||
return floor_modulo(p.y, static_cast<index_t>(Height)) * Width + floor_modulo(p.x, static_cast<index_t>(Width)); | ||
} | ||
|
||
[[nodiscard]] constexpr bool get(Point p) const { return data[index(p)]; } | ||
|
||
constexpr void set(Point p) { data[index(p)] = true; } | ||
|
||
constexpr static std::array<Point, 8> neighbors{ | ||
Point{ -1, -1 }, | ||
Point{ 0, -1 }, | ||
Point{ 1, -1 }, | ||
Point{ -1, 0 }, | ||
Point{ 1, 0 }, | ||
Point{ -1, 1 }, | ||
Point{ 0, 1 }, | ||
Point{ 1, 1 } | ||
}; | ||
|
||
constexpr std::size_t count_neighbors(Point p) const | ||
{ | ||
return static_cast<std::size_t>(std::ranges::count_if( | ||
neighbors, [&](auto offset) { return get(p + offset); })); | ||
} | ||
|
||
[[nodiscard]] constexpr Automata next() const | ||
{ | ||
Automata<Width, Height> result{ born, survives }; | ||
|
||
for (std::size_t y = 0; y < Height; ++y) { | ||
for (std::size_t x = 0; x < Width; ++x) { | ||
Point p{ static_cast<index_t>(x), static_cast<index_t>(y) }; | ||
const auto neighbors = count_neighbors(p); | ||
if (get(p)) { | ||
if (survives[neighbors]) { | ||
result.set(p); | ||
} | ||
} else { | ||
if (born[neighbors]) { | ||
result.set(p); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
constexpr void add_glider(Point p) | ||
{ | ||
set(p); | ||
set(p + Point(1, 1)); | ||
set(p + Point(2, 1)); | ||
set(p + Point(0, 2)); | ||
set(p + Point(1, 2)); | ||
} | ||
}; | ||
|
||
int main() | ||
{ | ||
constexpr static auto initial_state = []() { | ||
auto obj = Automata<WIDTH, HEIGHT>({ false, false, false, true, false, false, false, false, false }, { false, false, true, true, false, false, false, false, false }); | ||
obj.add_glider(Point(0, 18)); | ||
return obj; | ||
}(); | ||
|
||
auto obj = initial_state; | ||
|
||
for (int i = 0; i < ITERATIONS; ++i) { | ||
obj = obj.next(); | ||
} | ||
|
||
for (size_t y = 0; y < obj.height(); ++y) { | ||
for (size_t x = 0; x < obj.width(); ++x) { | ||
if (obj.get(Point(static_cast<index_t>(x), | ||
static_cast<index_t>(y)))) { | ||
std::putchar('X'); | ||
} else { | ||
std::putchar('.'); | ||
} | ||
} | ||
std::puts(""); | ||
} | ||
} |
134 changes: 134 additions & 0 deletions
134
python/conway_game_of_life/larger_tests/life-stack-based.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#include <algorithm> | ||
#include <array> | ||
#include <cstdio> | ||
#include <type_traits> | ||
#include <vector> | ||
#include <fmt/format.h> | ||
|
||
#include "parameters.hpp" | ||
|
||
// necessary to keep the same algorithm as Python | ||
constexpr auto floor_modulo(auto dividend, auto divisor) | ||
{ | ||
return ((dividend % divisor) + divisor) % divisor; | ||
} | ||
|
||
using index_t = std::make_signed_t<std::size_t>; | ||
|
||
struct Point | ||
{ | ||
index_t x; | ||
index_t y; | ||
|
||
[[nodiscard]] constexpr Point operator+(Point rhs) const | ||
{ | ||
return Point{ x + rhs.x, y + rhs.y }; | ||
} | ||
}; | ||
|
||
|
||
// if we wanted to push this further, we would make the width and height compile-time constants | ||
// that is for a future episode. | ||
template<std::size_t Width, std::size_t Height> | ||
struct Automata | ||
{ | ||
|
||
constexpr auto width() const | ||
{ | ||
return Width; | ||
} | ||
|
||
constexpr auto height() const | ||
{ | ||
return Height; | ||
} | ||
|
||
std::array<bool, 9> born; | ||
std::array<bool, 9> survives; | ||
|
||
std::array<bool, Width * Height> data{}; | ||
|
||
constexpr Automata(std::array<bool, 9> born_, std::array<bool, 9> survives_) | ||
: born(born_), survives(survives_) {} | ||
|
||
[[nodiscard]] constexpr std::size_t index(Point p) const | ||
{ | ||
return floor_modulo(p.y, static_cast<index_t>(Height)) * Width + floor_modulo(p.x, static_cast<index_t>(Width)); | ||
} | ||
|
||
[[nodiscard]] constexpr bool get(Point p) const { return data[index(p)]; } | ||
|
||
constexpr void set(Point p) { data[index(p)] = true; } | ||
|
||
constexpr static std::array<Point, 8> neighbors{ | ||
Point{ -1, -1 }, | ||
Point{ 0, -1 }, | ||
Point{ 1, -1 }, | ||
Point{ -1, 0 }, | ||
Point{ 1, 0 }, | ||
Point{ -1, 1 }, | ||
Point{ 0, 1 }, | ||
Point{ 1, 1 } | ||
}; | ||
|
||
constexpr std::size_t count_neighbors(Point p) const | ||
{ | ||
return static_cast<std::size_t>(std::ranges::count_if( | ||
neighbors, [&](auto offset) { return get(p + offset); })); | ||
} | ||
|
||
[[nodiscard]] constexpr Automata next() const | ||
{ | ||
Automata<Width, Height> result{ born, survives }; | ||
|
||
for (std::size_t y = 0; y < Height; ++y) { | ||
for (std::size_t x = 0; x < Width; ++x) { | ||
Point p{ static_cast<index_t>(x), static_cast<index_t>(y) }; | ||
const auto neighbors = count_neighbors(p); | ||
if (get(p)) { | ||
if (survives[neighbors]) { | ||
result.set(p); | ||
} | ||
} else { | ||
if (born[neighbors]) { | ||
result.set(p); | ||
} | ||
} | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
constexpr void add_glider(Point p) | ||
{ | ||
set(p); | ||
set(p + Point(1, 1)); | ||
set(p + Point(2, 1)); | ||
set(p + Point(0, 2)); | ||
set(p + Point(1, 2)); | ||
} | ||
}; | ||
|
||
int main() | ||
{ | ||
|
||
auto obj = Automata<WIDTH, HEIGHT>({ false, false, false, true, false, false, false, false, false }, { false, false, true, true, false, false, false, false, false }); | ||
obj.add_glider(Point(0, 18)); | ||
|
||
|
||
for (int i = 0; i < ITERATIONS; ++i) { | ||
obj = obj.next(); | ||
} | ||
|
||
for (size_t y = 0; y < obj.height(); ++y) { | ||
for (size_t x = 0; x < obj.width(); ++x) { | ||
if (obj.get(Point(static_cast<index_t>(x), | ||
static_cast<index_t>(y)))) { | ||
std::putchar('X'); | ||
} else { | ||
std::putchar('.'); | ||
} | ||
} | ||
std::puts(""); | ||
} | ||
} |
Oops, something went wrong.