flood it game

This commit is contained in:
Nathan Howard 2025-12-16 19:47:22 -08:00
parent 8a6b62ed07
commit 5c3e3909d1
6 changed files with 548 additions and 0 deletions

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" path="src"/>
<classpathentry kind="lib" path="/Users/nathanhoward/Documents/Code/OSSU-CS/completedwork/core_programming/02_classbased_design/Jars/javalib.jar"/>
<classpathentry kind="lib" path="/Users/nathanhoward/Documents/Code/OSSU-CS/completedwork/core_programming/02_classbased_design/Jars/tester.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Assn09_FloodIt</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=11
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=11

View File

@ -0,0 +1,259 @@
import java.util.ArrayList;
import javalib.impworld.*;
import java.awt.Color;
import javalib.worldimages.*;
import java.util.Random;
// Represents a single square of the game area
class Cell {
// In logical coordinates, with the origin at the top-left corner of the screen
int x;
int y;
Color color;
boolean flooded;
// the four adjacent cells to this one
Cell left;
Cell right;
Cell top;
Cell bottom;
Cell(int x, int y, Color color, boolean flooded,
Cell left, Cell right, Cell top, Cell bottom) {
this.x = x;
this.y = y;
this.color = color;
this.flooded = flooded;
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
}
Cell(int x, int y, Color color) {
this(x, y, color, false, null, null, null, null);
}
//returns a rectangle image of this cell
WorldImage drawCell(int tileAxis) {
return new RectangleImage(
FloodItWorld.BOARD_SIZE / tileAxis,
FloodItWorld.BOARD_SIZE / tileAxis,
OutlineMode.SOLID, this.color);
}
}
class Board {
ArrayList<Cell> cells;
int size; // tiles vert & horz, board is always square
Board(ArrayList<Cell> cells, int size) {
this.cells = cells;
this.size = size;
}
Board() {
this.size = FloodItWorld.DEFAULT_TILE_COUNT;
generateRandomBoard(new Random());
makeConnections();
}
Board(int size) {
this.size = size;
generateRandomBoard(new Random());
makeConnections();
}
Board(int size, int seed) {
this.size = size;
generateRandomBoard(new Random(seed));
makeConnections();
}
// generates a random board
void generateRandomBoard(Random rand) {
this.cells = new ArrayList<Cell>();
for (int i = 0; i < size * size; i++) {
this.cells.add(new Cell(i % size, i / size, randomColor(rand.nextInt(6))));
}
}
// returns a random color
Color randomColor(int rand) {
switch (rand) {
case 0:
return Color.red;
case 1:
return Color.yellow;
case 2:
return Color.blue;
case 3:
return Color.pink;
case 4:
return Color.orange;
case 5:
return Color.green;
default:
return Color.black;
}
}
// adds the flooded status and directional connections to each cell
void makeConnections() {
// first (top left / idx 0) cell is always flooded
this.cells.get(0).flooded = true;
for (int i = 0; i < this.cells.size(); i++) {
Cell cell = cells.get(i);
if (cell.x > 0) {
cell.left = this.cells.get(i - 1);
}
if (cell.x < this.size - 1) {
cell.right = this.cells.get(i + 1);
}
if (cell.y > 0) {
cell.top = this.cells.get(i - this.size);
}
if (cell.y < this.size - 1) {
cell.bottom = this.cells.get(i + this.size);
}
}
// floods all tiles where an adjacent tile is flooded and color matches flood
Color floodedColor = this.cells.get(0).color;
for (Cell cell : this.cells) {
if (((cell.left != null && cell.left.flooded) ||
(cell.top != null && cell.top.flooded) ||
(cell.right != null && cell.right.flooded) ||
(cell.bottom != null && cell.bottom.flooded)) &&
cell.color.equals(floodedColor)) {
cell.flooded = true;
}
}
}
// returns the cell in provided the position
Cell findCell(Posn pos) {
int cellPxSize = (FloodItWorld.BOARD_SIZE / this.size);
for (Cell cell : this.cells) {
if ((pos.x >= cell.x * cellPxSize && pos.x < (cell.x + 1) * cellPxSize) &&
(pos.y >= cell.y * cellPxSize && pos.y < (cell.y + 1) * cellPxSize)) {
return cell;
}
}
throw new IllegalArgumentException("Cannot Place Key Press" + pos.x + " " + pos.y);
// // !!! something is wrong with my math here and i cant figure it out
// int findX, findY;
// // protect from div 0
// if (pos.x == 0) {
// findX = 0;
// } else {
// findX = (int) Math.floor(this.size / (int) Math.floor(FloodItWorld.BOARD_SIZE / pos.x));
// }
// // protect from div 0
// if (pos.y == 0) {
// findY = 0;
// } else {
// findY = (int) Math.floor(this.size / (int) Math.floor(FloodItWorld.BOARD_SIZE / pos.y));
// }
// for (Cell cell : this.cells) {
// if (cell.x == findX && cell.y == findY) {
// return cell;
// }
// }
// throw new IllegalArgumentException("Cannot Place Key Press" + findX + " " + findY);
}
// sets all flooded tiles to the provided color
void updateColor(Color color) {
for (Cell cell : this.cells) {
if (cell.flooded) {
cell.color = color;
}
}
}
// sets flooded status of all tiles of the provided color and
// adjacent to a flooded tile
void updateFloodStatus(Color color) {
for (Cell cell : this.cells) {
if (((cell.left != null && cell.left.flooded) ||
(cell.right != null && cell.right.flooded) ||
(cell.top != null && cell.top.flooded) ||
(cell.bottom != null && cell.bottom.flooded)) &&
cell.color == color) {
cell.flooded = true;
}
}
}
// updates the color of flooded cells to match clicked cell
// any cells with the same color as clicked will become flooded
void floodCells(Posn pos) {
Color floodColor = this.findCell(pos).color;
this.updateColor(floodColor);
this.updateFloodStatus(floodColor);
}
// returns a world image of all the cells stitched together
WorldScene drawBoard(WorldScene scene) {
int tileLength = FloodItWorld.BOARD_SIZE / this.size;
for (Cell cell : this.cells) {
scene.placeImageXY(
cell.drawCell(this.size),
(cell.x * tileLength) + (tileLength / 2),
(cell.y * tileLength) + (tileLength / 2));
}
return scene;
}
}
class FloodItWorld extends World {
// constants
static int BOARD_SIZE = 256;
static int DEFAULT_TILE_COUNT = 16;
static Color TEXT_COLOR = Color.black;
// All the cells of the game
Board board;
int score;
int time;
FloodItWorld(Board board) {
this.board = board;
this.score = 0;
this.time = 0;
}
FloodItWorld(int seed) {
this(new Board(DEFAULT_TILE_COUNT, seed));
}
FloodItWorld(int size, int seed) {
this(new Board(size, seed));
}
FloodItWorld() {
this(new Board());
}
// resets the game to default start conditions
void reset() {
this.board = new Board();
this.score = 0;
this.time = 0;
}
// draws the game scene
public WorldScene makeScene() {
WorldScene scene = new WorldScene(
FloodItWorld.BOARD_SIZE,
FloodItWorld.BOARD_SIZE);
scene = this.board.drawBoard(scene);
scene.placeImageXY(
new TextImage("" + this.score, FloodItWorld.TEXT_COLOR),
10, 10);
scene.placeImageXY(
new TextImage(this.time / 3600 + ":" + this.time / 60 + ":" + this.time % 60,
FloodItWorld.TEXT_COLOR),
BOARD_SIZE - 30, 10);
return scene;
}
// floods the board with the color at the location clicked
public void onMouseClicked(Posn pos) {
this.board.floodCells(pos);
this.score++;
}
// reset game when r is pressed
public void onKeyEvent(String k) {
if (k.equals("r")) {
reset();
}
}
// increments the time counter every second
public void onTick() {
this.time++;
}
}

View File

@ -0,0 +1,247 @@
import tester.Tester;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import javalib.impworld.World;
import javalib.worldimages.Posn;
class Examples {
Cell cellSmall1;
Cell cellSmall2;
Cell cellSmall3;
Cell cellSmall4;
Board boardTest1;
Board boardTest2;
Board boardTest3;
Board boardTestSmall;
Board boardSolved;
Board boardRandom;
FloodItWorld gameBoard;
FloodItWorld gameRandom;
FloodItWorld gameRandom2;
void init() {
// @formatter:off
boardTest1 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.red ), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.blue))),
4);
boardTest2 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.red ), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.green))),
4);
boardTest3 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.blue), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.green))),
4);
boardSolved = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.blue), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.blue))),
4);
// x y color flooded left right top bottom
cellSmall1 = new Cell(0, 0, Color.red , true, null, cellSmall2, null, cellSmall3);
cellSmall2 = new Cell(1, 0, Color.blue, true, cellSmall1, null, null, cellSmall4 );
cellSmall3 = new Cell(0, 1, Color.blue, true, null, cellSmall4, cellSmall1, null );
cellSmall4 = new Cell(1, 1, Color.blue, true, cellSmall3, null, cellSmall2, null );
boardTestSmall = new Board(new ArrayList<Cell>(Arrays.asList(
cellSmall1, cellSmall2, cellSmall3, cellSmall4)),
2);
// @formatter:on
gameBoard = new FloodItWorld(boardTest1);
// Should make the same boards
boardRandom = new Board(16, 314);
gameRandom = new FloodItWorld(314);
gameRandom2 = new FloodItWorld(4, 314);
}
void testConstructor(Tester t) {
init();
t.checkExpect(boardTest1.size, 4);
t.checkExpect(boardRandom.size, 16);
t.checkExpect(gameRandom2.board.size, 4);
t.checkExpect(gameBoard.board, boardTest1);
t.checkExpect(gameRandom.board, boardRandom);
t.checkExpect(boardRandom.cells.size(), 256); // 16*16
t.checkExpect(gameRandom2.board.cells.size(), 16); // 4*4
}
void testRandomColor(Tester t) {
init();
t.checkExpect(boardTest1.randomColor(0), Color.red);
t.checkExpect(boardTest1.randomColor(1), Color.yellow);
t.checkExpect(boardTest1.randomColor(2), Color.blue);
t.checkExpect(boardTest1.randomColor(3), Color.pink);
t.checkExpect(boardTest1.randomColor(4), Color.orange);
t.checkExpect(boardTest1.randomColor(5), Color.green);
t.checkExpect(boardTest1.randomColor(100), Color.black);
}
void testMakeConnection(Tester t) {
init();
this.boardTest1.makeConnections();
t.checkExpect(boardTest1.cells.get(0).left, null);
t.checkExpect(boardTest1.cells.get(0).right, boardTest1.cells.get(1));
t.checkExpect(boardTest1.cells.get(0).top, null);
t.checkExpect(boardTest1.cells.get(0).bottom, boardTest1.cells.get(4));
t.checkExpect(boardTest1.cells.get(6).left, boardTest1.cells.get(5));
t.checkExpect(boardTest1.cells.get(6).right, boardTest1.cells.get(7));
t.checkExpect(boardTest1.cells.get(6).top, boardTest1.cells.get(2));
t.checkExpect(boardTest1.cells.get(6).bottom, boardTest1.cells.get(10));
t.checkExpect(boardTest1.cells.get(4).left, null);
t.checkExpect(boardTest1.cells.get(7).right, null);
t.checkExpect(boardTest1.cells.get(3).top, null);
t.checkExpect(boardTest1.cells.get(13).bottom, null);
t.checkExpect(boardTest1.cells.get(15).left, boardTest1.cells.get(14));
t.checkExpect(boardTest1.cells.get(15).right, null);
t.checkExpect(boardTest1.cells.get(15).top, boardTest1.cells.get(11));
t.checkExpect(boardTest1.cells.get(15).bottom, null);
t.checkExpect(boardTest1.cells.get(0).flooded, true);
t.checkExpect(boardTest1.cells.get(1).flooded, false);
t.checkExpect(boardTest1.cells.get(3).flooded, false);
t.checkExpect(boardTest1.cells.get(7).flooded, false);
t.checkExpect(boardTest1.cells.get(11).flooded, false);
t.checkExpect(boardTest1.cells.get(15).flooded, false);
this.boardTest3.makeConnections();
t.checkExpect(boardTest3.cells.get(0).flooded, true);
t.checkExpect(boardTest3.cells.get(1).flooded, true);
t.checkExpect(boardTest3.cells.get(3).flooded, true);
t.checkExpect(boardTest3.cells.get(5).flooded, true);
t.checkExpect(boardTest3.cells.get(8).flooded, true);
t.checkExpect(boardTest3.cells.get(11).flooded, true);
t.checkExpect(boardTest3.cells.get(14).flooded, true);
t.checkExpect(boardTest3.cells.get(15).flooded, false);
}
void testFindCell(Tester t) {
init();
t.checkExpect(this.boardTest1.findCell(new Posn(0, 0)),
this.boardTest1.cells.get(0));
t.checkExpect(this.boardTest1.findCell(new Posn(65, 0)),
this.boardTest1.cells.get(1));
t.checkExpect(this.boardTest1.findCell(new Posn(0, 65)),
this.boardTest1.cells.get(4));
t.checkExpect(this.boardTest1.findCell(new Posn(127, 127)),
this.boardTest1.cells.get(5));
t.checkExpect(this.boardTest1.findCell(new Posn(254, 254)),
this.boardTest1.cells.get(15));
}
void testUpdateColor(Tester t) {
init();
t.checkExpect(this.boardTestSmall.cells.get(0).color, Color.red);
this.boardTestSmall.updateColor(Color.blue);
t.checkExpect(this.boardTestSmall.cells.get(0).color, Color.blue);
init();
this.cellSmall2.color = Color.red;
t.checkExpect(this.boardTestSmall.cells.get(1).color, Color.red);
this.boardTestSmall.updateColor(Color.blue);
t.checkExpect(this.boardTestSmall.cells.get(1).color, Color.blue);
init();
this.cellSmall3.color = Color.red;
t.checkExpect(this.boardTestSmall.cells.get(2).color, Color.red);
this.boardTestSmall.updateColor(Color.blue);
t.checkExpect(this.boardTestSmall.cells.get(2).color, Color.blue);
init();
this.cellSmall4.color = Color.red;
t.checkExpect(this.boardTestSmall.cells.get(3).color, Color.red);
this.boardTestSmall.updateColor(Color.blue);
t.checkExpect(this.boardTestSmall.cells.get(3).color, Color.blue);
}
void testUpdateFloodStatus(Tester t) {
init();
this.boardTest1.makeConnections();
t.checkExpect(this.boardTest1.cells.get(0).flooded, true);
t.checkExpect(this.boardTest1.cells.get(1).flooded, false);
this.boardTest1.updateColor(Color.blue);
this.boardTest1.updateFloodStatus(Color.blue);
t.checkExpect(this.boardTest1.cells.get(0).flooded, true);
t.checkExpect(this.boardTest1.cells.get(1).flooded, true);
t.checkExpect(this.boardTest1.cells.get(11).flooded, true);
t.checkExpect(this.boardTest1.cells.get(15).flooded, true);
init();
this.boardTest2.makeConnections();
t.checkExpect(this.boardTest2.cells.get(0).flooded, true);
t.checkExpect(this.boardTest2.cells.get(1).flooded, false);
this.boardTest2.updateColor(Color.green);
this.boardTest2.updateFloodStatus(Color.green);
t.checkExpect(this.boardTest2.cells.get(0).flooded, true);
t.checkExpect(this.boardTest2.cells.get(1).flooded, false);
t.checkExpect(this.boardTest2.cells.get(11).flooded, false);
t.checkExpect(this.boardTest2.cells.get(15).flooded, false);
this.boardTest2.updateColor(Color.blue);
this.boardTest2.updateFloodStatus(Color.blue);
t.checkExpect(this.boardTest2.cells.get(0).flooded, true);
t.checkExpect(this.boardTest2.cells.get(1).flooded, true);
t.checkExpect(this.boardTest2.cells.get(11).flooded, true);
t.checkExpect(this.boardTest2.cells.get(15).flooded, false);
}
void testFloodCells(Tester t) {
init();
// @formatter:off
this.boardTest1.makeConnections();
this.boardTest1.floodCells(new Posn(0,0));
Board testAns1 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.red ), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.blue))),
4);
testAns1.makeConnections();
t.checkExpect(this.boardTest1, testAns1);
init();
this.boardTest1.makeConnections();
Board testAns2 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.blue ), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.blue))),
4);
testAns2.makeConnections();
this.boardTest1.floodCells(new Posn(128, 128));
t.checkExpect(this.boardTest1, testAns2);
init();
this.boardTest2.makeConnections();
this.boardTest2.floodCells(new Posn(255, 255));
Board testAns3 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.green), new Cell(1, 0, Color.blue), new Cell(2, 0, Color.blue), new Cell(3, 0, Color.blue),
new Cell(0, 1, Color.blue), new Cell(1, 1, Color.blue), new Cell(2, 1, Color.blue), new Cell(3, 1, Color.blue),
new Cell(0, 2, Color.blue), new Cell(1, 2, Color.blue), new Cell(2, 2, Color.blue), new Cell(3, 2, Color.blue),
new Cell(0, 3, Color.blue), new Cell(1, 3, Color.blue), new Cell(2, 3, Color.blue), new Cell(3, 3, Color.green))),
4);
testAns3.makeConnections();
t.checkExpect(this.boardTest1, testAns3);
init();
this.boardTest3.makeConnections();
this.boardTest3.floodCells(new Posn(224, 224));
Board testAns4 = new Board(new ArrayList<Cell>(Arrays.asList(
new Cell(0, 0, Color.green), new Cell(1, 0, Color.green), new Cell(2, 0, Color.green), new Cell(3, 0, Color.green),
new Cell(0, 1, Color.green), new Cell(1, 1, Color.green), new Cell(2, 1, Color.green), new Cell(3, 1, Color.green),
new Cell(0, 2, Color.green), new Cell(1, 2, Color.green), new Cell(2, 2, Color.green), new Cell(3, 2, Color.green),
new Cell(0, 3, Color.green), new Cell(1, 3, Color.green), new Cell(2, 3, Color.green), new Cell(3, 3, Color.green))),
4);
testAns4.makeConnections();
t.checkExpect(this.boardTest3, testAns4);
// @formatter:on
}
void testDrawBoard(Tester t) {
init();
World g = new FloodItWorld(boardRandom);
g.bigBang(256, 256, 1);
}
}