first commit

This commit is contained in:
Stefano Rossi 2025-07-10 03:45:41 +02:00
commit b827bb4ce6
Signed by: chadmin
GPG key ID: 9EFA2130646BC893
14 changed files with 673 additions and 0 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

155
GoL3D1/GoL3D1.pde Normal file
View file

@ -0,0 +1,155 @@
import com.shigeodayo.pframe.*;
import g4p_controls.*;
//gestione mouse e rotazione assi
float spostX, spostY, spostZ; //spostamento degli oggeto nel sistema di assi
int mousePressedX, mousePressedY;
float vRot; //velocità di rotazione al pixel
float rotX, rotY; //variabili rotazione assi
float tempRotX, tempRotY; //variabili temporanee per la somma della rotazione con il drag del mouse
float vSpost; // spostamento negli assi
float tempSpostX, tempSpostY; //spostamento temporaneo nel sistema
float zoom; //variabile per la gesione della quantità di zoom
float scalatura; //indica la grandezza di scale()
float scaleIndex; //indica di quanto diminuire scalatura es: 0.1 --> ogni pressione dei tasti su/giu scalatura cambia di 0.1
float explode;
int opacita;
int ogniTot;
int loneliness;
int overcrowding;
int minNeight, maxNeight;
thVita thv;;
//istanzio l'array tridimensionale di cellule
Cellula[][][] brodo;
//lato cubo
int L = 300;
//num Cellule per lato
int numCell = 50;
public void setup(){
size(800, 600, P3D);
//istanzio le alter finestre
createGUI();
zoom = 2;
spostX = 0;
spostY = 0;
spostZ = 0;
vSpost = 1;
explode = 0;
opacita = 51;
brodo = new Cellula[numCell][numCell][numCell];
ogniTot = 2;
istanziaBrodo();
loneliness = 3;
overcrowding = 20;
minNeight = 4;
maxNeight = 15;
thv = new thVita();
}
public void draw(){
background(255);//cancella tutto
pushMatrix();
translate(width/2 + spostX + tempSpostX - (explode/2)*brodo.length, height/2 + spostY + tempSpostY - (explode/2)*brodo.length, -L/2 - (explode/2)*brodo.length);//mi sposto al centro dello schermo
//ruoto il disegno
rotateY(rotX + tempRotX);
rotateX(rotY + tempRotY);
scale(zoom); //imposto la proporzione di disegno
noFill();
noStroke();
for (int i = 0; i< brodo.length; i++){
for (int j = 0; j< brodo[0].length; j++){
for (int k = 0; k< brodo[0][0].length; k++){
pushMatrix();
translate(-L/2 + (L/numCell + explode/2) * i, -L/2 + (L/numCell + explode/2) * j, -L/2 + (L/numCell + explode/2) * k);//mi sposto al centro dello schermo
if(brodo[i][j][k].isLiving()) {
if(brodo[i][j][k].getWilllive()) fill(0,100,255, opacita); //blu trasparente
else fill(200,100,0, opacita); //blu trasparente
}
else {
noFill();
}
box((L/numCell));
//sphere((L/numCell)/2);
popMatrix();
}
}
}
fill(255);
scalatura = 1;
popMatrix();
vRot = radians(0.3); //spostamento di 1 px per ogni pixel del mouse
}
void mouseDragged() {
if (mouseButton == 39) {
tempRotX = (mouseX - mousePressedX) * vRot;
tempRotY = -(mouseY - mousePressedY) * vRot;
}
if (mouseButton == 37) {
tempSpostX = (mouseX - mousePressedX) * vSpost;
tempSpostY = (mouseY - mousePressedY) * vSpost;
//println(spostX + " " + spostY + " " + tempSpostX + " " + tempSpostY);
}
}
void mouseReleased() {
//salvo la nuova posizione e resetto le varibili temporanee
rotX += tempRotX;
rotY += tempRotY;
spostX += tempSpostX;
spostY += tempSpostY;
tempSpostX = 0;
tempSpostY = 0;
tempRotX = 0;
tempRotY = 0;
}
void mouseWheel(MouseEvent event) {
if(zoom - event.getAmount() / 10 > 1) zoom -= (event.getAmount() / 10);
else if(zoom - event.getAmount() / 30 <= 1 && zoom - event.getAmount() / 30 >= 0.1) zoom -= (event.getAmount() / 30);
else zoom = 0.1;
}
void mousePressed() {
mousePressedX = mouseX;
mousePressedY = mouseY;
}
public void istanziaBrodo(){
for (int i = 0; i< brodo.length; i++){
for (int j = 0; j< brodo[0].length; j++){
for (int k = 0; k< brodo[0][0].length; k++){
brodo[i][j][k] = new Cellula(i, j, k);
//1 cellula su boh la faccio vivere in modo random
brodo[i][j][k].setLiving((Math.round(random(ogniTot)) == 0)?true:false);
}
}
}
}

35
GoL3D1/cellula.pde Normal file
View file

@ -0,0 +1,35 @@
public class Cellula{
private int x, y, z; //posizione nella matriche
private boolean living, willlive;
public Cellula(int x, int y, int z){
this.x = x;
this.y = y;
this.z = z;
living = false;
willlive = false;
}
public boolean isLiving(){
return living;
}
public boolean getWilllive(){
return willlive;
}
public void setLiving(boolean living){
this.living = living;
}
public void setWilllive(boolean willlive){
this.willlive = willlive;
}
public int[] getCoords(){
int[] pos = { x, y, z};
return pos;
}
}

82
GoL3D1/cellularLife.pde Normal file
View file

@ -0,0 +1,82 @@
//regole GoL 3D:
// Cells (in this case, cubes) with only 1 or less neighbours die, as if by lonliness.
// If 5 cells surround an empty cell, they breed and fill it.
// If a cell has 8 or more neighbours, it dies from overcrowding.
public void getFate(){
int neightboor = 0;
int lastCellindex = numCell-1;
//calcolo quante cellule vive esistono attorno a ogni cellula e ne imposto il destino
for (int i = 0; i< brodo.length; i++){
for (int j = 0; j< brodo[0].length; j++){
for (int k = 0; k< brodo[0][0].length; k++){
neightboor = calcolaVicini(i, j, k);
//println(neightboor);
//imposto il destino in base alle regole e al num dei vicini
//se la cella è viva
if(brodo[i][j][k].isLiving()){
//muore per solitudine o sovraffollamento
if(neightboor <= loneliness || neightboor >= overcrowding) brodo[i][j][k].setWilllive(false);
//altrimentio vive
else brodo[i][j][k].setWilllive(true);
//se è morta
//e ha abbastanza vicini allora nasce
}else if(neightboor >= minNeight && maxNeight <= maxNeight) brodo[i][j][k].setWilllive(true);
//altrimenti rimane morta
else brodo[i][j][k].setWilllive(false);
neightboor = 0;
}
}
}
}
private int calcolaVicini(int i, int j, int k){
int neight = 0;
short[] signs = new short[3];
for (int l = 0; l< 3; l++){
for (int m = 0; m< 3; m++){
for (int n = 0; n< 3; n++){
if(l == 0) signs[0] = -1;
else if(l == 1) signs[0] = 0;
else signs[0] = 1;
if(m == 0) signs[1] = -1;
else if(m == 1) signs[1] = 0;
else signs[1] = 1;
if(n == 0) signs[2] = -1;
else if(n == 1) signs[2] = 0;
else signs[2] = 1;
try {
if((signs[0] != 0 && signs[1] != 0 && signs[2] != 0) && brodo[i + signs[0]][j + signs[1]][k + signs[2]].isLiving()) neight++;
//println(signs[0] + " " + signs[1] + " " + signs[2]);
}catch(IndexOutOfBoundsException e){}
}
}
}
return neight;
}
public void setFate(){
for (int i = 0; i< brodo.length; i++){
for (int j = 0; j< brodo[0].length; j++){
for (int k = 0; k< brodo[0][0].length; k++){
brodo[i][j][k].setLiving(brodo[i][j][k].getWilllive());
}
}
}
}

240
GoL3D1/gui.pde Normal file
View file

@ -0,0 +1,240 @@
/* =========================================================
* ==== WARNING ===
* =========================================================
* The code in this tab has been generated from the GUI form
* designer and care should be taken when editing this file.
* Only add/edit code inside the event handlers i.e. only
* use lines between the matching comment tags. e.g.
void myBtnEvents(GButton button) { //_CODE_:button1:12356:
// It is safe to enter your event code here
} //_CODE_:button1:12356:
* Do not rename this tab!
* =========================================================
*/
synchronized public void win_draw1(GWinApplet appc, GWinData data) { //_CODE_:window1:677055:
appc.background(255);
} //_CODE_:window1:677055:
public void csExpl_change1(GCustomSlider source, GEvent event) { //_CODE_:csExpl:499811:
explode = csExpl.getValueF();
} //_CODE_:csExpl:499811:
public void csAgg_change1(GCustomSlider source, GEvent event) { //_CODE_:csAgg:315096:
thv.setWait(round((1/csAgg.getValueF())*1000));
} //_CODE_:csAgg:315096:
public void pRegole_Click1(GPanel source, GEvent event) { //_CODE_:pRegole:224665:
} //_CODE_:pRegole:224665:
public void tfLon_change1(GTextField source, GEvent event) { //_CODE_:tfLon:673356:
} //_CODE_:tfLon:673356:
public void tfCrow_change1(GTextField source, GEvent event) { //_CODE_:tfCrow:374114:
} //_CODE_:tfCrow:374114:
public void tfMinN_change1(GTextField source, GEvent event) { //_CODE_:tfMinN:658076:
} //_CODE_:tfMinN:658076:
public void tfMaxN_change1(GTextField source, GEvent event) { //_CODE_:tfMaxN:314532:
} //_CODE_:tfMaxN:314532:
public void button1_click1(GButton source, GEvent event) { //_CODE_:button1:604408:
ogniTot = int(tfOgniTot.getText());
loneliness = int(tfLon.getText());
overcrowding = int(tfCrow.getText());
minNeight = int(tfMinN.getText());
maxNeight = int(tfMaxN.getText());
thv.interrupt();
istanziaBrodo();
thv = new thVita();
} //_CODE_:button1:604408:
public void tfOgniTotchange1(GTextField source, GEvent event) { //_CODE_:tfOgniTot:934471:
} //_CODE_:tfOgniTot:934471:
public void csOpa_change1(GCustomSlider source, GEvent event) { //_CODE_:csOpa:589219:
opacita = int(255 * csOpa.getValueI()/100);
} //_CODE_:csOpa:589219:
// Create all the GUI controls.
// autogenerated do not edit
public void createGUI(){
G4P.messagesEnabled(false);
G4P.setGlobalColorScheme(GCScheme.BLUE_SCHEME);
G4P.setCursor(ARROW);
if(frame != null)
frame.setTitle("Sketch Window");
window1 = new GWindow(this, "Window title", 0, 0, 338, 424, false, JAVA2D);
window1.addDrawHandler(this, "win_draw1");
lExplode = new GLabel(window1.papplet, 20, 30, 80, 20);
lExplode.setText("Explode");
lExplode.setTextBold();
lExplode.setOpaque(false);
csExpl = new GCustomSlider(window1.papplet, 130, 20, 190, 40, "grey_blue");
csExpl.setShowValue(true);
csExpl.setShowLimits(true);
csExpl.setLimits(0.0, 0.0, 100.0);
csExpl.setNumberFormat(G4P.DECIMAL, 2);
csExpl.setLocalColorScheme(GCScheme.CYAN_SCHEME);
csExpl.setOpaque(false);
csExpl.addEventHandler(this, "csExpl_change1");
lAgg = new GLabel(window1.papplet, 10, 80, 100, 30);
lAgg.setText("Aggiornamenti al secondo");
lAgg.setTextBold();
lAgg.setOpaque(false);
csAgg = new GCustomSlider(window1.papplet, 130, 70, 190, 50, "grey_blue");
csAgg.setShowValue(true);
csAgg.setShowLimits(true);
csAgg.setLimits(1.0, 0.3, 5.0);
csAgg.setNbrTicks(5);
csAgg.setNumberFormat(G4P.DECIMAL, 1);
csAgg.setOpaque(false);
csAgg.addEventHandler(this, "csAgg_change1");
pRegole = new GPanel(window1.papplet, 11, 206, 320, 210, "Regole (su 26 cellule adiacenti)");
pRegole.setCollapsible(false);
pRegole.setDraggable(false);
pRegole.setText("Regole (su 26 cellule adiacenti)");
pRegole.setTextBold();
pRegole.setLocalColorScheme(GCScheme.CYAN_SCHEME);
pRegole.setOpaque(true);
pRegole.addEventHandler(this, "pRegole_Click1");
lSeViva = new GLabel(window1.papplet, 10, 30, 80, 20);
lSeViva.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
lSeViva.setText("Se Viva:");
lSeViva.setTextBold();
lSeViva.setOpaque(false);
lSeMorta = new GLabel(window1.papplet, 10, 110, 80, 20);
lSeMorta.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
lSeMorta.setText("Se Morta:");
lSeMorta.setTextBold();
lSeMorta.setOpaque(false);
lmuoveSolit = new GLabel(window1.papplet, 10, 50, 170, 20);
lmuoveSolit.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
lmuoveSolit.setText("Muore se ha meno di");
lmuoveSolit.setOpaque(false);
label1 = new GLabel(window1.papplet, 240, 50, 80, 20);
label1.setText("vicini");
label1.setOpaque(false);
label2 = new GLabel(window1.papplet, 10, 70, 170, 20);
label2.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
label2.setText("Muore se ha più di");
label2.setOpaque(false);
label3 = new GLabel(window1.papplet, 240, 70, 80, 20);
label3.setText("vicini");
label3.setOpaque(false);
label4 = new GLabel(window1.papplet, 10, 130, 170, 20);
label4.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
label4.setText("Vive se ha almeno");
label4.setOpaque(false);
label5 = new GLabel(window1.papplet, 240, 130, 80, 20);
label5.setText("vicini");
label5.setOpaque(false);
label6 = new GLabel(window1.papplet, 10, 150, 170, 20);
label6.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
label6.setText("Vive se ha al massimo");
label6.setOpaque(false);
label7 = new GLabel(window1.papplet, 240, 150, 80, 20);
label7.setText("vicini");
label7.setOpaque(false);
tfLon = new GTextField(window1.papplet, 180, 50, 60, 20, G4P.SCROLLBARS_NONE);
tfLon.setText("3");
tfLon.setLocalColorScheme(GCScheme.CYAN_SCHEME);
tfLon.setOpaque(true);
tfLon.addEventHandler(this, "tfLon_change1");
tfCrow = new GTextField(window1.papplet, 180, 70, 60, 20, G4P.SCROLLBARS_NONE);
tfCrow.setText("20");
tfCrow.setLocalColorScheme(GCScheme.CYAN_SCHEME);
tfCrow.setOpaque(true);
tfCrow.addEventHandler(this, "tfCrow_change1");
tfMinN = new GTextField(window1.papplet, 180, 130, 60, 20, G4P.SCROLLBARS_NONE);
tfMinN.setText("4");
tfMinN.setLocalColorScheme(GCScheme.CYAN_SCHEME);
tfMinN.setOpaque(true);
tfMinN.addEventHandler(this, "tfMinN_change1");
tfMaxN = new GTextField(window1.papplet, 180, 150, 60, 20, G4P.SCROLLBARS_NONE);
tfMaxN.setText("15");
tfMaxN.setLocalColorScheme(GCScheme.CYAN_SCHEME);
tfMaxN.setOpaque(true);
tfMaxN.addEventHandler(this, "tfMaxN_change1");
button1 = new GButton(window1.papplet, 240, 180, 80, 30);
button1.setText("Riavvia simulazione");
button1.setTextBold();
button1.setLocalColorScheme(GCScheme.CYAN_SCHEME);
button1.addEventHandler(this, "button1_click1");
tfOgniTot = new GTextField(window1.papplet, 180, 180, 60, 20, G4P.SCROLLBARS_NONE);
tfOgniTot.setText("2");
tfOgniTot.setOpaque(true);
tfOgniTot.addEventHandler(this, "tfOgniTotchange1");
label8 = new GLabel(window1.papplet, 10, 180, 170, 20);
label8.setTextAlign(GAlign.LEFT, GAlign.MIDDLE);
label8.setText("Fai vivere una cellula ogni");
label8.setOpaque(false);
lOpac = new GLabel(window1.papplet, 10, -70, 80, 20);
lOpac.setText("Opacità");
lOpac.setTextBold();
lOpac.setOpaque(false);
csOpa = new GCustomSlider(window1.papplet, 120, -80, 190, 40, "grey_blue");
csOpa.setShowValue(true);
csOpa.setShowLimits(true);
csOpa.setLimits(20.0, 0.0, 100.0);
csOpa.setNumberFormat(G4P.INTEGER, 0);
csOpa.setLocalColorScheme(GCScheme.CYAN_SCHEME);
csOpa.setOpaque(false);
csOpa.addEventHandler(this, "csOpa_change1");
pRegole.addControl(lSeViva);
pRegole.addControl(lSeMorta);
pRegole.addControl(lmuoveSolit);
pRegole.addControl(label1);
pRegole.addControl(label2);
pRegole.addControl(label3);
pRegole.addControl(label4);
pRegole.addControl(label5);
pRegole.addControl(label6);
pRegole.addControl(label7);
pRegole.addControl(tfLon);
pRegole.addControl(tfCrow);
pRegole.addControl(tfMinN);
pRegole.addControl(tfMaxN);
pRegole.addControl(button1);
pRegole.addControl(tfOgniTot);
pRegole.addControl(label8);
pRegole.addControl(lOpac);
pRegole.addControl(csOpa);
}
// Variable declarations
// autogenerated do not edit
GWindow window1;
GLabel lExplode;
GCustomSlider csExpl;
GLabel lAgg;
GCustomSlider csAgg;
GPanel pRegole;
GLabel lSeViva;
GLabel lSeMorta;
GLabel lmuoveSolit;
GLabel label1;
GLabel label2;
GLabel label3;
GLabel label4;
GLabel label5;
GLabel label6;
GLabel label7;
GTextField tfLon;
GTextField tfCrow;
GTextField tfMinN;
GTextField tfMaxN;
GButton button1;
GTextField tfOgniTot;
GLabel label8;
GLabel lOpac;
GCustomSlider csOpa;

35
GoL3D1/thread.pde Normal file
View file

@ -0,0 +1,35 @@
public class thVita extends Thread {
private boolean running;
private int wait;
public thVita () {
running = true;
this.wait = round((1/csAgg.getValueF())*1000);
this.start();
}
boolean isRunning(){
return this.running;
}
public void setWait(int wait){
this.wait = wait;
//println(wait);
}
void run () {
//apro il socket
while (running) {
try {
//println("agg");
getFate();
Thread.sleep(wait); // 1/40 di secondo
setFate();
}
catch(InterruptedException e) {
running = false;
}
}
}
}

26
LICENSE Normal file
View file

@ -0,0 +1,26 @@
# DON'T BE A DICK PUBLIC LICENSE
> Version 1.1, December 2016
> Copyright (C) 2024 Rossi Stefano
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document.
> DON'T BE A DICK PUBLIC LICENSE
> TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
1. Do whatever you like with the original work, just don't be a dick.
Being a dick includes - but is not limited to - the following instances:
1a. Outright copyright infringement - Don't just copy this and change the name.
1b. Selling the unmodified original with no work done what-so-ever, that's REALLY being a dick.
1c. Modifying the original work to contain hidden harmful content. That would make you a PROPER dick.
2. If you become rich through modifications, related works/services, or supporting the original work,
share the love. Only a dick would make loads off this work and not buy the original work's
creator(s) a pint.
3. Code is provided with no warranty. Using somebody else's code and bitching when it goes wrong makes
you a DONKEY dick. Fix the problem yourself. A non-dick would submit the fix back.

