Skip to content

Commit

Permalink
basic gol done
Browse files Browse the repository at this point in the history
  • Loading branch information
dedztbh committed Apr 21, 2024
1 parent 5ad6932 commit a66a111
Show file tree
Hide file tree
Showing 12 changed files with 295 additions and 29 deletions.
2 changes: 1 addition & 1 deletion SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def validate_parent_dir(key, val, env):
raise UserError("'%s' is not a directory: %s" % (key, os.path.dirname(val)))


libname = "EXTENSION-NAME"
libname = "lifepvp"
projectdir = "game"

localEnv = Environment(tools=["default"], PLATFORM="")
Expand Down
23 changes: 0 additions & 23 deletions game/bin/example.gdextension

This file was deleted.

23 changes: 23 additions & 0 deletions game/bin/lifepvp.gdextension
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[configuration]

entry_symbol = "lifepvp_library_init"
compatibility_minimum = "4.2"

[libraries]

macos.debug = "res://bin/macos/liblifepvp.macos.template_debug.framework"
macos.release = "res://bin/macos/liblifepvp.macos.template_release.framework"
windows.debug.x86_32 = "res://bin/windows/liblifepvp.windows.template_debug.x86_32.dll"
windows.release.x86_32 = "res://bin/windows/liblifepvp.windows.template_release.x86_32.dll"
windows.debug.x86_64 = "res://bin/windows/liblifepvp.windows.template_debug.x86_64.dll"
windows.release.x86_64 = "res://bin/windows/liblifepvp.windows.template_release.x86_64.dll"
linux.debug.x86_64 = "res://bin/linux/liblifepvp.linux.template_debug.x86_64.so"
linux.release.x86_64 = "res://bin/linux/liblifepvp.linux.template_release.x86_64.so"
linux.debug.arm64 = "res://bin/linux/liblifepvp.linux.template_debug.arm64.so"
linux.release.arm64 = "res://bin/linux/liblifepvp.linux.template_release.arm64.so"
linux.debug.rv64 = "res://bin/linux/liblifepvp.linux.template_debug.rv64.so"
linux.release.rv64 = "res://bin/linux/liblifepvp.linux.template_release.rv64.so"
android.debug.x86_64 = "res://bin/android/liblifepvp.android.template_debug.x86_64.so"
android.release.x86_64 = "res://bin/android/liblifepvp.android.template_release.x86_64.so"
android.debug.arm64 = "res://bin/android/liblifepvp.android.template_debug.arm64.so"
android.release.arm64 = "res://bin/android/liblifepvp.android.template_release.arm64.so"
37 changes: 37 additions & 0 deletions game/board.gd
Original file line number Diff line number Diff line change
@@ -1,13 +1,50 @@
extends GridContainer

signal next_iteration

var life_driver : LifeDriver
var cells : Array

# Called when the node enters the scene tree for the first time.
func _ready():
for i in range(columns):
cells.append([])
for j in range(columns):
var new_cell = ColorRect.new()
new_cell.custom_minimum_size = Vector2(10, 10)
add_child(new_cell)
cells[-1].append(new_cell)
life_driver = LifeDriver.new()
life_driver.update_cell.connect(_update_cell)
life_driver.update_done.connect(_update_done)
next_iteration.connect(life_driver.next_iteration)

var bytearray = PackedByteArray()
bytearray.resize(columns * columns)
bytearray[0 * columns + 1] = 1
bytearray[1 * columns + 2] = 1
bytearray[2 * columns + 0] = 1
bytearray[2 * columns + 1] = 1
bytearray[2 * columns + 2] = 1
_update_cell(0, 1, 1)
_update_cell(1, 2, 1)
_update_cell(2, 0, 1)
_update_cell(2, 1, 1)
_update_cell(2, 2, 1)

life_driver.setup(columns, columns, bytearray, LifeDriver.BASIC)


# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
pass

func _update_cell(i: int, j: int, state: int):
cells[i][j].color = Color.BLACK if state else Color.WHITE

func _update_done():
pass


func _on_timer_timeout():
emit_signal("next_iteration")
6 changes: 6 additions & 0 deletions game/board.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ theme_override_constants/h_separation = 1
theme_override_constants/v_separation = 1
columns = 42
script = ExtResource("1_o7lpq")

[node name="Timer" type="Timer" parent="."]
wait_time = 0.1
autostart = true

[connection signal="timeout" from="Timer" to="." method="_on_timer_timeout"]
52 changes: 52 additions & 0 deletions src/basic_engine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <utility>

#include "basic_engine.h"

void BasicEngine::next_iteration() {
const auto& curr_board = m_board_pair[m_board];
auto& next_board = m_board_pair[m_board ^ 1];

for (size_t i = 0; i < W; ++i) {
for (size_t j = 0; j < H; ++j) {
const std::pair<int64_t, int64_t> neighbor_offsets[]
{{-1, -1}, {-1, 0}, {-1, 1},
{ 0, -1}, { 0, 1},
{ 1, -1}, { 1, 0}, { 1, 1}};
size_t count = 0;
for (const auto [x, y] : neighbor_offsets) {
if (at(curr_board, (x+W+i)%W, (y+H+j)%H)) {
++count;
}
}

const state_t curr_cell = at(curr_board, i, j);
state_t& next_cell = at(next_board, i, j);
if (count < 2 || count > 3) {
next_cell = 0; // die
} else if (count == 3) {
next_cell = 1; // survive or create
} else { // count == 2
next_cell = curr_cell; // survive
}

if (next_cell != curr_cell) {
m_update_cb(i, j, next_cell);
}
}
}

m_board ^= 1;
m_done_cb();
}

BasicEngine::state_t BasicEngine::get_state(size_t i, size_t j) {
return at(m_board_pair[m_board], i, j);
}

BasicEngine::state_t& BasicEngine::at(board_t& v, size_t i, size_t j) {
return v[i * W + j];
}

const BasicEngine::state_t& BasicEngine::at(const board_t& v, size_t i, size_t j) const {
return v[i * W + j];
}
32 changes: 32 additions & 0 deletions src/basic_engine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef LIFEPVP_BASIC_ENGINE_H
#define LIFEPVP_BASIC_ENGINE_H

#include <vector>

#include "engine_base.h"

class BasicEngine : public EngineBase {
public:
using board_t = std::vector<state_t>;

BasicEngine(board_t&& board,
const size_t w,
const size_t h,
const update_cb_t update_cb,
const done_cb_t done_cb)
: EngineBase(w, h, update_cb, done_cb),
m_board_pair{board, board_t(board.size())} {}

virtual ~BasicEngine() = default;
void next_iteration() override;
state_t get_state(size_t i, size_t j) override;

protected:
size_t m_board = 0;
std::array<board_t, 2> m_board_pair;

state_t& at(board_t& v, size_t i, size_t j);
const state_t& at(const board_t& v, size_t i, size_t j) const;
};

#endif
29 changes: 29 additions & 0 deletions src/engine_base.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef LIFEPVP_ENGINE_BASE_H
#define LIFEPVP_ENGINE_BASE_H

#include <functional>
#include <cstdint>

class EngineBase {
public:
using state_t = uint8_t;
using update_cb_t = std::function<void(size_t, size_t, uint8_t)>;
using done_cb_t = std::function<void()>;

EngineBase(const size_t w,
const size_t h,
const update_cb_t update_cb,
const done_cb_t done_cb)
: W(w), H(h), m_update_cb(update_cb), m_done_cb(done_cb) {}

virtual ~EngineBase() = default;
virtual void next_iteration() = 0;
virtual state_t get_state(size_t, size_t) = 0;
protected:
const size_t W;
const size_t H;
const update_cb_t m_update_cb;
const done_cb_t m_done_cb;
};

#endif
70 changes: 70 additions & 0 deletions src/life_driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include "life_driver.h"

#include <vector>
#include <cstring>

#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>


#include "engine_base.h"
#include "basic_engine.h"

using namespace godot;

void LifeDriver::setup(const size_t w, const size_t h, const Variant& init_board, const EngineType engine) {

const auto init_board_to_vec = [&]() {
const PackedByteArray& array = std::forward<PackedByteArray>(init_board);
static_assert(sizeof(*(array.ptr())) == sizeof(EngineBase::state_t));
std::vector<EngineBase::state_t> vec(w * h);
memcpy(vec.data(), array.ptr(), sizeof(EngineBase::state_t) * vec.size());
return vec;
};

const auto get_board_vec = [&]() {
switch (init_board.get_type()) {
case Variant::NIL:
return std::vector<EngineBase::state_t>(w * h);

case Variant::PACKED_BYTE_ARRAY:
return init_board_to_vec();
break;

default:
ERR_PRINT("Unknown init_board type");
return std::vector<EngineBase::state_t>{};
}
};

switch (engine) {
case BASIC:
m_engine = std::make_unique<BasicEngine>(get_board_vec(), w, h,
[&](size_t i, size_t j, uint8_t state) {
emit_signal("update_cell", i, j, state);
},
[&]() {
emit_signal("update_done");
}
);
break;

default:
ERR_PRINT("Unknown engine type");
return;
}
}

void LifeDriver::next_iteration() {
m_engine->next_iteration();
}

void LifeDriver::_bind_methods() {
ADD_SIGNAL(MethodInfo("update_cell", PropertyInfo(Variant::INT, "i"), PropertyInfo(Variant::INT, "j"), PropertyInfo(Variant::INT, "state")));
ADD_SIGNAL(MethodInfo("update_done"));

ClassDB::bind_method(D_METHOD("setup", "w", "h", "init_board", "engine_type"), &LifeDriver::setup);
ClassDB::bind_method(D_METHOD("next_iteration"), &LifeDriver::next_iteration);

BIND_ENUM_CONSTANT(BASIC);
}
36 changes: 36 additions & 0 deletions src/life_driver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef LIFEPVP_LIFE_DRIVER_H
#define LIFEPVP_LIFE_DRIVER_H

#include <memory>

#include <godot_cpp/classes/node.hpp>
#include <godot_cpp/variant/variant.hpp>

#include "engine_base.h"

namespace godot {

class LifeDriver : public Object {
GDCLASS(LifeDriver, Object)

public:
enum EngineType {
BASIC
};

void setup(const size_t w, const size_t h, const Variant& init_board, const EngineType engine);

void next_iteration();

protected:
static void _bind_methods();

private:
std::unique_ptr<EngineBase> m_engine;
};

}

VARIANT_ENUM_CAST(LifeDriver::EngineType);

#endif // LIFEPVP_LIFE_DRIVER_H
8 changes: 6 additions & 2 deletions src/register_types.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
#include "register_types.h"

#include "life_driver.h"

#include <gdextension_interface.h>
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/core/defs.hpp>
Expand All @@ -11,7 +14,8 @@ void initialize_gdextension_types(ModuleInitializationLevel p_level)
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
//ClassDB::register_class<YourClass>();

ClassDB::register_class<LifeDriver>();
}

void uninitialize_gdextension_types(ModuleInitializationLevel p_level) {
Expand All @@ -23,7 +27,7 @@ void uninitialize_gdextension_types(ModuleInitializationLevel p_level) {
extern "C"
{
// Initialization
GDExtensionBool GDE_EXPORT example_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
GDExtensionBool GDE_EXPORT lifepvp_library_init(GDExtensionInterfaceGetProcAddress p_get_proc_address, GDExtensionClassLibraryPtr p_library, GDExtensionInitialization *r_initialization)
{
GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_gdextension_types);
Expand Down
6 changes: 3 additions & 3 deletions src/register_types.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef EXAMPLE_REGISTER_TYPES_H
#define EXAMPLE_REGISTER_TYPES_H
#ifndef LIFEPVP_REGISTER_TYPES_H
#define LIFEPVP_REGISTER_TYPES_H

void initialize_gdextension_types();
void uninitialize_gdextension_types();

#endif // EXAMPLE_REGISTER_TYPES_H
#endif // LIFEPVP_REGISTER_TYPES_H

0 comments on commit a66a111

Please sign in to comment.