I'm doing a collegeproject to make tetris, however I'm stuck at the moment.
I have a nullpointerexception when I simply want to change a value of an array. Should be easy right?
Apparently not...
I'm not an advanced programmer yet, so if anyone could help me find the incorrect code, and specifically explain to me why it's wrong, it'll be appreciated.
Here's my code:
package tetris;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import engine.*;
public class Tetris extends Game {
private int x = 0, y = 0, maxWidth = 0, bSize = 25;
private int[][] field;
private boolean busy;
private Blok blok = null;
public Tetris() {
title = "Tetris";
height = 600;
width = 400;
delay = 100;
delay2 = 10;
field = new int[20][10];
field[19][7] = 1;
field[18][7] = 2;
field[17][7] = 3;
field[19][2] = 4;
field[19][3] = 5;
}
public static void main(String arg[]) {
GameApplication.start(new Tetris());
}
#Override
/**
* Right Arrow: keycode 39
* Left Arrow: keycode 37
*/
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 37) {
if (tryMove(-1)) {
x--;
}
}
else if(e.getKeyCode() == 39) {
if (tryMove(1)) {
x++;
}
} else if(e.getKeyCode() == 40) {
if (tryMove(0)) {
y++;
}
}
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void update() {
if(!busy) {
int random = (int) (Math.random()*7);
//debug mode
random = 0;
///
System.out.println(random);
blok = new Blok(random);
y = 1;
x = 3;
busy = true;
}
if (!tryMove(0)){
field[y][x] = 1;
busy = false;
} else {
y++;
}
scanLine();
}
#Override
public void update2() {
}
#Override
public void draw(Graphics2D g) {
g.fillRect(0, 0, width, height);
g.setColor(Color.LIGHT_GRAY);
g.fillRect(0, 0, 250, 500);
for (int i = 0; i<20; i++){
for (int j = 0; j<10; j++){
if (field[i][j]>0) {
g.setColor(Color.black);
g.fillRect(j*25,i*25,bSize,bSize);
}
}
}
if(busy) {
maxWidth = blok.getWidth();
for (int i = 0; i<3; i++){
g.fillRect(blok.getX(i)*25,blok.getY(i)*25,bSize,bSize);
}
}
}
public boolean tryMove(int a) {
boolean b = true;
if (a == -1){
if (x <= 0 || field[y][x-1] != 0){
b = false;
}
} else if (a == 0){
if (y >= 19 || field[y+1][x] != 0){
b = false;
}
} else if (a == 1){
if (x >= (9-maxWidth) || field[y][x+1] != 0){
b = false;
}
}
return b;
}
public void scanLine(){
for (int i = 0; i<20; i++){
boolean vol = true;
for (int j = 0; j<10; j++){
if (field[i][j]==0) {
vol = false;
}
}
if (vol) {
removeLine(i);
}
}
}
public void removeLine(int a){
for (int i = a; i>0; i--){
for (int j = 0; j<10; j++){
field[i][j] = field[i-1][j];
}
}
}
}
and for making the block(and where it goes wrong)
package tetris;
public class Blok {
private int type;
private int[] x,y;
private int width;
public Blok(int type) {
this.setType(type);
setCoords(type);
x = new int[4];
y = new int[4];
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public void setCoords(int type) {
if (type == 0){
setWidth(3);
setX(0,1); setY(0,0);
setX(1,2); setY(1,0);
setX(2,3); setY(2,0);
setX(3,0); setY(3,0);
//x[0] = 1; y[0] = 0;
//x[1] = 2; y[1] = 0;
//x[2] = 3; y[2] = 0;
//x[3] = 0; y[3] = 0;
} else if (type == 1){
setWidth(2);
x[0] = 1; y[0] = 0;
x[1] = 2; y[1] = 0;
x[2] = 0; y[2] = -1;
x[3] = 0; y[3] = 0;
} else if (type == 2){
setWidth(2);
x[0] = 1; y[0] = 0;
x[1] = 2; y[1] = 0;
x[2] = 2; y[2] = -1;
x[3] = 0; y[3] = 0;
} else if (type == 3){
setWidth(2);
x[0] = 1; y[0] = 0;
x[1] = 2; y[1] = 0;
x[2] = 1; y[2] = -1;
x[3] = 0; y[3] = 0;
} else if (type == 4){
setWidth(2);
x[0] = 1; y[0] = -1;
x[1] = 1; y[1] = 0;
x[2] = 0; y[2] = -1;
x[3] = 0; y[3] = 0;
} else if (type == 5){
setWidth(1);
x[0] = 1; y[0] = 0;
x[1] = 1; y[1] = -1;
x[2] = 2; y[2] = -1;
x[3] = 0; y[3] = 0;
} else if (type == 6){
setWidth(2);
x[0] = 1; y[0] = 0;
x[1] = 1; y[1] = 1;
x[2] = 2; y[2] = 1;
x[3] = 0; y[3] = 0;
}
}
public int getX(int type) {
return x[type];
}
public int getY(int type) {
return y[type];
}
public void setX(int index, int value){
x[index] = value; //This is line 82, goes wrong here.
}
public void setY(int index, int value){
y[index] = value;
}
public int getWidth() {
return width;
}
public void setWidth(int w) {
this.width = w;
}
}
Here's the errorcode:
Exception in thread "Thread-2" java.lang.NullPointerException
at tetris.Blok.setX(Blok.java:82)
at tetris.Blok.setCoords(Blok.java:26)
at tetris.Blok.<init>(Blok.java:10)
at tetris.Tetris.update(Tetris.java:75)
at engine.Engine.run(Engine.java:18)
In your constructor you put
public Blok(int type) {
this.setType(type);
setCoords(type);
x = new int[4];
y = new int[4];
}
You call setCoords that calls setX(..) and setX use x that is null then NullPointerException is thrown.
A workaround is to change order.
public Blok(int type) {
this.setType(type);
x = new int[4];
y = new int[4];
setCoords(type);
}
But calling an overridable method in a constructor is not a good practice. Read more What's wrong with overridable method calls in constructors?. A workaround is making setCoords(..) final or making your class final or make that method private or remove from constructor and call it from client code of this class.
Related
Hi I have been working on a space invader game in processing, I am relatively new to java/coding. What my problem is that I do not really understand how to make the collision actually work, and also my aliens (which are the space ships), they move left to right but do not move down. These are the 2 major problems that I am having a hard time solving. This is my code underneath, any professional advice would be appreciated.
PImage SpaceShip;
PImage Laser;
int TankX = 450;
int TankY = 450;
int SpaceshipX = 20;
int SpaceshipY = 20;
int MoveSpaceShipDown = 5;
int TankSizeX = 200;
int TankSizeY = 90;
int ShipSizeX = 90;
int ShipSizeY = 80;
int Xtankspeed = 2;
int LaserX = 9999;
int LaserY = TankY;
int LasersizeX = 10;
int LasersizeY = 40;
int spaceShipDirection = 5;
int spaceshipxspeed = 2;
int spaceshipSpeed = 5;
//int Xtankspeed2 = -6;
boolean moveRight = false;
boolean moveLeft = false;
boolean ShowLaser = false;
int[] ShipX = new int [15];
int [] ShipY = new int [4];
int gameState = 1;
int StopWatch = 0;
void setup() {
size(1000, 500);
imageMode(CENTER);
SpaceShip = loadImage("Spaceship.png");
SpaceShip.resize( ShipSizeX, ShipSizeY );
Laser = loadImage ("LaserBeam.png");
Laser.resize(LasersizeX, LasersizeY);
Tank = loadImage("Tank.png");
Tank.resize(TankSizeX, TankSizeY);
setSpaceShipPositions();
}
void setSpaceShipPositions() {
for(int j = 0; j < ShipY.length; j++){
for (int i = 0; i < ShipX.length; i++) {
ShipX[i] = 50 + 50*i;
}
ShipY[j] = 50 + 50*j;
}
}
void draw() {
if (gameState == 1) {
IntroScreen();
} else if (gameState == 2) {
startGame();
}
}
void IntroScreen() {
background(#000000);
textMode(CENTER);
textSize(50);
text("Space Defenders", 325, 250);
}
void startGame() {
background (#2f3069);
MakeLaser();
Maketank();
Maketankmove();
checkiftankhitedge();
for (int j = 0; j < ShipY.length; j++) {
for (int i = 0; i < ShipX.length; i++) {
MakeSpaceShip(i,j);
moveSpaceShip();
checkiflaserhitspaceship(i,j);
}
}
Shootlaser();
Makelaserreturentoorignalposition();
//makespaceshipgodown();
}
void keyPressed() {
println(keyCode);
if (keyCode == 39) { //right key
moveRight = true;
}
if (keyCode == 37) { //leftkey
moveLeft = true;
}
if (keyCode == 32 && ShowLaser == false) { //Spacebar
ShowLaser = true;
LaserX = TankX;
LaserY = TankY;
}
if (keyCode == 10) {
gameState = 2;
}
}
void keyReleased() {
if (keyCode == 39) { //right key
moveRight = false;
}
if (keyCode == 37) { //leftkey
moveLeft = false;
}
if (keyCode == 32) { //Spacebar
}
}
void Maketank() {// this is to make the tank
//PImage.resize(0,5);
imageMode(CENTER);
image(Tank, TankX, TankY);
}
void MakeLaser() {
if (ShowLaser) {
image(Laser, LaserX, LaserY);
}
}
void MakeSpaceShip(int i, int j) {
image(SpaceShip, ShipX[i], ShipY[j]);
//for (int i = 0; i < spaceShipX.length; i++){
// image( spaceShipX[i] - 15, ,SpaceshipX, SpaceshipY ); Confused
}
int lastlaptime = 0;
int timesincelastlap = 0;
//void moveSpaceShip(int i, int j) {
/*StopWatch = millis();
timesincelastlap = StopWatch - lastlaptime;
if (timesincelastlap > 500) {
spaceShipX[i] += spaceshipxspeed;
lastlaptime = millis();
// if (spaceShipX[i] > 990) {
// SpaceshipY = SpaceshipY + 30;
//spaceShipDirection = -1*spaceShipDirection;
// }
//if (spaceShipX[i] < 10) {
// SpaceshipY = SpaceshipY + 30;
//spaceShipDirection = -1*spaceShipDirection;
//}
//}
}*/
void moveSpaceShip() {
/*for (int i = 0; i < 15; i++){
if (spaceShipX[40] > 990){
spaceShipDirection = -1*spaceShipDirection;
SpaceshipY = SpaceshipY + 30;
}
if (spaceShipX[1] < 10){
spaceShipDirection = -1*spaceShipDirection;
SpaceshipY = SpaceshipY + 30;
}
}
for (int i = 0; i < 15; i++){
spaceShipX[i] = spaceShipX[i] + spaceShipDirection;
}*/
if (millis() - StopWatch > 1000) {
StopWatch = millis();
checkIfHitEdge();
moveShips();
}
}
void moveShips() {
for (int i = 0; i < 15; i++) {
ShipX[i] = ShipX[i] + spaceShipDirection*spaceshipSpeed;
}
}
void checkIfHitEdge() {
for (int i = 0; i < 15; i++) {
if (ShipX[14] > 990) {
SpaceshipY = SpaceshipY + 5;
spaceShipDirection = -1*spaceShipDirection;
}
if (ShipX[0] < 10) {
spaceShipDirection = -1*spaceShipDirection;
SpaceshipY = SpaceshipY + 5;
}
}
}
//void makespaceshipgodown(){
// if(SpaceshipX + 45 > width){
//SpaceshipY++;
// }
//}
void Maketankmove() {
if (moveLeft == true) {
TankX--; //this makes the tank go left
TankX = TankX - Xtankspeed;//this is for the speed of the tank
}
if (moveRight == true) {
TankX++;//this makes the tank go right
TankX = TankX + Xtankspeed;//the speed of the tank
}
}
void checkiftankhitedge() {
if (TankX > width-50) {
TankX = 950;
moveRight = false;
}
if (TankX-100 < -50) {
TankX = 50;
moveLeft = false;
}
}
void Makelaserreturentoorignalposition() {
//if(TankX++){
if (LaserY == 0) {
LaserY = TankY;
LaserX = 9999;
ShowLaser = false;
}
}
void checkiflaserhitspaceship(int i, int j) {
/* int Lasertop = LasersizeY - 20;
int Laserbottom = LasersizeY + 20;
int LaserLeft= LasersizeX - 5;
int LaserRight = LasersizeX +5;
int SpaceShipBottom = ShipY[j] - 40;
int SpaceShipTop = ShipY[j] + 40;
int SpaceShipleft = spaceShipX[i] - 45;
int SpaceShipright = spaceShipX[i] + 45;
boolean LaserhitSpaceship = Lasertop > SpaceShipBottom &&
Laserbottom < SpaceShipTop &&
LaserLeft < SpaceShipright &&
LaserRight > SpaceShipleft;
if(LaserhitSpaceship == true){
spaceShipX[0] = 90000;
}*/
}
void Shootlaser() {
if (ShowLaser == true) {
LaserY-=5;
}
}```
Here is what I think the issues are. First of all, processing is not the best language to make a game like Space Invaders. You can't have multiple key inputs at once. For example, if I press the left arrow, hold it, then press the right arrow, and let go of the left arrow, processing will ignore the left arrow. Processing has one key input: key. It can only have one value. You can't track multiple inputs at once. You can maybe replace it with your mouse - if the mouse is far to the left, move left. If it is far to the right, move right. In the middle? Stay still.
Aside from that, you want to check for collision. First of all, make the enemy into an object. I am assuming you know how to make objects. If not, look at this tutorial. Now, we need to check for collision. I'd suggest making a collision method inside of the enemy class, and here is what i'd imagine it to be:
boolean collidingWithPlayer() {
return (playerX > enemyX && playerX < enemyX + enemyW
&& playerY > enemyY && playerY < enemyY + enemyH);
}
Use this as you will. Good luck with your game.
On the main method of my code on the very last line, I have a directory to run maze.txt from my desktop to run the maze. How can I fix this problem because if I send this code to someone else they have to open the file and change the directory to the directory of the maze.txt which they downloaded with my file.**
Maze.txt
7 7
GOOOOXO
XXOXOOX
OXOOOXX
XXXOOXO
XXXXOXX
SOOOOOX
XXXXXXX
import java.io.*;
public class MazeSolver {
private char [][] maze;
private int startX , startY;
private int counter = 0;
public MazeSolver(String fileName) throws IOException {
maze = fileIterator(fileName);
startX = startX(maze);
startY = startY(maze);
solve(startX,startY);
System.out.println(printMaze());
}
public void solve(int x, int y) {
if (findPath(x,y)) {
maze[x][y] = 'S';
}
}
public boolean findPath(int x , int y){
counter ++;
if (maze[x][y] > 7) {return false;}
if (maze[x][y] == 'G') {return true;}
if (maze[x][y] == 'X' || maze[x][y] == 'O'){return false;}
maze[x][y] ='O';
boolean result;
result = findPath(x , y+1);
if(result){return true;}
result = findPath(x-1 , y);
if(result){return true;}
result = findPath(x , y-1);
if(result){return true;}
result = findPath(x+1 , y);
if(result){return true;}
maze[x][y] = 'O';
return false;
}
public String printMaze() {
String output = "";
for (int x = 0; x < 7; x++) {
for (int y = 0; y < 7; y++) {
output += maze[x][y] + " ";
}
output += "\n";
}
return output;
}
private char[][] fileIterator(String fileName) throws IOException {
File file = new File(fileName);
if(!file.exists()){
System.out.println(fileName+ "does not exists");
}
if(!(file.canRead() && file.isFile())){
System.out.println(fileName + "can not be read");
}
BufferedReader read = new BufferedReader(new FileReader(file));
String rea = read.readLine();
String[] split = rea.split(" ");
int row = Integer.valueOf(split[0]);
int col = Integer.valueOf(split[1]);
String readline;
int num = 0;
char [][] maze = new char[row][col];
while((readline = read.readLine()) != null){
char[] ch = readline.toCharArray();
for(int i = 0;i < ch.length;i++){
maze[i][num] = ch[i];
}
num++;
}
return maze;
}
private static int startX(char[][] charArray){
int startX = 0;
for(int i=0 ; i < charArray.length ; i++){
for(int j=0 ; j < charArray[i].length ; j++){
if(charArray[i][j] == 'S'){
startX = i;
}
}
}
return startX;
}
private static int startY(char[][] charArray){
int startY = 0;
for(int i=0 ; i < charArray.length ; i++){
for(int j=0 ; j < charArray[i].length ; j++){
if(charArray[i][j] == 'S'){
startY = j;
}
}
}
return startY;
}
public static void main(String[] args) throws IOException {
MazeSolver ms = new MazeSolver("C:\\Users\\mypc\\Desktop\\maze.txt");
}
}
There are many solutions for that, depending on what you need.
A simple one, if you want the users to experiment with different maze.txt files that they can provide, is to get the path of the file from the command line arguments (i.e., from the args parameter of the main method).
You could change your main method body to:
MazeSolver ms = new MazeSolver(args[0]);
Of course, further checks need to be made, but that's irrelevant for this exercise.
Then, the users run your program from the terminal as:
java MazeSolver /path/to/their/maze.txt
/path/to/their/maze.txt will be captured by args[0] in your main method.
import java.util.Scanner;
import java.io.*;
public class MazeSolver {
private char[][] maze;
private int startX;
private int startY;
private int row;
private int col;
private int endX;
private int endY;
public MazeSolver (String fileName) {
try {
Scanner get = new Scanner(new FileReader(fileName));
row = get.nextInt(); // Integer.parseInt(sChar[0]);
col = get.nextInt(); //col = Integer.parseInt(sChar[2]);
maze = new char[row][col];
String mazeString = "";
// Read the entire file and store in a String called mazeString
while(get.hasNextLine()) {
mazeString += get.nextLine();
}
char[] temp = mazeString.toCharArray();
for(int x = 0; x < row * col; x++) {
maze[x/row][x%col] = temp[x];
}
}
catch (IOException e) {
System.out.println("\nFile cannot be found. Please try again: \n");
System.exit(0);
}
char start = 'S';
for(int i = 0; i < row; i++) {
for(int x = 0; x < col; x++) {
char setStart = maze[i][x];
if(setStart == start) {
startX = i;
startY = x;
}
}
}
char goal = 'G';
for(int i = 0; i < row; i++) {
for(int x = 0; x < col; x++) {
char setEnd = maze[i][x];
if(setEnd == goal) {
endX = i;
endY = x;
}
}
}
if (solveMaze(startX,startY)){
System.out.println("Solution Found");
printMaze();
}
else{
System.out.println("No solution Found");
printMaze();
}
}
public void printMaze() {
for(int r = 0; r < row; r++) {
for(int c = 0; c < col; c++) {
System.out.print(maze[r][c]);
}
System.out.println();
}
}
public boolean solveMaze(int x, int y) {
// Base case
if(x == endX && y == endY) {
maze[x][y] = 'G';
maze[startX][startY]='S';
return true;
}
// Out of bounds
if((x >= 0 && x < row && y >= 0 && y < col && maze[x][y] != 'X' && maze[x][y] != '.') == true) {
maze[x][y] = '.';
// Right
if(solveMaze(x + 1, y)) {
return true;
}
// Left
if(solveMaze(x - 1, y)) {
return true;
}
// Up
if(solveMaze(x, y - 1)) {
return true;
}
// Down
if(solveMaze(x, y + 1)) {
return true;
}
else {
maze[x][y] = '#';
return false;
}
}
else {
return false;
}
}
}
I have a class Game which add to the logs score of my game.
Then I want to add the limit, that I can only 2 logs add for example and than logs don't added. But what I should to add in my Game.class that the class will communicate with the file log.properties? Should I use log4j?
Here is my Game.class:
import java.util.Random;
import java.util.logging.Logger;
public class Game {
public static final int numOfFutMarbles = 3; // przyszle kulki
private int score;
Field fieldProcessor = new Field();
Wave wave = new Wave();
Logger logger = Logger.getLogger(Game.class.getName());
Random random = new Random();
public final static int width = 9; // rozmiar planszy
public final static int height = 9;
public Bin[][] field;
public static final int not_sel = -1;
int activeBinX = not_sel;
int activeBinY = not_sel;
public Game() {
this.field = new Bin[width][height];
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
field[i][j] = new Bin(i, j);
}
}
placeMarbles(5, Marble.new_mar); // liczba kulek na poczatku
placeMarbles(3, Marble.fut_mar); // liczba przyszlych kulek
score = 0;
}
public void BinSelected(int i, int j) {
if (isBinContainsMarble(i, j)) {
activeBinchange(i, j);
}
}
boolean isBinContainsMarble(int i, int j) {
return field[i][j].isBinContainsMarble();
}
public void makeMoveOrSelect(int i, int j) {
if (field[i][j].isBinContainsMarble()) {
activeBinchange(i, j);
return;
}
if (activeBinX == not_sel) {
return;
}
if (wave.isMoveAvailable(field, activeBinX, activeBinY, i, j)) {
makeMove(i, j);
}
}
void makeMove(int x, int y) {
field[x][y].marble = field[activeBinX][activeBinY].marble;
field[x][y].setMarbleState(Marble.inac_mar);
field[activeBinX][activeBinY].marble = null;
activeBinX = not_sel;
activeBinY = not_sel;
boolean isLineRemoved = fieldProcessor.checkField(field);
if (!isLineRemoved) {
placeNewMarbles();
fieldProcessor.checkField(field);
}
calcScores();
wave.createWaveArrayFrom(field);
}
void activeBinchange(int i, int j) {
if (isActiveBinSelected()) {
field[activeBinX][activeBinY].setMarbleState(Marble.inac_mar);
}
field[i][j].setMarbleState(Marble.act_mar);
activeBinX = i;
activeBinY = j;
}
private boolean isActiveBinSelected() {
return activeBinX > not_sel;
}
void placeNewMarbles() {
int remaningFutureMarbles = calcRemaningFutureMarblesAndMakeThemNEW();
placeMarbles(numOfFutMarbles, Marble.fut_mar);
}
int calcRemaningFutureMarblesAndMakeThemNEW() {
int remainingFutureMarblesAmount = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (field[i][j].getMarbleState() == Marble.fut_mar) {
remainingFutureMarblesAmount++;
field[i][j].setMarbleState(Marble.new_mar);
}
}
}
return remainingFutureMarblesAmount;
}
void placeMarbles(int n, int state) {
for (int i = 0; i < n; i++) {
placeMarbleOnEmptySpace(state);
}
}
void placeMarbleOnEmptySpace(int state) { // umieszamy kulke na wolnym miejscu
boolean isPlaced = false;
do {
int i = random.nextInt(width);
int j = random.nextInt(height);
if (field[i][j].getMarbleState() == 0) {
field[i][j].marble = new Marble(state);
isPlaced = true;
}
} while (!isPlaced);
}
public void updateBins() {
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (field[i][j].marble != null) {
field[i][j].marble.porcessMarbles();
}
}
}
}
public int calcScores() {
int markedForDel = 0;
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
if (field[i][j].marble != null) {
if (field[i][j].marble.MarbleState == Marble.mark_for_rem) {
markedForDel++;
}
}
}
}
if (markedForDel > 0) {
int bon = (int) (4 + Math.pow(markedForDel - 4, 3)); // 6 kulek = 12 pkt, 7 kulek - 31 pkt
score += bon;
logger.info(score + "");
System.out.println("your score: " + score); // 1 pkt za kazda kulke
}
return score;
}
}
Here is my log configuration:
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
.level = ALL
# File Logging
java.util.logging.FileHandler.pattern=./logs/Marbles_game.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.limit=2
java.util.logging.FileHandler.count=100
# Console Logging
java.util.logging.ConsoleHandler.level = OFF
Add java.util.logging.FileHandler.append=true to your properties file. This will append data to the log file until it reaches the limit.
When I use a random matrix (class Determine), my program runs successfully in 1700 miliseconds. However, when I create a matrix by reading a file through a buffered reader (class Construct) my program experiences a logic error and enters and infinite loop.
Again, it works for a random matrix, but does not work for a 'real' matrix of the same size. I've checked my work and cannot find an error in my reading of the file. Does anyone know what may be causing this logic error? I will append my code with comments if it helps!
Update: OK the problem was from my own silly oversight (see my answer below). This did not occur with random data due to my 'haveIt' method and the probability of getting missing data. As such, my code has been updated to reflect this logic error and I will be happy to explain in detail how this code works if anyone asks:
import java.util.Random;
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
class ValMax {
public static int valMax;
}
class Construct {
private static int colEnd;
private static int colStart;
private static int[] colSkip;
public static List<List<Integer>> rFile(String[] args){
if (args.length != 4) {
System.out.println("Format: FileName colStart colEnd colSkipped");
System.exit(0);
}
BufferedReader reader = null;
try {
List<List<Integer>> matrix = new ArrayList<List<Integer>>();
Construct.colEnd = Integer.parseInt(args[2]);
Construct.colStart = Integer.parseInt(args[1]);
String[] colSkipped = args[3].split(",");
Construct.colSkip = new int[colSkipped.length];
for (int x = 0; x < colSkipped.length; x++) {
Construct.colSkip[x] = Integer.parseInt(colSkipped[x]);
}
String line;
reader = new BufferedReader(new FileReader(new File(args[0])));
while ((line = reader.readLine()) != null) {
String[] tokens = line.split(",");
List<Integer> rows = new ArrayList<Integer>(colEnd - colStart + 1 - colSkip.length);
for (int x = 1; x <= tokens.length; x++) {
if (x >= colStart && x <= colEnd && contains(x, colSkip) == false) {
try {
Double.parseDouble(tokens[x - 1]);
} catch (NumberFormatException e3) {
break;
}
if (tokens[x - 1].equals("-999")) { //
rows.add(2);
} else {
rows.add(1);
}
}
}
if (rows.size() == colEnd - colStart + 1 - colSkip.length) {
matrix.add(rows);
}
}
System.out.println(matrix.size() + "\t" + matrix.get(0).size());
return matrix;
} catch (IOException e1) {
System.out.println("IOEXCEPTION!!");
System.exit(0);
} catch (NumberFormatException e2) {
System.out.println("NumberFormatException!!");
System.exit(0);
} finally {
try {
reader.close();
} catch (IOException e5) {
e5.printStackTrace();
}
}
return null;
}
private static boolean contains(int a, int[] colSkip) {
boolean bluejay = false;
for (int skip : colSkip) {
if (a == skip) {
bluejay = true;
}
}
return bluejay;
}
}
class Determine {
private static Integer gen(int a, int b, Random r) {
Integer rand = r.nextInt(a) + b;
return rand;
}
public static List<List<Integer>> rando() {
Random r = new Random();
int k = gen(1, 24, r), l = gen(1, 33, r); //userinput
List<List<Integer>> matrix = new ArrayList<List<Integer>>(k);
for (int x = 1; x <= k; x++) {
List<Integer> row = new ArrayList<Integer>(l);
for (int y = 1; y <= l; y++) {
double bias = Math.random();
if (bias > 0.7) {
row.add(2);
} else {
row.add(1);
}
}
matrix.add(row);
}
return matrix;
}
}
class Search {
public static void finalize(List<List<Integer>> matTan, boolean gumDrop, int minimum) {
final int A = matTan.size();
final int B = matTan.get(0).size();
boolean judge = true;
if (minimum > A && gumDrop == false || minimum > B && gumDrop == true) {
System.out.print("\nMinimum too high\n\n");
System.exit(0);
}
ValMax.valMax = 1; //userinput
int[] rows = new int[2 + A + B];
List<int[]> combination = new ArrayList<int[]>(100);
int threads = Runtime.getRuntime().availableProcessors();
ExecutorService service = Executors.newFixedThreadPool(threads);
List<List<int[]>> ranTime = new ArrayList<List<int[]>>(2 * threads);
for (int x = 0; x < 2 * threads; x++) {
List<int[]> jobs = new ArrayList<int[]>(90);
ranTime.add(jobs);
}
if (gumDrop == false) {
for (int x = 1; x <= minimum; x++) {
rows[x] = 1;
}
} else {
rows[1] = 1;
}
rows[A + 1] = 999;
int y = 0, z = 0;
System.out.println(threads);
while (rows[A + 1] == 999) {
y++;
int[] copy = Arrays.copyOf(rows, rows.length);
if (y == 91) {
z++;
y = 1;
if (z < 2* threads) {
ranTime.get(z).clear();
}
}
if (z == 2 * threads) {
processInputs(ranTime, combination, matTan, minimum, gumDrop, service);
z = 0;
ranTime.get(0).clear();
ranTime.get(0).add(copy);
} else {
ranTime.get(z).add(copy);
}
nextComb(A, rows);
}
if (ranTime.get(0).size() > 0) {
for (int x = 0; x < 2 * threads; x++) {
if (judge == false) {
ranTime.remove(x);
threads--;
x--;
}
if (ranTime.get(x).size() != 90 && judge == true) {
judge = false;
}
}
processInputs(ranTime, combination, matTan, minimum, gumDrop, service);
}
service.shutdown();
try {
service.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e6) {
System.out.print("Termination Error!");
}
developed(matTan, combination, gumDrop);
}
private static void processInputs(List<List<int[]>> ranTime, List<int[]> combination, List<List<Integer>> matTan, int minimum, boolean gumDrop, ExecutorService service) {
Collection<StringTask> collection = new ArrayList<StringTask>(ranTime.size());
for (List<int[]> jobs : ranTime) {
StringTask analysis = new StringTask(jobs, combination, matTan, minimum, gumDrop);
collection.add(analysis);
}
try {
List<Future<Integer>> futures = service.invokeAll(collection);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void developed(List<List<Integer>> matTan, List<int[]> combination, boolean gumDrop) {
System.out.print("\n\n\n");
for (int[] e : combination) {
if (e[0] == ValMax.valMax) { // == ValMax.valMax
Optimize10.prin(e);
List<List<Integer>> complete = Multi.reduct1(e, matTan);
if (gumDrop == true) {
System.out.println("Solution Matrix, transposed [above data works on column]");
Optimize10.prin(Multi.transpose(complete)); //The solution matrix, reorientated
} else {
System.out.println("Solution Matrix");
Optimize10.prin(complete); //The solution matrix, reorientated
}
}
}
}
private static void nextComb(int bounds, int[] rows) {
int kappas = findMax(rows);
if (rows[bounds] == 0) {
rows[kappas + 1] = 1;
rows[kappas] = 0;
} else {
int y = 1;
int x = bounds;
while (rows[x] == 1) {
rows[x] = 0;
y++;
x--;
}
kappas = findMax(rows);
if (kappas != -1) {
rows[kappas] = 0;
}
int z = kappas + 1;
while (y > 0) {
rows[z] = 1;
z++;
y--;
}
}
}
private static int findMax(int[] rows) {
int y = 0;
for (int x = rows.length - 1; x >= 0; x--) {
if (rows[x] == 1) {
return x;
}
}
return y;
}
}
class StringTask implements Callable<Integer> {
private List<List<Integer>> matTan;
private List<int[]> combination;
private List<int[]> jobs;
private boolean gumDrop;
private int minimum;
StringTask(List<int[]> a, List<int[]> b, List<List<Integer>> c, int d, boolean e) {
this.combination = b;
this.minimum = d;
this.gumDrop = e;
this.matTan = c;
this.jobs = a;
}
public Integer call() {
for (int[] e : jobs) {
int temp = Multi.reduct2(e, matTan, minimum, gumDrop);
if (temp > ValMax.valMax) { //ValMax.valMax //userinput
ValMax.valMax = e[0]; //userinput
combination.add(e);
System.out.print(ValMax.valMax + " ");
}
}
return null;
}
}
class Multi {
public static int[] inverse;
public static void halveIt(int[] col, List<List<Integer>> matCop) {
int size = matCop.size(), a = 0;
inverse = new int[size];
for (int x = 0; x < size; x++) {
for (int y = 0; y < matCop.get(0).size(); y++) {
if (col[y] == 1 && matCop.get(x).get(y) == 2) {
inverse[x + a] = 1;
matCop.remove(x);
size--;
x--;
a++;
break;
}
}
}
}
public static List<List<Integer>> reduct1(int[] row, List<List<Integer>> matCan) {
List<List<Integer>> matTan = new ArrayList<List<Integer>>(matCan);
int with = matTan.size(), high = inverse.length, a = 0;
final int B = matCan.get(0).size() - 1;
final int A = matCan.size();
for (int x = 0; x < A; x++) {
List<Integer> value = new ArrayList<Integer>(matCan.get(x));
matTan.set(x, value);
}
int y = 0, size = 0;
for (int x = 0; x < high; x++) {
if (x < with) {
if (row[x + a + 1] > 0) {
size = matTan.get(0).size();
for (y = 0; y < size; y++) {
if (matTan.get(x).get(y) == 2) {
for (int z = 0; z < with ; z++) {
matTan.get(z).remove(y);
}
size--;
y--;
}
}
} else {
matTan.remove(x);
with--;
high--;
x--;
a++;
}
}
}
return matTan;
}
public static int reduct2(int[] row, List<List<Integer>> matCan, int minimum, boolean gumDrop) {
int b = 0, c = 0, d = 0, e = 0, g = 0, high = inverse.length;
final int B = matCan.get(0).size() - 1;
final int A = matCan.size();
for (int x = 0; x < high; x++) {
if (x < A) {
if (row[x + 1] > 0) {
b++;
for (int y = 0; y < B + 1; y++) {
if (matCan.get(x).get(y) == 2 && row[2 + A + y] == 0) {
row[2 + A + y] = 1; // 1s mean that a column was deleted, 0 is kept.
d -= e;
} else if (row[2 + A + y] == 0) {
d++;
}
}
e++;
}
}
if (inverse[x] == 0 && x < high || gumDrop == true && x < high) {
if (row[x - c + 1] == 1) {
row[x - c + 1] = 1 + c + g;
g++;
} else {
g++;
}
} else {
c++;
}
}
if (d / b < minimum && gumDrop == true) {
row[0] = 0;
d = 0;
} else {
row[0] = d;
}
return d;
}
public static List<List<Integer>> transpose(List<List<Integer>> matTan) {
int d = matTan.get(0).size();
List<List<Integer>> matFlip = new ArrayList<List<Integer>>(d);
for (int y = 0; y < d; y++) {
List<Integer> row = new ArrayList<Integer>();
for (int x = 0; x < matTan.size(); x++) {
row.add(matTan.get(x).get(y));
}
matFlip.add(row);
}
return matFlip;
}
}
// ########## Main Method Start ##########
public class Optimize10 {
public static void main(String[] args) {
double startTime = System.nanoTime() / 1000000;
List<List<Integer>> matrix = Determine.rando();
// List<List<Integer>> matrix = Construct.rFile(args);
List<List<Integer>> matTan = contract(new int[matrix.get(0).size()], matrix);
int a = matTan.size(), b = matTan.get(0).size();
System.out.println(a + "\t" + b);
boolean gumDrop = false;
int minimum = 40; //userinput
BigInteger aNew = new BigInteger("2");
BigInteger bNew = new BigInteger("2");
aNew = aNew.pow(a);
bNew = bNew.pow(b);
for (int x = 1; x < minimum; x++) {
aNew = aNew.subtract(binomial(a, x));
}
if (aNew.compareTo(bNew) > 0) {
gumDrop = true;
matTan = Multi.transpose(matTan);
}
System.out.println(gumDrop);
prin(matrix);
prin(matTan);
Search.finalize(matTan, gumDrop, minimum);
double endTime = System.nanoTime() / 1000000;
double duration = (endTime - startTime);
System.out.println(duration);
}
// ########## MAIN METHOD END ############
private static BigInteger binomial(final int N, final int K) {
BigInteger ret = BigInteger.ONE;
for (int k = 0; k < K; k++) {
ret = ret.multiply(BigInteger.valueOf(N-k)).divide(BigInteger.valueOf(k+1));
}
return ret;
}
private static List<List<Integer>> contract(int[] col, List<List<Integer>> matrix) {
List<List<Integer>> matCop = new ArrayList<List<Integer>>(matrix);
col[0] = 1; //userinput 1 means don't delete!
col[1] = 1; //userinput
col[2] = 1;
col[12] = 1;
col[14] = 1;
col[22] = 1;
col[28] = 1;
col[29] = 1;
Multi.halveIt(col, matCop);
return matCop;
}
public static void prin(List<List<Integer>> matrix) {
for (int x = 0; x < matrix.size(); x ++) {
System.out.print("[" + matrix.get(x).get(0));
for (int y = 1; y < matrix.get(0).size(); y++) {
System.out.print(" " + matrix.get(x).get(y));
}
System.out.print("]\n");
}
System.out.print("\n\n");
}
public static void prin(int[] a) {
System.out.print("[" + a[0]);
for (int x = 1; x < a.length; x ++) {
System.out.print(" " + a[x]);
}
System.out.print("]\n\n");
}
public static void prin(String[] a) {
System.out.print("[" + a[0]);
for (int x = 1; x < a.length; x ++) {
System.out.print(" " + a[x]);
}
System.out.print("]\n\n");
}
public static void prin2(List<Integer> a) {
System.out.print("[" + a.get(0));
for (int x = 1; x < a.size(); x ++) {
System.out.print(" " + a.get(x));
}
System.out.print("]\n\n");
}
}
OK, so there actually was no infinite loop in this code whatsoever. The problem was with line 466 of my code; specifically, I was basing whether I analyzed the original matrix or its transpose on the number of rows after truncation on the original matrix and subtracting the minimum. This is wrong because, for example,
sum_{i = 40)^{54}(54 choose i) >> 2^32.
My program was taking forever because it was told to traverse through over a trillion combinations instead of 'just' a few billion. Granted it can do 10 billion in about 2 hours, and I can save more time by inverting a few nested for loops (another time).
I Guess it's time to learn profiling to see where my code slows down.
Hi could anybody help me understand this particular piece of code from this Langton's Ant sketch.
antLoc = new int[]{rows/2,columns/2};
I don't exactly understand what is actually happening here, here is the rest of the code for context. (originally from here http://www.openprocessing.org/visuals/?visualID=13653)
boolean[][] state;
int[] antLoc;
int antDirection;
int squareSize = 5;
int columns, rows;
color bgCol = color(0,128,128);
color antCol = color (255,0,0);
color sqCol = color(128,128,128);
void setup(){
size(800,600);
background(bgCol);
columns = width/squareSize;
rows = height/squareSize;
state = new boolean[rows][columns];
for(int j = 0; j < rows; j++){
for(int i = 0; i < columns; i++){
state[j][i] = false;
}
}
antLoc = new int[]{rows/2,columns/2};
antDirection = 1;
}
void drawScene(){
fill(sqCol);
for(int j = 0; j < rows; j++){
for(int i = 0; i < columns; i++){
if(state[j][i]){
rect(i*squareSize,j*squareSize,squareSize,squareSize);
}
}
}
fill(antCol);
rect(antLoc[1]*squareSize,antLoc[0]*squareSize,squareSize,squareSize);
}
void turnLeft(){
if (antDirection > 1){
antDirection--;
} else{
antDirection = 4;
}
}
void turnRight(){
if (antDirection < 4){
antDirection++;
} else {
antDirection = 1;
}
}
void moveForward(){
if (antDirection == 1){
antLoc[0]--;
}
if (antDirection == 2){
antLoc[1]++;
}
if (antDirection == 3){
antLoc[0]++;
}
if (antDirection == 4){
antLoc[1]--;
}
}
void updateScene(){
moveForward();
if (state[antLoc[0]][antLoc[1]] == false){
state[antLoc[0]][antLoc[1]] = true;
turnRight();
} else {
state[antLoc[0]][antLoc[1]] = false;
turnLeft();
}
}
void draw(){
background(bgCol);
drawScene();
for(int i = 0; i < 10; i++){
updateScene();
}
}
The line you mention:
antLoc = new int[]{rows/2,columns/2};
is broadly similar to:
antLoc = new int[2];
antLoc[0] = rows / 2;
antLoc[1] = columns / 2;
It's just syntactic shorthand, for convenience.
Your code creates a new array of int with length 2, and initialises the elements with the given expressions. It is equivalent to:
antLoc = new int[2];
antLoc[0] = rows/2;
antLoc[1] = columns/2;