100
README.md Normal file
View file

@ -0,0 +1,100 @@
# Game Of life 3D
This is a 3D version of Conway's Game of Life.
Always wonder how Conway's game of life would develops in a 3D environnment? now you can!
- 3D interface (rotate, zoom, and explode)
- Settings GUI to change GOL3D rules run-time
- Play/Pause the simulation
- Color based on future cell state
It is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input.
One interacts with the Game of Life by creating an initial configuration and observing how it evolves.
In this version you can change the rules of the game and see the simulation in a 3D environment.
**Note: the demo following gif takes a while to load**
![gif](images/Gol3d.gif)
## Running the project
### Requirements
- [Java 7](https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html)
### Executable
The project is already compiled and ready to run. You can download the executable for windows and linux here: [releases](https://gitlab.com/stefanorossiti/gameOfLife3D/-/releases)
## Instructions
Start the project, you can move the camera with your mouse
![Scheme](images/3d.png)
You can change game rules and view settings
![Scheme](images/menu.png)
Rules settings translation:
If alive:
- dies with less than `{specified}` neighbours
- dies with more than `{specified}` neighbours
If dead:
- dies with more than `{specified}` neighbours
- dies with less than `{specified}` neighbours
## Development Requirements
This program run with [Processing 2.2.2](https://processing.org/). Processing is a **standalone** client.
You must use the right versions otherwise the progect wont work.
[Processing 2.2.1](https://processing.org/releases) (search for the correct archieved version)
### Libraries
These 2 libraries are needed to add more views to the GUIs.
- [G4P 3.5.4](https://sourceforge.net/projects/g4p/files/?source=navbar) (search the correct archieved version)
- [PFrame](https://github.com/shigeodayo/PFrame)
Extract both libraries in a separate folder into sketchbook libraries folder:
- Default libraries folder: `<user>\Documents\Processing\libraries`. If it doesn't exist, create it.
![alt text](images/libsPath.png)
You can now open processing and run the project.
### Alternative downloads
I did a backup of the dependencies in case the original links are down.
[Google Drive](https://drive.google.com/drive/folders/1ik1m29vXTRL1l6UIpJSqgC5Y5LQx7pbR?usp=sharing)
And the 2 libraries are in the repository itlself in the `Backups_libraries` folder.
### Run
Clone the repo, install both libraries and open with processing 2.2.1 the folder `GoL3D`, press play.
```bash
git clone https://gitlab.com/stefanorossiti/gameOfLife3D.git
```
## License
Released under [DBAD](https://www.dbad-license.org/) license.

BIN
images/3d.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
images/Gol3d.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 MiB

BIN
images/libsPath.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9 KiB

BIN
images/menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB