Skip to content
Snippets Groups Projects
Commit 04b65a9f authored by Colin DAMON's avatar Colin DAMON
Browse files

Game of life implementation

parent 8d58b798
No related branches found
No related tags found
1 merge request!58Resolve "Game of life"
package fr.ippon.life;
import java.util.Set;
public class Cell {
private static final int LOW_POPULATION_THRESHOLD = 2;
private static final int HIGH_POPULATION_THRESHOLD = 3;
private static final int BORN_THRESHOLD = HIGH_POPULATION_THRESHOLD;
private final int row;
private final int column;
public Cell(int row, int column) {
this.row = row;
this.column = column;
}
boolean stayAlive(Set<Cell> aliveCells) {
long neighbourgCount = countNeigbours(aliveCells);
return neighbourgCount == LOW_POPULATION_THRESHOLD || neighbourgCount == HIGH_POPULATION_THRESHOLD;
}
boolean born(Set<Cell> aliveCells) {
return countNeigbours(aliveCells) == BORN_THRESHOLD;
}
private long countNeigbours(Set<Cell> aliveCells) {
return aliveCells.stream().filter(this::isNeighbour).count();
}
private boolean isNeighbour(Cell other) {
if (other.equals(this)) {
return false;
}
return delta(row, other.row) <= 1 && delta(column, other.column) <= 1;
}
private static int delta(int first, int second) {
return Math.abs(first - second);
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + column;
result = prime * result + row;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Cell other = (Cell) obj;
if (column != other.column) return false;
if (row != other.row) return false;
return true;
}
}
package fr.ippon.life;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class Generation {
private Set<Cell> aliveCells;
public Generation(Cell... aliveCells) {
this(Set.of(aliveCells));
}
private Generation(Set<Cell> cells) {
aliveCells = cells;
}
public Generation next() {
Stream<Cell> stayAlive = aliveCells.stream().filter(cell -> cell.stayAlive(aliveCells));
Stream<Cell> born = buildGrid().deadCells().stream().filter(cell -> cell.born(aliveCells));
Set<Cell> cells = Stream.concat(stayAlive, born).collect(Collectors.toUnmodifiableSet());
return new Generation(cells);
}
public Collection<Cell> getAliveCells() {
return aliveCells;
}
private Grid buildGrid() {
return new Grid(aliveCells);
}
}
package fr.ippon.life;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Grid {
private final Set<Cell> deadCells;
private final Box box;
Grid(Set<Cell> cells) {
box = new Box(cells);
this.deadCells = buildDeadCells(cells);
}
private Set<Cell> buildDeadCells(Set<Cell> cells) {
return IntStream
.range(box.getTopRow(), box.getBottomRow())
.mapToObj(Integer::valueOf)
.flatMap(row -> toDeadCell(cells, row))
.collect(Collectors.toUnmodifiableSet());
}
private Stream<Cell> toDeadCell(Set<Cell> cells, int row) {
return IntStream
.range(box.getLeftColumn(), box.getRightColumn())
.mapToObj(column -> new Cell(row, column))
.filter(cell -> !cells.contains(cell));
}
public Collection<Cell> deadCells() {
return deadCells;
}
private static class Box {
private final Point topLeft;
private final Point bottomRight;
public Box(Set<Cell> cells) {
topLeft = Point.topLeft(cells);
bottomRight = Point.bottomRight(cells);
}
public int getTopRow() {
return topLeft.getRow();
}
public int getBottomRow() {
return bottomRight.getRow() + 1;
}
public int getLeftColumn() {
return topLeft.getColumn();
}
public int getRightColumn() {
return bottomRight.getColumn() + 1;
}
}
private static class Point {
private final int row;
private final int column;
public Point(int row, int column) {
this.row = row;
this.column = column;
}
private static Point topLeft(Set<Cell> cells) {
int row = cells.stream().mapToInt(Cell::getRow).min().orElse(0);
int column = cells.stream().mapToInt(Cell::getColumn).min().orElse(0);
return new Point(row - 1, column - 1);
}
private static Point bottomRight(Set<Cell> cells) {
int row = cells.stream().mapToInt(Cell::getRow).max().orElse(0);
int column = cells.stream().mapToInt(Cell::getColumn).max().orElse(0);
return new Point(row + 1, column + 1);
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
}
}
package fr.ippon.life;
import static org.assertj.core.api.Assertions.*;
import org.junit.jupiter.api.Test;
class GameOfLifeTest {
@Test
void nextGenerationShouldHaveAllDeadCellsForAllDeadGrid() {
Generation nextGeneration = new Generation().next();
assertThat(nextGeneration.getAliveCells()).isEmpty();
}
@Test
void nextGenerationShouldHaveAllDeadCellsFromOneAliveCell() {
Generation nextGeneration = new Generation(cell(1, 1)).next();
assertThat(nextGeneration.getAliveCells()).isEmpty();
}
@Test
void nextGenerationShouldHaveAllDeadCellsFromTwoContiguousAliveCells() {
Generation nextGeneration = new Generation(cell(1, 1), cell(2, 1)).next();
assertThat(nextGeneration.getAliveCells()).isEmpty();
}
@Test
void nextGenerationShouldHaveFourAliveCellsFromTriangularConfiguration() {
Cell first = cell(1, 2);
Cell second = cell(2, 1);
Cell third = cell(2, 2);
Generation nextGeneration = new Generation(first, second, third).next();
assertThat(nextGeneration.getAliveCells()).containsExactlyInAnyOrder(cell(1, 1), first, second, third);
}
@Test
void nextGenerationShouldHaveOneColumnFromOneLine() {
Generation nextGeneration = new Generation(cell(4, 5), cell(5, 5), cell(6, 5)).next();
assertThat(nextGeneration.getAliveCells()).containsExactlyInAnyOrder(cell(5, 4), cell(5, 5), cell(5, 6));
}
@Test
void shouldAdvanceInGenerations() {
Generation nextGeneration = threeCellsColumn();
assertThat(nextGeneration.getAliveCells()).containsExactlyInAnyOrder(cell(4, 5), cell(5, 5), cell(6, 5));
}
private Generation threeCellsColumn() {
return new Generation(cell(4, 5), cell(5, 5), cell(6, 5)).next().next();
}
private static Cell cell(int row, int column) {
return new Cell(row, column);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment