From 83e80a48e219926d3ed120e2bf53d0dca06b15a2 Mon Sep 17 00:00:00 2001 From: Jacob Signorovitch Date: Wed, 28 May 2025 08:02:46 -0400 Subject: [PATCH] h --- .../src/twentyfortyeight/Main.java | 170 ++++++++++++++---- 1 file changed, 131 insertions(+), 39 deletions(-) diff --git a/twentyfortyeight/src/twentyfortyeight/Main.java b/twentyfortyeight/src/twentyfortyeight/Main.java index 5ef5744..b19cc61 100644 --- a/twentyfortyeight/src/twentyfortyeight/Main.java +++ b/twentyfortyeight/src/twentyfortyeight/Main.java @@ -4,6 +4,7 @@ import java.awt.Color; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.Random; import javalib.impworld.*; import javalib.worldimages.*; import tester.Tester; @@ -11,10 +12,6 @@ import tester.Tester; class Examples { void testRun(Tester t) { Game game = new Game(); - game.board.board.put(new Coord(0, 0), new Tile(2)); - game.board.board.put(new Coord(3, 1), new Tile(20)); - game.board.board.put(new Coord(3, 2), new Tile(200)); - game.board.board.put(new Coord(2, 3), new Tile(2000)); game.run(); } } @@ -64,23 +61,36 @@ class Game extends World { this.sz = Util.defaultWidth; this.width = this.sz * Util.scale; this.board = new Board(this.sz); + this.board.randGen(); + this.board.randGen(); } public WorldScene makeScene() { WorldScene scene = new WorldScene(this.width, this.width); scene.placeImageXY(this.board.draw(), this.width / 2, this.width / 2); + scene.placeImageXY( + new TextImage("Score: " + this.score, 20, Color.RED), + this.width / 2, 20 + ); return scene; } public void onKeyEvent(String key) { System.out.println("got key" + key); - if (key.equals("left") || key.equals("h")) this.board.move(Move.LEFT); + + int score = 0; + + if (key.equals("left") || key.equals("h")) + score = this.board.move(Move.LEFT); else if (key.equals("down") || key.equals("j")) - this.board.move(Move.DOWN); - else if (key.equals("up") || key.equals("k")) this.board.move(Move.UP); + score = this.board.move(Move.DOWN); + else if (key.equals("up") || key.equals("k")) + score = this.board.move(Move.UP); else if (key.equals("right") || key.equals("l")) - this.board.move(Move.RIGHT); + score = this.board.move(Move.RIGHT); else return; + + this.score += score; } void run() { this.bigBang(this.width, this.width, 0.01); } @@ -90,10 +100,14 @@ class Game extends World { class Board { int sz; // The side length of the board grid square. Map board; + Random rand; + boolean boardChanged; Board(int sz) { this.sz = sz; this.board = new HashMap(); + this.rand = new Random(); + this.boardChanged = false; } // Draw the board. @@ -130,9 +144,7 @@ class Board { } // Set the cell at the coords. - void set(Coord coord, Cell cell) { - this.board.put(coord, cell); - } + void set(Coord coord, Cell cell) { this.board.put(coord, cell); } // Try to move the cell at the coords to the coords. void tryCellMove(Coord coord, Coord dest) { @@ -142,47 +154,123 @@ class Board { if (cell.isMoveable() && destCell.isReplaceable()) { this.set(dest, cell); this.set(coord, new Space()); + boardChanged = true; // It did move. } } - // Move cell as much as possible. - void fullCellMove(Coord coord, Move move) { + // Try to combine two tiles if they have the same value + int tryCombine(Coord source, Coord target) { + Cell sourceCell = this.get(source); + Cell targetCell = this.get(target); + + // Check if both cells are tiles. + if (sourceCell instanceof Tile && targetCell instanceof Tile) { + Tile sourceTile = (Tile)sourceCell; + Tile targetTile = (Tile)targetCell; + + // Check they've the same n and haven't yet been combined. + if (sourceTile.n == targetTile.n && !targetTile.flag) { + Tile newTile = new Tile(sourceTile.n * 2); + int score = sourceTile.n; + newTile.flag = true; + + this.set(target, newTile); + this.set(source, new Space()); + boardChanged = true; + return score; + } + } + return 0; + } + + // Move cell as much as possible. Return score. + int fullCellMove(Coord coord, Move move) { Cell cell = this.get(coord); Coord disp = Util.moveDisp(move); - if (!cell.isMoveable()) return; + if (!cell.isMoveable()) return 0; - for () { - this.tryCellMove(coord, coord.add(disp)); + Coord current = coord; + Coord next = current.add(disp); + + // Keep moving until edge or a non-replaceable cell hit. + while (next.x >= 0 && next.x < this.sz && next.y >= 0 && + next.y < this.sz && this.get(next).isReplaceable()) { + this.tryCellMove(current, next); + current = next; + next = current.add(disp); } + + // Check if can combine next tile. + if (next.x >= 0 && next.x < this.sz && next.y >= 0 && next.y < this.sz) + return this.tryCombine(current, next); + + // Only generate new tile if changed. + if (boardChanged) this.randGen(); + + return 0; } - // Move in the given direction. - void move(Move move) { + // Move in the given direction. Returns the generated score. + int move(Move move) { System.out.println("moving"); - for (int i = 0; i < this.sz; i ++) { - this.moveLine(i, move); - } + + // Reset flags for all tiles and change tracker. + resetFlags(); + + int score = 0; + for (int i = 0; i < this.sz; i++) { score += this.moveLine(i, move); } + + return score; + } + + // Reset flags of all tiles. + void resetFlags() { + for (int x = 0; x < this.sz; x++) + for (int y = 0; y < this.sz; y++) { + Cell cell = this.get(new Coord(x, y)); + if (cell instanceof Tile) ((Tile)cell).flag = false; + } } // Move a line of tiles. - void moveLine(int i, Move move) { - if (move.equals(Move.LEFT)) { - for (int x = 1; x < this.sz; x++) { - this.fullCellMove(new Coord(x, i), move); - } - } + int moveLine(int i, Move move) { + int score = 0; + if (move.equals(Move.LEFT)) + for (int x = 1; x < this.sz; x++) + score += this.fullCellMove(new Coord(x, i), move); - else if (move.equals(Move.RIGHT)) { - for (int x = this.sz - 2; x >= 0; x--) { - this.fullCellMove(new Coord(x, i), move); - } - } + else if (move.equals(Move.RIGHT)) + for (int x = this.sz - 2; x >= 0; x--) + score += this.fullCellMove(new Coord(x, i), move); - else if (move.equals(Move.DOWN)) { - for (int y = this.sz - 2; y > 0; y--) { - this.tryCellMove(new Coord(i, y), new Coord(i , y + 1)); + else if (move.equals(Move.DOWN)) + for (int y = this.sz - 2; y >= 0; y--) + score += this.fullCellMove(new Coord(i, y), move); + + else if (move.equals(Move.UP)) + for (int y = 1; y < this.sz; y++) + score += this.fullCellMove(new Coord(i, y), move); + + return score; + } + + // Adds new tile (2 @ 80% chance, or 4 @ 20%) to random empty space on + // board. + void randGen() { + ArrayList emptySpaces = new ArrayList<>(); + + for (int x = 0; x < this.sz; x++) + for (int y = 0; y < this.sz; y++) { + Coord coord = new Coord(x, y); + if (this.get(coord).isReplaceable()) emptySpaces.add(coord); } + + if (!emptySpaces.isEmpty()) { + Coord chosenSpace = + emptySpaces.get(rand.nextInt(emptySpaces.size())); + int value = rand.nextDouble() < 0.8 ? 2 : 4; + this.set(chosenSpace, new Tile(value)); } } } @@ -204,14 +292,18 @@ abstract class Cell { // Is this moveable? boolean isMoveable() { return false; } - boolean isReplaceable() { return false;} + boolean isReplaceable() { return false; } } // A moveable tile on the board. class Tile extends Cell { int n; + boolean flag; - Tile(int n) { this.n = n; } + Tile(int n) { + this.n = n; + this.flag = false; + } Color col() { int r = (int)Math.min(255, 20 * (int)(Math.log(this.n) / Math.log(2))); @@ -227,8 +319,8 @@ class Tile extends Cell { ); } - boolean isMoveable() { return true;} - boolean isReplaceable() {return false;} + boolean isMoveable() { return true; } + boolean isReplaceable() { return false; } } // An empty space on the board.