128 lines
3.3 KiB
C++
128 lines
3.3 KiB
C++
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <luna/Heap.h>
|
|
#include <os/ArgumentParser.h>
|
|
#include <os/Timer.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <ui/App.h>
|
|
#include <ui/Window.h>
|
|
#include <unistd.h>
|
|
|
|
struct Cell
|
|
{
|
|
bool state;
|
|
bool new_state;
|
|
};
|
|
|
|
static int g_num_rows = 40;
|
|
static int g_num_columns = 60;
|
|
|
|
static Cell* g_cells;
|
|
|
|
static ui::Window* g_window;
|
|
|
|
static Result<void> fill_cells()
|
|
{
|
|
g_cells = (Cell*)TRY(calloc_impl(g_num_rows, g_num_columns * sizeof(Cell), false));
|
|
|
|
for (isize i = 0; i < (g_num_rows * g_num_columns); i++)
|
|
{
|
|
auto value = rand() % 2;
|
|
g_cells[i].state = g_cells[i].new_state = value;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
static Cell& find_cell(int row, int column)
|
|
{
|
|
assert(row < g_num_rows);
|
|
assert(column < g_num_columns);
|
|
return g_cells[row * g_num_columns + column];
|
|
}
|
|
|
|
static constexpr int BYTES_PER_PIXEL = sizeof(u32);
|
|
static constexpr ui::Color activated_cell_color = ui::CYAN;
|
|
static constexpr ui::Color deactivated_cell_color = ui::Color::from_rgb(40, 40, 40);
|
|
|
|
static void draw_cells()
|
|
{
|
|
const int CELL_WIDTH = g_window->canvas().width / g_num_columns;
|
|
const int CELL_HEIGHT = g_window->canvas().height / g_num_rows;
|
|
|
|
auto canvas = g_window->canvas();
|
|
|
|
for (int i = 0; i < g_num_rows; i++)
|
|
{
|
|
for (int j = 0; j < g_num_columns; j++)
|
|
{
|
|
auto subcanvas = canvas.subcanvas(ui::Rect { j * CELL_WIDTH, i * CELL_HEIGHT, CELL_WIDTH, CELL_HEIGHT });
|
|
|
|
auto& cell = find_cell(i, j);
|
|
ui::Color color = cell.state ? activated_cell_color : deactivated_cell_color;
|
|
subcanvas.fill(color);
|
|
}
|
|
}
|
|
|
|
g_window->update();
|
|
}
|
|
|
|
static int find_neighbors(int row, int column)
|
|
{
|
|
int sum = 0;
|
|
|
|
if (row > 0 && column > 0) sum += find_cell(row - 1, column - 1).state;
|
|
if (row > 0) sum += find_cell(row - 1, column).state;
|
|
if (row > 0 && (column + 1) < g_num_columns) sum += find_cell(row - 1, column + 1).state;
|
|
if (column > 0) sum += find_cell(row, column - 1).state;
|
|
if ((column + 1) < g_num_columns) sum += find_cell(row, column + 1).state;
|
|
if ((row + 1) < g_num_rows && column > 0) sum += find_cell(row + 1, column - 1).state;
|
|
if ((row + 1) < g_num_rows) sum += find_cell(row + 1, column).state;
|
|
if ((row + 1) < g_num_rows && (column + 1) < g_num_columns) sum += find_cell(row + 1, column + 1).state;
|
|
|
|
return sum;
|
|
}
|
|
|
|
static void next_generation()
|
|
{
|
|
for (int i = 0; i < g_num_rows; i++)
|
|
{
|
|
for (int j = 0; j < g_num_columns; j++)
|
|
{
|
|
auto& cell = find_cell(i, j);
|
|
int neighbors = find_neighbors(i, j);
|
|
if (!cell.state && neighbors == 3) cell.new_state = true;
|
|
else if (cell.state && (neighbors < 2 || neighbors > 3))
|
|
cell.new_state = false;
|
|
}
|
|
}
|
|
|
|
for (isize i = 0; i < (g_num_rows * g_num_columns); i++) g_cells[i].state = g_cells[i].new_state;
|
|
}
|
|
|
|
static void update()
|
|
{
|
|
next_generation();
|
|
draw_cells();
|
|
}
|
|
|
|
Result<int> luna_main(int, char**)
|
|
{
|
|
ui::App app;
|
|
TRY(app.init());
|
|
|
|
g_window = TRY(ui::Window::create(ui::Rect { 200, 200, 600, 400 }));
|
|
g_window->set_title("Game of Life");
|
|
app.set_main_window(g_window);
|
|
|
|
TRY(fill_cells());
|
|
|
|
update();
|
|
|
|
auto timer = TRY(os::Timer::create_repeating(100, update));
|
|
|
|
return app.run();
|
|
}
|