Skip to content

Instantly share code, notes, and snippets.

@dz0
Last active February 13, 2018 10:39
Show Gist options
  • Select an option

  • Save dz0/f83b046ed75e3e11c9d6b503b80dd017 to your computer and use it in GitHub Desktop.

Select an option

Save dz0/f83b046ed75e3e11c9d6b503b80dd017 to your computer and use it in GitHub Desktop.
/*
* Game of Life v1.0
* https://en.wikipedia.org/wiki/Conway's_Game_of_Life
*
* Author: Chionsas
* Licence: PUBLIC DOMAIN, https://unlicense.org/UNLICENSE
*/
/*
* Užduotis: pabaigti funkcijas getAliveNeighbourCount ir (panaudojant ją) generateNextTick (pagal išvardintas taisykles).
* Kaip elgtis su programa?: Su pele paspaudinėt pradinę situaciją ir paskui paspaust "Space", procesui paleisti.
*/
// Konstantos
final int rows = 10; // eilučių skaičius = aukštis
final int columns = 20; // stulpelių skaičius = plotis
final int target_world_width = 1400; // norimas lentos plotis pixeliais
final int target_world_height = 700; // norimas lentos aukštis pixeliais
final int cell_border = 1; // langelio krašto storis pixeliais
final int cell_width = (target_world_width / columns) - cell_border; // vidinis langelio plotis pixeliais
final int cell_height = (target_world_height / rows) - cell_border; // vidinis langelio aukštis pixeliais
final int world_width = columns * (cell_width + cell_border) - cell_border; // lentos plotis
final int world_height = rows * (cell_height + cell_border) - cell_border; // lentos aukštis
final int window_width = floor(world_width*1.00); // lango plotis pixeliais
final int window_height = floor(world_height*1.00); // lango aukštis pixeliais
final int world_x = (window_width - world_width) / 2; // lentos pozicija x - centruota
final int world_y = (window_height - world_height) / 2; // lentos pozicija y - centruota
// Tango palette, https://en.wikipedia.org/wiki/Tango_Desktop_Project#Palette
final color color_background = #eeeeec;
final color color_cell_normal = color_background;
final color color_cell_hover = color(255, 255, 255, 200);
final color color_border = #d3d7cf;
final color[] color_debug = { #a40000, #5c3566 };
final color[] color_value = { color_background, #d3d7cf, #75507b };
// Galimos langelių reikšmės
final int VALUE_EMPTY = 0;
final int VALUE_DEAD = 1;
final int VALUE_ALIVE = 2;
// Globalūs kintamieji
// logging
final int TRACE_DRAW = 70; // rodyti informaciją ir apie piešiamus objektus
final int TRACE = 60; // detaliausias log'inimo lygis (konsolė ir grafinis rodymas)
final int TRACE_GRAPHICAL = 55; // detaliai, grafiškai vaizduojami veiksmai su langeliais
final int DEBUG = 50; // keičiant duomenis, veiksmai aprašomi konsolėje
final int INFO = 40; // tik informacija apie svarbesnius pokyčius
final int OFF = 0; // išjungta
int trace_graphical_delay = 100; // programos sulėtinimo indeksas TRACE_GRAPHICAL režimui
// logLevel gali būti keičiamas klaviatūra, programos eigoje:
// r = TRACE_DRAW
// t = TRACE
// g = TRACE_GRAPHICAL
// d = DEBUG
// i = INFO
// o = OFF
int logLevel = INFO;
int fps = 24; // frames per second; gali būti keičiamas rodyklėmis aukštyn/žemyn
boolean isRunning = false; // kai true, programa
boolean isMouseInputDisabled = false; // kai true, programa nereaguoja į pelę
boolean wrap = true; // ar kirtus kraštą pereinama į priešingą pusę
int[][] world = new int[rows][columns]; // dvimatis masyvas žaidimo būklei saugoti
int mouseColumn = -1; // mouseColumn keičiamas judinant pelę pagal mouseX
int mouseRow = -1; // mouseRow keičiamas judinant pelę pagal mouseY
// debug'inamas langelis būna apibrėžtas spalvotai, kai įjungtas TRACE_GRAPHICAL logLevel'is
int debugRow = -1; // debug'inamo langelio eilutė
int debugColumn = -1; // debug'inamo langelio stulpelis
color debugColor; // debug'inamo langelio spalva
// -------------------------------------------------------------------------------------------
// Pagrindiniai nustatymai
void settings() {
size(window_width, window_height); // Nustato lango dydį
}
// Nustatymai
void setup() {
frameRate(fps);
noLoop();
noStroke();
background(color_background);
}
// Piešimo funkcija, iškviečiama per redraw()
// arba nuolat kviečiama paleidus loop()
void draw() {
if (isRunning) {
tick();
}
drawWorld();
}
// Piešia pasaulį ir susijusius elementus
void drawWorld() {
log(TRACE_DRAW, "Drawing world at " + world_x + "," + world_y);
// Lentos fonas, bus matomas tarp langelių kaip kraštinės
fill(color_border);
rect(world_x, world_y, world_width, world_height);
for (int row = 0; row < rows; row++) {
for (int column = 0; column < columns; column++) {
int x = world_x + translateColumnToX(column);
int y = world_y + translateRowToY(row);
color color_cell = getCellColor(row, column);
if (color_cell != color_border) { // praleidžiam, jei sutampa spalva
fill(color_cell);
rect(x, y, cell_width, cell_height);
}
if (!isRunning && isCellHovered(row, column)) {
log(TRACE, "Cell " + row + "," + column + " is hovered");
fill(color_cell_hover);
rect(x, y, cell_width, cell_height);
}
// Jei įjungtas grafinis trace'inimas, piešiam papildomus elementus
if (isLogLevel(TRACE_GRAPHICAL)) {
if (row == debugRow && column == debugColumn) {
drawCellDebug(world_x, world_y, debugRow, debugColumn, debugColor);
}
}
}
}
}
// Piešia nurodytos spalvos rėmelį aplink nurodytą langelį
void drawCellDebug(int x, int y, int row, int column, color strokeColor) {
log(TRACE_DRAW, "Drawing debug stroke for " + row + "," + column + " at " + x + "," + y);
pushStyle();
stroke(strokeColor);
strokeWeight(cell_border*2);
noFill();
rect(x, y, cell_width, cell_height);
noStroke();
popStyle();
}
// Pakeičia esamą pasaulį nauju
void tick() {
world = generateNextTick();
}
// Generuoja naują pasaulį iš esamo
int[][] generateNextTick() {
int[][] world_new = cloneTwoDimensionalArray(world);
for (int row=0; row < rows; row++) {
for (int column=0; column < columns; column++) {
// RULES:
// Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
// Any live cell with two or three live neighbours lives on to the next generation.
// Any live cell with more than three live neighbours dies, as if by overpopulation.
// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
int neighbours_alive = getAliveNeighbourCount(row, column);
}
}
return world_new;
}
// Grąžina gyvų kaimynų kiekį
int getAliveNeighbourCount(int row, int column) {
/* Reliatyvios kaimynų koordinatės:
{-1, -1}, {-1, 0}, {-1, 1},
{ 0, -1}, { 0, 1},
{ 1, -1}, { 1, 0}, { 1, 1}
*/
int neighbours_alive = 0;
//if (isCellAlive(neighbour_row, neighbour_column)) {
// neighbours_alive++;
//}
return neighbours_alive;
}
// Grąžina duotojo dvimačio masyvo kopiją
int[][] cloneTwoDimensionalArray(int[][] source) {
int[][] copy = new int[source.length][];
for (int i = 0; i < source.length; i++) {
copy[i] = source[i].clone();
}
return copy;
}
// Iškviečiamas kaskart pajudėjus pelei.
// Nustato mouseRow ir mouseColumn kintamuosius ir iškviečia perpiešimą, jei jie pasikeitė
void mouseMoved() {
if (isMouseInputDisabled) { return; }
int newMouseRow = translateYToRow(mouseY - world_y);
int newMouseColumn = translateXToColumn(mouseX - world_x);
if (isOutOfBounds(newMouseRow, newMouseColumn)) { return; }
if (newMouseRow != mouseRow || newMouseColumn != mouseColumn) {
mouseRow = newMouseRow;
mouseColumn = newMouseColumn;
if (mousePressed) {
log(TRACE, "Toggling value of " + mouseRow + "," + mouseColumn);
toggleCellValue(mouseRow, mouseColumn);
}
log(TRACE, "MouseColumn=" + mouseColumn + ", mouseRow=" + mouseRow);
log(TRACE, "Redrawing..");
redraw();
}
}
void mousePressed() {
if (isMouseInputDisabled) { return; }
if (!isOutOfBounds(mouseRow, mouseColumn)) {
log(TRACE, "Toggling value of " + mouseRow + "," + mouseColumn);
toggleCellValue(mouseRow, mouseColumn);
redraw();
}
}
void mouseDragged() {
mouseMoved();
}
// Pradeda žaidimą
void startWorld() {
if (isLogLevel(TRACE_GRAPHICAL)) {
// įjungtas TRACE/TRACE_GRAPHICAL loglevel'os
frameRate(120);
redraw();
log(TRACE_GRAPHICAL, "Tracing a single tick..");
thread("tick"); // tick() paleidžiamas atskiram procese, kad galėtume piešti debugCell
} else if (isLogLevel(DEBUG)) {
// įjungtas DEBUG LogLevel'is
log(DEBUG, "Drawing a single tick..");
tick();
redraw();
} else {
// normalus programos paleidimas
log(INFO, "Starting..");
isMouseInputDisabled = true;
mouseColumn = -1;
mouseRow = -1;
frameRate(fps);
isRunning = true;
loop();
}
}
// Stabdo žaidimą
void stopWorld() {
log(INFO, "Stopping.");
noLoop();
isMouseInputDisabled = false;
isRunning = false;
}
void clearWorld() {
log(INFO, "Resetting world..");
world = cloneTwoDimensionalArray(new int[rows][columns]);
redraw();
}
// Iškviečiamas paspaudus klaviatūros mygtuką
// Pakeičia logLevel:
// r = TRACE_DRAW
// t = TRACE
// g = TRACE_GRAPHICAL
// d = DEBUG
// i = INFO
// o = OFF
//
// c = išvalo pasaulį
// w = keičia kraštų sujungimą
// + / - = padidina/sumažina trace_graphical_delay
// ↑ / ↓ = padidina/sumažina kadrų per sekundę skaičių
// <space> = paleidžia/stabdo žaidimą
void keyPressed() {
log(TRACE, "Key pressed: " + key);
switch(key) {
case 'r':
logLevel = TRACE_DRAW;
debugCell(-1, -1, 0);
log(INFO, "Log level: TRACE_DRAW");
break;
case 't':
logLevel = TRACE;
debugCell(-1, -1, 0);
log(INFO, "Log level: TRACE");
break;
case 'g':
logLevel = TRACE_GRAPHICAL;
debugCell(-1, -1, 0);
log(INFO, "Log level: TRACE_GRAPHICAL");
break;
case 'd':
logLevel = DEBUG;
log(INFO, "Log level: DEBUG");
break;
case 'i':
logLevel = INFO;
log(INFO, "Log level: INFO");
break;
case 'o':
log(INFO, "Logging is off");
logLevel = OFF;
break;
case '+':
trace_graphical_delay += 10;
log(INFO, "Graphical trace delay: " + trace_graphical_delay);
break;
case '-':
if (trace_graphical_delay > 10) {
trace_graphical_delay -= 10;
}
log(INFO, "Graphical trace delay: " + trace_graphical_delay);
break;
case 'w':
wrap = !wrap;
log(INFO, "Wrap edges: " + (wrap ? "ON" : "OFF"));
break;
case 'c': // išvalo pasaulį
if (isRunning) {
stopWorld();
}
clearWorld();
break;
case ' ': // pradeda/stabdo programą
if (isRunning) {
stopWorld();
} else {
startWorld();
}
break;
case CODED:
if (keyCode == UP && fps < 120) { // didina kadrų per sekundę skaičių
fps += 4;
} else if (keyCode == DOWN && fps > 4) { // mažina kadrų per sekundę skaičių
fps -= 4;
}
frameRate(fps);
log(INFO, "Framerate=" + fps + " (actual: " + frameRate + ")");
break;
}
log(TRACE, "Redrawing..");
redraw();
}
// Grąžina true, jei duotas langelio adresas yra už lentos ribų
// (t.y. neigiamos arba per didelės koordinatės)
boolean isOutOfBounds(int row, int column) {
return row < 0 || row >= rows || column < 0 || column >= columns;
}
// Grąžina true, jei duotasis langelis turi virš savęs pelę
boolean isCellHovered(int row, int column) {
return mouseRow == row && mouseColumn == column;
}
// Grąžina true, jei langelis neturi reikšmės
boolean isCellAlive(int row, int column) {
return getCellValue(row, column) == VALUE_ALIVE;
}
void toggleCellValue(int row, int column) {
if (isCellAlive(row, column)) {
log(TRACE, row + "," + column + " is now DEAD");
setCellValue(row, column, VALUE_DEAD);
} else {
log(TRACE, row + "," + column + " is now ALIVE");
setCellValue(row, column, VALUE_ALIVE);
}
}
// Grąžina langelio reikšmę
int getCellValue(int row, int column) {
return world[row][column];
}
// Nustato langelio reikšmę
void setCellValue(int row, int column, int[][] twoDimensionalArray, int value) {
twoDimensionalArray[row][column] = value;
log(DEBUG, "Setting " + row + "," + column + " to " + value);
if (isLogLevel(TRACE_GRAPHICAL)) {
debugCell(row, column, 1);
}
}
void setCellValue(int row, int column, int value) {
setCellValue(row, column, world, value);
}
// Nustto langelį kaip pažymėtą (neigiamą reikšmę)
void setCellAlive(int row, int column) {
log(DEBUG, "Setting " + row + "," + column + " as alive");
setCellAlive(row, column, world);
}
void setCellAlive(int row, int column, int[][] twoDimensionalArray) {
setCellValue(row, column, twoDimensionalArray, VALUE_ALIVE);
}
void setCellDead(int row, int column) {
log(DEBUG, "Setting " + row + "," + column + " as dead");
setCellValue(row, column, world, VALUE_DEAD);
}
// Nustato langelį kaip nepažymėtą (teigiamą reikšmę)
void setCellDead(int row, int column, int[][] twoDimensionalArray) {
setCellValue(row, column, twoDimensionalArray, VALUE_DEAD);
}
// Grąžina duotojo langelio ženklo spalvą
color getCellColor(int row, int column) {
return translateValueToColor(getCellValue(row, column));
}
color translateValueToColor(int value) {
return color_value[value];
}
// Paverčia stulpelio indeksą į x koordinatę lentoje
int translateColumnToX(int column) {
return column * (cell_width + cell_border);
}
// Paverčia eilutės indeksą į y koordinatę lentoje
int translateRowToY(int row) {
return row * (cell_height + cell_border);
}
// Paverčia x koordinatę lentoje į stulpelio indeksą
int translateXToColumn(int x) {
return x / (cell_width + cell_border);
}
// Paverčia y koordinatę lentoje į eilutės indeksą
int translateYToRow(int y) {
return y / (cell_height + cell_border);
}
// Grąžina true, jei esamas logLevel yra detalesnis arba lygus duotajam argumentui
boolean isLogLevel(int level) {
return level <= logLevel;
}
// Spausdina message, jei esamas logLevel atitinka duotąjį level (yra detalesnis arba lygus)
void log(int level, String message) {
if (isLogLevel(level)) {
println(message);
}
}
// Sustabdo programą nurodydam laikui, jei esamas logLevel atitinka duotąjį level
void debugDelay(int level, int milliseconds) {
if (isLogLevel(level)) {
delay(milliseconds);
}
}
// Nustato debug'inamą langelį ir perpiešia ekraną
void debugCell(int row, int column, int debugColorIndex) {
if (!isLogLevel(TRACE_GRAPHICAL)) { return; }
debugRow = row;
debugColumn = column;
debugColor = color_debug[debugColorIndex];
redraw();
debugDelay(TRACE_GRAPHICAL, trace_graphical_delay);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment