In order to study programming, I am making a game 2048 in java. The game has a class in which there are many repetitive fragments - field iteration loops. The question is, is it possible to create such a method that will accept the values of the enumeration bounds and the executable code?
Something like this both for assignment and comparison.
public void forField(int borderX, int borderY, ??? code){
for (int x = 0; x < borderX; x++)
for (int y = 0; y < borderY; y++)
do code;
}
public boolean checkField(int borderX, int borderY, ??? code, boolean default_answer){
for (int x = 0; x < borderX; x++)
for (int y = 0; y < borderY; y++)
return code;
return default_answer;
}
If not, can you recommend how to make my code better? Thank you for your attention.
public class Field {
private int[][] field;
private int width, heigth;
public Field(int sizeX, int sizeY) {
this.width = sizeX;
this.heigth = sizeY;
this.field = new int[sizeX][sizeY];
}
public int getCell(int x, int y) {
return this.field[x][y];
}
public void setCell(int val, int x, int y) {
this.field[x][y] = val;
}
// for restart
public void reset() {
for (int x = 0; x < width; x++)
for (int y = 0; y < heigth; y++)
this.field[x][y] = 0;
}
// for step cancelling function
public void copyOf(Field f) {
for (int x = 0; x < width; x++)
for (int y = 0; y < heigth; y++)
this.field[x][y] = f.getCell(x, y);
}
// can field changed after pressing a key
public boolean isEqualTo(Field f) {
for (int x = 0; x < width; x++)
for (int y = 0; y < heigth; y++)
if (field[x][y] != f.getCell(x, y))
return false;
return true;
}
private boolean canMergeByY() {
for (int x = 0; x < width; x++)
for (int y = 0; y < heigth - 1; y++)
if (field[x][y] == field[x][y + 1])
return true;
return false;
}
private boolean canMergeByX() {
for (int x = 0; x < width - 1; x++)
for (int y = 0; y < heigth; y++)
if (field[x][y] == field[x + 1][y])
return true;
return false;
}
// checking the possibility of continuing the game
public boolean canMerge() {
return canMergeByX() && canMergeByY();
}
// checking 0 and 2048 cells for different tasks
public boolean contains(int i) {
for (int x = 0; x < width; x++)
for (int y = 0; y < heigth; y++)
if (field[x][y] == i)
return true;
return false;
}
}
The ??? in forField can just be a BiConsumer<Integer, Integer>, or you can declare your own IntBiConsumer interface if you don't like boxing:
interface IntBiConsumer {
void accept(int i, int j);
}
forField can then be declared as:
public void forField(int borderX, int borderY, IntBiConsumer code){
for (int x = 0; x < borderX; x++)
for (int y = 0; y < borderY; y++)
code.accept(x, y);
}
copyOf can then be written as:
public void copyOf(Field f) {
forField(width, height, (x, y) -> {
this.field[x][y] = f.getCell(x, y);
});
}
checkField is a little bit more tricky, your proposed code wouldn't actually work, because you are not checking anything before you return in the inner loop. The loops will only loop once, and return immediately. It should be more like:
public boolean checkField(int borderX, int borderY, ??? condition, boolean default_answer){
for (int x = 0; x < borderX; x++)
for (int y = 0; y < borderY; y++)
if (condition)
return !default_answer;
return default_answer;
}
??? here can be a BiPredicate<Integer, Integer>, or your own interface like this:
interface IntBiPredicate {
boolean test(int i, int j);
}
checkField can then be declared like this:
public boolean checkField(int borderX, int borderY, IntBiPredicate condition, boolean defaultAnswer){
for (int x = 0; x < borderX; x++)
for (int y = 0; y < borderY; y++)
if (condition.test())
return !defaultAnswer;
return defaultAnswer;
}
isEqualTo can be rewritten as:
public boolean isEqualTo(Field f) {
return checkField(width, height, (x, y) -> field[x][y] != f.getCell(x, y), true);
}
Related
Im currently trying to implement SAT in java but for some reason it doesn't work. I have rewritten my code multiple times, looked over it even more and watched many tutorials but cant find my mistake. In some cases for some edges it works partly properly but otherwise it detects collision when not colliding.
Later i'll add AABB collision detection for better performance.
Here are the relevant parts of my code:
SAT class:
public class SAT {
public static boolean checkSAT(Polygon poly1, Polygon poly2) {
Vector[] axes = new Vector[poly1.p.length + poly2.p.length];
for (int i = 0; i < poly1.p.length + poly2.p.length; i++) {
int a = i; if(i == poly1.p.length) a -= poly1.p.length;
axes[i] = poly1.getEdge(a).getNormal().getNormalized();
}
double p1_min = Double.POSITIVE_INFINITY, p1_max = Double.NEGATIVE_INFINITY,
p2_min = Double.POSITIVE_INFINITY, p2_max = Double.NEGATIVE_INFINITY;
for (int i = 0; i < axes.length; i++) {
for (int j = 0; j < poly1.p.length; j++) {
double proj = axes[i].dotProduct(poly1.p[j]);
if(proj < p1_min) p1_min = proj;
if(proj > p1_max) p1_max = proj;
}
for (int j = 0; j < poly2.p.length; j++) {
double proj = axes[i].dotProduct(poly2.p[j]);
if(proj < p2_min) p2_min = proj;
if(proj > p2_max) p2_max = proj;
}
if (p1_max < p2_min || p2_max < p1_min)
return false;
}
return true;
}
}
vector class:
public class Vector {
public final double x;
public final double y;
public Vector(double x, double y) {
this.x = x;
this.y = y;
}
public Vector getNormal() {
return new Vector(-y, x);
}
public double getLength() {
return Math.sqrt(x*x + y*y);
}
public Vector getNormalized() {
double l = getLength();
return new Vector(x/l, y/l);
}
public double dotProduct(Vector vec) {
return x * vec.x + y * vec.y;
}
}
relevant parts of the polygon class:
public class Polygon {
public Vector[] m; //"model" of the polygon
public Vector[] p; //coordinates of the corners of the polygon in space
public double posX;
public double posY;
public Polygon(Vector[] m) {
this.m = m;
p = new Vector[m.length];
transform();
}
//later i'll add rotation
public void transform() {
for (int i = 0; i < m.length; i++) {
p[i] = new Vector(m[i].x + posX, m[i].y + posY);
}
}
public void setPosition(Vector pos) {
posX = pos.x;
posY = pos.y;
transform();
}
public Vector getEdge(int i) {
if(i >= p.length) i = 0;
int j = i+1; if(j >= p.length) j = 0;
return new Vector(p[j].x - p[i].x, p[j].y - p[i].y);
}
}
Update:
I found the mistake and it's just plain stupid!! And on top of that I spend more than 5 hours finding it!!!!!!
double p1_min = Double.POSITIVE_INFINITY, p1_max = Double.NEGATIVE_INFINITY,
p2_min = Double.POSITIVE_INFINITY, p2_max = Double.NEGATIVE_INFINITY;
//those doubles should be declared inside the for loop
for (int i = 0; i < axes.length; i++) {
//right here
for (int j = 0; j < poly1.p.length; j++) {
double proj = axes[i].dotProduct(poly1.p[j]);
if(proj < p1_min) p1_min = proj;
if(proj > p1_max) p1_max = proj;
}
for (int j = 0; j < poly2.p.length; j++) {
double proj = axes[i].dotProduct(poly2.p[j]);
if(proj < p2_min) p2_min = proj;
if(proj > p2_max) p2_max = proj;
}
if (p1_max < p2_min || p2_max < p1_min)
return false;
}
I have this method that's able to rotate the array by 90 degrees. I want to be to flip vertically and horizontally (I'm binding them with different buttons). Here's the method.
private void Rotate90() {
String[][] temp = new String[totalX][totalY];
for (int y = 0; y < totalY; y++) {
for (int x = 0; x < totalX; x++) {
temp[x][y] = fields[x][y].getText();
}
}
for (int y = 0; y < totalY; y++) {
for (int x = 0; x < totalX; x++) {
fields[x][y].setText(temp[y][x]);
}
}
Draw();
}
#khriskooper code contains an obvious bug: it flips array twice i.e. effectively does nothing. To flip array you should iterate only half of the indices. Try something like this:
private void flipHorizontally() {
for (int y = 0; y < totalY; y++) {
for (int x = 0; x < totalX/2; x++) {
String tmp = fields[totalX-x-1][y].getText();
fields[totalX-x-1][y].setText(fields[x][y].getText());
fields[x][y].setText(tmp);
}
}
}
private void flipVertically() {
for (int x = 0; x < totalX; x++) {
for (int y = 0; y < totalY/2; y++) {
String tmp = fields[x][totalY - y - 1].getText();
fields[x][totalY - y - 1].setText(fields[x][y].getText());
fields[x][y].setText(tmp);
}
}
}
I am quite new to Java and I have this school assignment to write Conway's Game of Life. The task I am struggling with is reading a patterns from file. So far I got this code from tutorial from my school:
#FXML
private void readFromFile(){
FileChooser fileChooser = new FileChooser();
File openFile = fileChooser.showOpenDialog(null);
if(openFile == null){
return;
}
try (BufferedReader reader = Files.newBufferedReader(openFile.toPath())){
String line;
while ((line = reader.readLine()) != null){
addMessage(line);
}
}catch (IOException ex){
showIOErrorAlert(ex);
}
}
#FXML
private void showIOErrorAlert(IOException ex){
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setContentText("IOException, filen cannot be open: " + ex);
alert.show();
}
The code opens a window where I can choose a file from disk (I've downloaded all patterns in rle format , and I wish to open them rle format, because that is the assignments requirement). But when I choose a file nothing happens, not an error, nothing. What do I need to do that this work? Do I need to write a parser here? To read a rle format. I am using mvc model and java fxml this is my Cell class:
public class Cell extends Rectangle{
public static final int CELL_SIZE = 5;
private boolean alive;
public Cell(){
super(CELL_SIZE, CELL_SIZE);
setAlive(false);
}
public void setAlive(boolean bool){
alive = bool;
if (alive){
setFill(Color.WHITE);
} else {
setFill(Color.BLACK);
}
}
public boolean isAlive(){
return alive;
}
}
Board class:
public class Board {
public static final int COLUMNS = 90;
public static final int ROWS = 210;
private Cell[][] generation;
public Board(){
generation = new Cell[COLUMNS][ROWS];
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
generation[x][y] = new Cell();
}
}
}
public Cell[][] getBoard(){
return generation;
}
public void fill(){
Random rand = new Random();
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
generation[x][y].setAlive(rand.nextBoolean());
}
}
}
public void reset(){
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
generation[x][y].setAlive(false);
}
}
}
public int countNeighbors(int x, int y){
int neighbors = 0;
//iteration starts with -1 in order to 'wrap' the grid around
for (int a = -1; a < 2; a++){
for (int b = -1; b < 2; b++){
int nx = x + a;
int ny = y + b;
if (nx < 0){
nx = COLUMNS - 1;
}
if (ny < 0){
ny = ROWS - 1;
}
if (nx > COLUMNS - 1){
nx = 0;
}
if (ny > ROWS - 1){
ny = 0;
}
if(generation[nx][ny].isAlive()){
neighbors += 1;
}
}
}
if(generation[x][y].isAlive())
neighbors--;
return neighbors;
}
public void renew(){
Cell[][] nextGeneration = new Cell[COLUMNS][ROWS];
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
nextGeneration[x][y] = new Cell();
nextGeneration[x][y].setAlive(generation[x][y].isAlive());
}
}
int neighborsCount = 0;
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
neighborsCount = countNeighbors(x, y);
if(generation[x][y].isAlive()){
if(neighborsCount < 2 || neighborsCount > 3)
nextGeneration[x][y].setAlive(false);
}
else{
if(neighborsCount == 3)
nextGeneration[x][y].setAlive(true);
}
}
}
for(int x = 0; x < COLUMNS; x++){
for(int y = 0; y < ROWS; y++){
generation[x][y].setAlive(nextGeneration[x][y].isAlive());
}
}
}
How to write a method that reads a rle format file and adds a pattern to my board?
I have my code as the following.
package net.ferrell.wrathoftuemdaym;
import java.awt.*;
public class Level {
public Block[][] block = new Block[50][50];
public Level() {
for(int x = 0; x < block.length; x++) {
for(int y = 0; y < block[0].length; y++);
block[x][y] = new Block(new Rectangle(x * Tile.tileSize, y * Tile.tileSize, Tile.tileSize, Tile.tileSize), Tile.air);
}
}
public void generateLevel() {
for(int x = 0; x < block.length; x++) {
for(int y = 0; y < block[0].length; y++);
if(x == 0 || y == 0 || x == block.length-1 || y == block[0].length-1) {
block[x][y].id = Tile.earth;
}
}
}
public void tick() {
}
public void render(Graphics g) {
for(int x = 0; x < block.length; x++) {
for(int y = 0; y < block[0].length; y++);
block[x][y].render(g);
}
}
}
In a line that says " block[x][y] ", y cannot be resolved to a variable. I do not know the fix for this and it is only in this class that the problem exists. Please help me. I do not understand because the x CAN be resolved...
this is your culprit
for(int y = 0; y < block[0].length; y++);
it should be
for(int y = 0; y < block[0].length; y++)
Personally I always put braces in code blocks even if it is just one line.
My head is not working anymore. I have to finish this a.s.a.p
How can i make this for loop shorter.
At the moment i have got 4 different for loop. I want to combine them and have only one.
Card[] cards = new Card[4*13];
void testCreateCards() {
int k = 0;
for (int suit = 0; suit <= 3; suit++) { // for suit
for (int value = 1; value <= 13; value++) { // from Ace to King
// build new card
cards[k++] = new Card(suit, value);
}
}
}
void testDrawClubs() {
int x = 0;
int y = 0;
for (int i = 0; i <= 12; i++) {
cards[i].displayCard(x, y);
x +=80;
}
}
void testDrawDiamonds() {
int x = 0;
int y = 80;
for (int i = 13; i <= 25; i++) {
cards[i].displayCard(x, y);
x +=80;
}
}
void testDrawHearts() {
int x = 0;
int y = 160;
for (int i = 26; i <= 38; i++) {
cards[i].displayCard(x, y);
x +=80;
}
}
void testDrawSpades() {
int x = 0;
int y = 240;
for (int i = 39; i <= 51; i++) {
cards[i].displayCard(x, y);
x +=80;
}
}
You can calculate x and y directly using modular arithmetic because i % 13 gives you the x-coordinate and i / 13 gives you the y-coordinate:
void testDrawCards() {
for (int i = 0; i < 52; i++) {
int x = i % 13;
int y = i / 13;
cards[i].displayCard(x * 80, y * 80);
}
}