Compare commits
4 Commits
0b30c851e4
...
31e83a33fb
Author | SHA1 | Date | |
---|---|---|---|
![]() |
31e83a33fb | ||
![]() |
473a3f7cb8 | ||
![]() |
5b8ce38723 | ||
![]() |
83e80a48e2 |
@@ -57,15 +57,13 @@ class Sudoku {
|
||||
for (int[] col : transposed)
|
||||
if (isRepetitive(col)) return false;
|
||||
|
||||
/*
|
||||
// Check there'ren't any repeats in a square.
|
||||
for (int i = 0; i < 9; i++) {
|
||||
int[] square = new int[3][3];
|
||||
for (int j = i; j < i + 3; j++) {
|
||||
// for (int k = i; k < i + 3; k++) { square[i][k] }
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Check all 3x3 squares.
|
||||
for (int squareRow = 0; squareRow < 3; squareRow++) {
|
||||
for (int squareCol = 0; squareCol < 3; squareCol++) {
|
||||
if (squareCheck(puz, squareRow * 3, squareCol * 3))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -91,6 +89,20 @@ class Sudoku {
|
||||
|
||||
return transposed;
|
||||
}
|
||||
|
||||
// Check if a 3x3 square repeats values.
|
||||
static boolean squareCheck(int[][] puz, int startRow, int startCol) {
|
||||
HashMap<Integer, Boolean> seen = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
for (int j = 0; j < 3; j++) {
|
||||
int val = puz[startRow + i][startCol + j];
|
||||
if (seen.containsKey(val)) return true;
|
||||
else seen.put(val, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class Examples {
|
||||
@@ -166,6 +178,7 @@ class Examples {
|
||||
t.checkExpect(Sudoku.solved(testPuz6), false);
|
||||
t.checkExpect(Sudoku.solved(testPuz7), false);
|
||||
}
|
||||
|
||||
void testSieve(Tester t) {
|
||||
Sieve sieve = new Sieve(29);
|
||||
t.checkExpect(sieve.hasNext(), true);
|
||||
|
@@ -2,7 +2,6 @@ package streams;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -50,6 +47,7 @@ class Game extends World {
|
||||
int sz; // The size of the grid.
|
||||
int width; // The width of the image in pixels.
|
||||
Board board; // The game board.
|
||||
boolean gameOver;
|
||||
|
||||
Game(int score, int sz, int width, Board board) {
|
||||
this.score = score;
|
||||
@@ -64,23 +62,74 @@ class Game extends World {
|
||||
this.sz = Util.defaultWidth;
|
||||
this.width = this.sz * Util.scale;
|
||||
this.board = new Board(this.sz);
|
||||
this.gameOver = false;
|
||||
this.board.randGen();
|
||||
this.board.randGen();
|
||||
}
|
||||
|
||||
Game(int w) {
|
||||
this.score = 0;
|
||||
this.sz = w;
|
||||
this.width = this.sz * Util.scale;
|
||||
this.board = new Board(this.sz);
|
||||
this.gameOver = false;
|
||||
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
|
||||
);
|
||||
|
||||
// Display loss message.
|
||||
if (this.gameOver)
|
||||
scene.placeImageXY(
|
||||
new TextImage(
|
||||
"Game over. Score: " + this.score + ". [R] to restart.", 20,
|
||||
Color.RED
|
||||
),
|
||||
this.width / 2, this.width / 2
|
||||
);
|
||||
|
||||
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);
|
||||
|
||||
// If game over, ignore movement keys.
|
||||
if (this.gameOver) {
|
||||
// Restart game with 'r'.
|
||||
if (key.equals("r")) {
|
||||
this.score = 0;
|
||||
this.board = new Board(this.sz);
|
||||
this.gameOver = false;
|
||||
this.board.randGen();
|
||||
this.board.randGen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
// Check if game over after move.
|
||||
this.gameOver = this.board.isGameOver();
|
||||
}
|
||||
|
||||
void run() { this.bigBang(this.width, this.width, 0.01); }
|
||||
@@ -90,10 +139,14 @@ class Game extends World {
|
||||
class Board {
|
||||
int sz; // The side length of the board grid square.
|
||||
Map<Coord, Cell> board;
|
||||
Random rand;
|
||||
boolean boardChanged;
|
||||
|
||||
Board(int sz) {
|
||||
this.sz = sz;
|
||||
this.board = new HashMap<Coord, Cell>();
|
||||
this.rand = new Random();
|
||||
this.boardChanged = false;
|
||||
}
|
||||
|
||||
// Draw the board.
|
||||
@@ -130,9 +183,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,48 +193,160 @@ 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.
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Move in the given direction.
|
||||
void move(Move move) {
|
||||
System.out.println("moving");
|
||||
for (int i = 0; i < this.sz; i ++) {
|
||||
this.moveLine(i, move);
|
||||
}
|
||||
// Move in the given direction. Returns the generated score.
|
||||
int move(Move move) {
|
||||
// Reset flags for all tiles and change tracker.
|
||||
resetFlags();
|
||||
this.boardChanged = false;
|
||||
|
||||
int score = 0;
|
||||
for (int i = 0; i < this.sz; i++) score += this.moveLine(i, move);
|
||||
|
||||
if (this.boardChanged) this.randGen();
|
||||
|
||||
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--)
|
||||
score += this.fullCellMove(new Coord(x, i), move);
|
||||
|
||||
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<Coord> 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));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if game over.
|
||||
boolean isGameOver() {
|
||||
for (int x = 0; x < this.sz; x++)
|
||||
for (int y = 0; y < this.sz; y++)
|
||||
if (this.get(new Coord(x, y)).isReplaceable())
|
||||
return false; // There's an empty space, game not over.
|
||||
|
||||
// Check if any adjacent tiles can be combined.
|
||||
for (int x = 0; x < this.sz; x++) {
|
||||
for (int y = 0; y < this.sz; y++) {
|
||||
Cell current = this.get(new Coord(x, y));
|
||||
|
||||
// Skip if not tile.
|
||||
if (!(current instanceof Tile)) continue;
|
||||
|
||||
Tile currentTile = (Tile)current;
|
||||
|
||||
if (x < this.sz - 1) {
|
||||
Cell right = this.get(new Coord(x + 1, y));
|
||||
if (right instanceof Tile &&
|
||||
((Tile)right).n == currentTile.n) {
|
||||
return false; // Can combine horizontally.
|
||||
}
|
||||
}
|
||||
|
||||
if (y < this.sz - 1) {
|
||||
Cell bottom = this.get(new Coord(x, y + 1));
|
||||
if (bottom instanceof Tile &&
|
||||
((Tile)bottom).n == currentTile.n) {
|
||||
return false; // Can combine vertically.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.DOWN)) {
|
||||
for (int y = this.sz - 2; y > 0; y--) {
|
||||
this.tryCellMove(new Coord(i, y), new Coord(i , y + 1));
|
||||
}
|
||||
}
|
||||
return true; // Game over.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,14 +367,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 +394,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.
|
||||
|
Reference in New Issue
Block a user