From 8d7c46f965136b66135b15d270842965651a896f Mon Sep 17 00:00:00 2001 From: Thomas Papendieck Date: Wed, 18 Jan 2023 07:53:55 +0100 Subject: [PATCH] procedural and OOP --- .../java/de/hsfulda/pmuw/CgolLauncher.java | 12 +++ .../java/de/hsfulda/pmuw/oop/CellCreator.java | 73 +++++++++++++++++ .../de/hsfulda/pmuw/oop/CgolBoardOop.java | 59 ++++++++++++++ .../java/de/hsfulda/pmuw/oop/CgolCell.java | 51 ++++++++++++ .../de/hsfulda/pmuw/oop/NeighborPosition.java | 24 ++++++ .../hsfulda/pmuw/oop/StateChangeListener.java | 4 + .../pmuw/procedural/CgolBoardProcedural.java | 80 +++++++++++++++++++ 7 files changed, 303 insertions(+) create mode 100644 src/main/java/de/hsfulda/pmuw/CgolLauncher.java create mode 100644 src/main/java/de/hsfulda/pmuw/oop/CellCreator.java create mode 100644 src/main/java/de/hsfulda/pmuw/oop/CgolBoardOop.java create mode 100644 src/main/java/de/hsfulda/pmuw/oop/CgolCell.java create mode 100644 src/main/java/de/hsfulda/pmuw/oop/NeighborPosition.java create mode 100644 src/main/java/de/hsfulda/pmuw/oop/StateChangeListener.java create mode 100644 src/main/java/de/hsfulda/pmuw/procedural/CgolBoardProcedural.java diff --git a/src/main/java/de/hsfulda/pmuw/CgolLauncher.java b/src/main/java/de/hsfulda/pmuw/CgolLauncher.java new file mode 100644 index 0000000..c77de88 --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/CgolLauncher.java @@ -0,0 +1,12 @@ +package de.hsfulda.pmuw; + +import de.hsfulda.pmuw.oop.CgolBoardOop; +import de.hsfulda.pmuw.procedural.CgolBoardProcedural; + +public class CgolLauncher { + public static void main(String[] args) { + CgolBoardProcedural.main(null); + CgolBoardOop.main(null); + } + +} diff --git a/src/main/java/de/hsfulda/pmuw/oop/CellCreator.java b/src/main/java/de/hsfulda/pmuw/oop/CellCreator.java new file mode 100644 index 0000000..c1eccf6 --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/oop/CellCreator.java @@ -0,0 +1,73 @@ +package de.hsfulda.pmuw.oop; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class CellCreator { + + /** one alive to X dead */ + private static final int ALIVE_CELLS_RATIO = 30; + private static final int BOARD_SIZE = 500; + public static List aliveList = new Random().ints(0, ALIVE_CELLS_RATIO).limit(BOARD_SIZE * BOARD_SIZE) + .mapToObj(Integer::valueOf).map(i -> Boolean.valueOf(i == 0)).collect(Collectors.toList()); + + int calculateNeighbourIndex(List allCells, CgolCell cgolCell, NeighborPosition neighborPosition) { + int row = cgolCell.row; + int column = cgolCell.column; + int size = allCells.size(); + int index = neighborPosition.getIndex(row, column, BOARD_SIZE); + int finalIndex = (index + size) % size; + return finalIndex; + } + + protected void createCells(Collection activeCells, boolean isOptimized) { + StateChangeListener changeListener = getChangeListener(activeCells, isOptimized); + List allCells = createCells(changeListener); + constructGameField(activeCells, isOptimized, allCells); + System.out.println(String.format("active cells: %7s", activeCells.size())); + System.out.println(String.format("alive cells : %7s", allCells.stream().filter(CgolCell::isAlive).count())); + } + + private StateChangeListener getChangeListener(Collection activeCells, boolean isOptimized) { + StateChangeListener changeListener = isOptimized ? nc -> activeCells.add(nc) : nc -> { + ; + }; + return changeListener; + } + + private List createCells(StateChangeListener changeListener) { + Iterator iterator = aliveList.iterator(); + List allCells = new ArrayList<>(); + for (int row = 0; row < BOARD_SIZE; row++) + for (int col = 0; col < BOARD_SIZE; col++) + allCells.add(new CgolCell(row, col, iterator.next(), changeListener)); + + System.out.println(String.format("cells created: %7s", allCells.size())); + return allCells; + } + + private void constructGameField(Collection activeCells, boolean isOptimized, List allCells) { + for (CgolCell cgolCell : allCells) { + Set neighbors = Stream.of(NeighborPosition.values()) + .map(np -> calculateNeighbourIndex(allCells, cgolCell, np)).map(allCells::get).collect(Collectors.toSet()); + cgolCell.setNeighbors(neighbors); + + if (cgolCell.isAlive()) { + if (isOptimized) { + activeCells.add(cgolCell); + activeCells.addAll(neighbors); + } + } + } + if (!isOptimized) { + activeCells.addAll(allCells); + } + } + +} diff --git a/src/main/java/de/hsfulda/pmuw/oop/CgolBoardOop.java b/src/main/java/de/hsfulda/pmuw/oop/CgolBoardOop.java new file mode 100644 index 0000000..3e55879 --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/oop/CgolBoardOop.java @@ -0,0 +1,59 @@ +package de.hsfulda.pmuw.oop; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; + +public class CgolBoardOop { + private final Collection activeCells ; + private final CellCreator cellCreator; + private boolean isOptimized; + + CgolBoardOop(CellCreator cellCreator, boolean isOptimized) { + this.cellCreator = cellCreator; + this.isOptimized = isOptimized; + activeCells = isOptimized? new HashSet<>():new ArrayList<>(); + } + + public void initialize() { + cellCreator.createCells(activeCells, isOptimized); + } + + public void nextGen() { + List currentGeneration = new ArrayList<>(activeCells); + if (isOptimized) + activeCells.clear(); + currentGeneration.stream().parallel().forEach(CgolCell::calculateNextGeneration); + currentGeneration.stream().parallel().forEach(CgolCell::switchState); + } + private long countAliveCells() { + return activeCells.stream().filter(CgolCell::isAlive).count(); + } + + public static void main(String[] args) { + boolean isOptimized = true; + startGame(!isOptimized); + startGame(isOptimized); + } + + private static void startGame(boolean isOptimized) { + long start = Calendar.getInstance().getTimeInMillis(); + CgolBoardOop cgolBoard = new CgolBoardOop(new CellCreator(), isOptimized); + cgolBoard.initialize(); + long end = Calendar.getInstance().getTimeInMillis(); + System.out.println(String.format("initializing took: %sms", end - start)); + start = Calendar.getInstance().getTimeInMillis(); + int iterations = 1000; + for (int i = 0; i < iterations; i++) { + cgolBoard.nextGen(); + if (0 == i % (isOptimized? 100:100)) + System.out.println(String.format("iteration %6d cells alife: %7s , cells active %7s",i,cgolBoard.countAliveCells(),cgolBoard.activeCells.size())); + } + end = Calendar.getInstance().getTimeInMillis(); + System.out.println( + String.format("time spend for %d iterations: %sms, optimized: %s\n\n", iterations, end - start, isOptimized)); + } + +} \ No newline at end of file diff --git a/src/main/java/de/hsfulda/pmuw/oop/CgolCell.java b/src/main/java/de/hsfulda/pmuw/oop/CgolCell.java new file mode 100644 index 0000000..38f24bd --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/oop/CgolCell.java @@ -0,0 +1,51 @@ +package de.hsfulda.pmuw.oop; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +public class CgolCell { + private final StateChangeListener listener; + private CgolCell[] neighbors; + private boolean isAlive, nextState; + final int row, column; + + public CgolCell(int row, int column, boolean isAlive, StateChangeListener listener) { + super(); + this.row = row; + this.column = column; + this.isAlive = this.nextState = isAlive; + this.listener = listener; + } + + public boolean isAlive() { + return isAlive; + } + + public void setNeighbors(Set neighbors) { + this.neighbors = neighbors.toArray(new CgolCell[0]); +// System.out.print(neighbors.stream().map(n -> String.format("(r%d-c%d %s)", n.row, n.column ,n.isAlive?"*":"-")) +// .collect(Collectors.joining("", String.format("cell r%d-c%d:\n ", row, column), "\n"))); + } + + void calculateNextGeneration() { + int alifeNeigborsCount =0; + for (CgolCell cgolCell : neighbors) { + alifeNeigborsCount+= cgolCell.isAlive?1:0; + } + nextState = 3 == alifeNeigborsCount || (isAlive && (2 == alifeNeigborsCount)); + } + + void switchState() { + if (isAlive || nextState) { + for (CgolCell cgolCell : neighbors) { + listener.addActiveCell(cgolCell); + } + listener.addActiveCell(this); + } + isAlive = nextState; + } + +} diff --git a/src/main/java/de/hsfulda/pmuw/oop/NeighborPosition.java b/src/main/java/de/hsfulda/pmuw/oop/NeighborPosition.java new file mode 100644 index 0000000..f96048a --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/oop/NeighborPosition.java @@ -0,0 +1,24 @@ +package de.hsfulda.pmuw.oop; + +public enum NeighborPosition { + NORTH(-1, 0), + SOUTH(1, 0), + EAST(0, 1), + WEST(0, -1), + NORTH_EAST(-1, 1), + SOUTH_EAST(1, 1), + SOUTH_WEST(1, -1), + NORTH_WEST(-1, -1); + + private final int rowOffset; + private final int columnOffset; + + NeighborPosition(int rowOffset, int columnOffset) { + this.rowOffset = rowOffset; + this.columnOffset = columnOffset; + } + + int getIndex(int row, int column, int rowSize) { + return (((row + rowOffset) * rowSize) + column + columnOffset); + } +} diff --git a/src/main/java/de/hsfulda/pmuw/oop/StateChangeListener.java b/src/main/java/de/hsfulda/pmuw/oop/StateChangeListener.java new file mode 100644 index 0000000..38cbd80 --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/oop/StateChangeListener.java @@ -0,0 +1,4 @@ +package de.hsfulda.pmuw.oop; +interface StateChangeListener { + void addActiveCell(T cell); +} \ No newline at end of file diff --git a/src/main/java/de/hsfulda/pmuw/procedural/CgolBoardProcedural.java b/src/main/java/de/hsfulda/pmuw/procedural/CgolBoardProcedural.java new file mode 100644 index 0000000..f25d773 --- /dev/null +++ b/src/main/java/de/hsfulda/pmuw/procedural/CgolBoardProcedural.java @@ -0,0 +1,80 @@ +package de.hsfulda.pmuw.procedural; + +import java.util.Calendar; +import java.util.Iterator; + +import de.hsfulda.pmuw.oop.CellCreator; + +public class CgolBoardProcedural { + /** one alive to X dead */ + static final int ALIVE_CELLS_RATIO = 30; + static final int BOARD_SIZE = 500; + private boolean[][] board = new boolean[BOARD_SIZE][BOARD_SIZE]; + + public void initialize() { + createCells(); + System.out.println(String.format("cells created: %7s", BOARD_SIZE*BOARD_SIZE)); + System.out.println(String.format("active cells: %7s", BOARD_SIZE*BOARD_SIZE)); + System.out.println(String.format("alive cells : %7s", countAliveCells())); + + } + + private void createCells() { + Iterator iterator = CellCreator.aliveList.iterator(); + for (int row = 0; row < board.length; row++) + for (int col = 0; col < board[0].length; col++) + board[row][col] = iterator.next(); + } + + public void nextGen() { + boolean[][] nextGen = new boolean[BOARD_SIZE][BOARD_SIZE]; + for (int row = 0; row < board.length; row++) + for (int col = 0; col < board[0].length; col++) + nextGen[row][col] = newStateOfCell(row, col); + board = nextGen; + } + + private boolean newStateOfCell(int row, int col) { + int countAliveNeighbors = countAliveNeighbors(row, col); + return newState(countAliveNeighbors, board[row][col]); + } + + private int countAliveNeighbors(int row, int col) { + int aliveNeighbors = 0; + for (int rOffset = -1; rOffset <= 1; rOffset++) + for (int cOffset = -1; cOffset <= 1; cOffset++) + aliveNeighbors += board[(row + rOffset + BOARD_SIZE) % BOARD_SIZE][(col + cOffset + BOARD_SIZE) % BOARD_SIZE] + ? 1 + : 0; + return aliveNeighbors - (board[row][col] ? 1 : 0); + } + + private boolean newState(int aliveNeighbors, boolean isAlive) { + return 3 == aliveNeighbors || (isAlive && 2 == aliveNeighbors); + } + + private int countAliveCells() { + int aliveCells = 0; + for (int row = 0; row < board.length; row++) + for (int col = 0; col < board[0].length; col++) + aliveCells += board[row][col] ? 1 : 0; + return aliveCells; + } + + public static void main(String[] args) { + long start = Calendar.getInstance().getTimeInMillis(); + CgolBoardProcedural cgolBoard = new CgolBoardProcedural(); + cgolBoard.initialize(); + long end = Calendar.getInstance().getTimeInMillis(); + System.out.println(String.format("initializing took: %sms", end - start)); + start = Calendar.getInstance().getTimeInMillis(); + int iterations = 1000; + for (int i = 0; i < iterations; i++) { + cgolBoard.nextGen(); + if (0 == i % 100) + System.out.println(String.format("iteration %6d cells alife: %s , cells active %7s", i, cgolBoard.countAliveCells(),BOARD_SIZE*BOARD_SIZE)); + } + end = Calendar.getInstance().getTimeInMillis(); + System.out.println(String.format("time spend for %d iterations: %sms\n\n", iterations, end - start)); + } +} \ No newline at end of file