Created
November 28, 2022 17:07
-
-
Save denkspuren/4c19d39dfb14caaf6d40ed9ee7b6fb75 to your computer and use it in GitHub Desktop.
Conway's Game of Life
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
class GoL { | |
int width, height; | |
int[] world; | |
GoL(int width, int height) { | |
assert width >= 1 && height >= 1; | |
this.width = width + 2; // ergänze "unsichtbaren" Rand links und rechts | |
this.height = height + 2; // ergänze "unsichtbaren" Rand oben und unten | |
this.world = new int[this.width * this.height]; | |
} | |
GoL set(int row, int col) { | |
assert row >= 1 && row < height - 1 : "1 <= row < " + (height - 1); | |
assert col >= 1 && col < width - 1 : "1 <= col < " + (width - 1); | |
world[row * width + col] = 1; | |
return this; | |
} | |
int rule(int center) { | |
int[] neighbours = new int[]{center - 1, center + 1, center + width, center - width, // left, right, above, below | |
center - width - 1, center - width + 1, // top left/right | |
center + width - 1, center + width + 1}; // bottom left/right | |
int LIVE = 1, DEAD = 0, count = 0; | |
for (int pos : neighbours) count += world[pos]; | |
if (world[center] == DEAD) return count == 3 ? LIVE : DEAD; | |
if (count == 2 || count == 3) return LIVE; | |
return DEAD; // underpopulation: count < 2, overpopulation: count > 3 | |
} | |
void timestep() { | |
int[] newWorld = new int[world.length]; | |
for (int row = 1; row < height - 1; row++) { | |
for (int col = 1; col < width - 1; col++) { | |
int pos = row * width + col; | |
newWorld[pos] = rule(pos); | |
} | |
} | |
world = newWorld; | |
} | |
@Override public String toString() { | |
String s = ""; | |
char[] symbols = new char[]{'.', '*'}; | |
for (int row = 1; row < height - 1; row++) { | |
for (int col = 1; col < width - 1; col++) { | |
int pos = row * width + col; | |
s += symbols[world[pos]]; | |
} | |
s += row != height ? "\n" : ""; | |
} | |
return s; | |
} | |
void run(int steps) { | |
while (steps-- >= 1) { | |
timestep(); | |
System.out.println(this); | |
} | |
} | |
GoL insert(int row, int col, GoL source) { | |
for (int y = 1; y < source.height - 1; y++) { | |
for (int x = 1; x < source.width - 1; x++) { | |
int sourcePos = y * source.width + x; | |
int targetRef = (row - 1) * width + (col - 1); | |
int targetPos = targetRef + y * width + x; | |
world[targetPos] = source.world[sourcePos]; | |
} | |
} | |
return this; | |
} | |
} | |
GoL block = new GoL(2,2).set(1,1).set(1,2).set(2,1).set(2,2); | |
GoL boat = new GoL(3,3).set(1,1).set(1,2).set(2,1).set(2,3).set(3,2); | |
GoL blinker = new GoL(3,1).set(1,1).set(1,2).set(1,3); | |
GoL glider = new GoL(3,3).set(1,3).set(2,3).set(3,3).set(2,1).set(3,2); | |
/* | |
Achtung: Die JShell verkürzt Ausgaben auf der Konsole, d.h. das Spielfeld von | |
GoL wird durch `toString` möglicherweise unvollständig angezeigt. | |
Spielfeldausgaben sollten ein `System.out.println` verwenden. | |
~~~ | |
jshell> GoL g = new GoL(10,10) | |
g ==> .......... | |
.......... | |
.......... | |
.......... | |
..... ... ... | |
.......... | |
.......... | |
jshell> System.out.println(g) | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
.......... | |
~~~ | |
*/ | |
GoL smallWorld = new GoL(20,15).insert(2,1,glider); | |
// smallWorld.run(20) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment