Recursively find connectivity in a 2D Array - java

I have a game and I'm having trouble implementing the scores.
Prof stated that it must be recursively done without a for-loop. But I'm having trouble thinking of the algorithm that is used. This is the game.
The score system works so it starts with the valve pipe (Pipe.ValvePipe) and then it checks to see how many pipes are connected to it. Is there a certain algorithm/strategy for doing this type of recursion? Thank you in advance.
pipe.java
public class Pipe {
private boolean openAtTop;
private boolean openAtRight;
private boolean openAtBottom;
private boolean openAtLeft;
private boolean isValve;
private static Pipe VALVE_PIPE;
public Pipe(boolean t, boolean r, boolean b, boolean l, boolean valve) {
openAtTop = t; openAtBottom = b; openAtRight = r; openAtLeft = l;
isValve = valve;
}
public boolean isValve() { return isValve; }
public static Pipe ValvePipe() { return new Pipe(false, false, true, false, true); }
public boolean isValid() { return !(!openAtTop&&!openAtBottom&&!openAtLeft&&!openAtRight); }
public static Pipe RandomPipe() {
Pipe p;
do {
p = new Pipe(Math.random() < 0.5, Math.random() < 0.5,
Math.random() < 0.5, Math.random() < 0.5, false);
} while (!p.isValid());
return p;
}
public boolean isOpenAtTop() { return openAtTop; }
public boolean isOpenAtBottom() { return openAtBottom; }
public boolean isOpenAtLeft() { return openAtLeft; }
public boolean isOpenAtRight() { return openAtRight; }
public boolean fitsBelow(Pipe p) {
return (p == null) || (!openAtTop && !p.isOpenAtBottom()) || (openAtTop && p.isOpenAtBottom());
}
public boolean fitsAbove(Pipe p) {
return (p == null) || (!openAtBottom && !p.isOpenAtTop()) || (openAtBottom && p.isOpenAtTop());
}
public boolean fitsToLeftOf(Pipe p) {
return (p == null) || (!openAtRight && !p.isOpenAtLeft()) || (openAtRight && p.isOpenAtLeft());
}
public boolean fitsToRightOf(Pipe p) {
return (p == null) || (!openAtLeft && !p.isOpenAtRight()) || (openAtLeft && p.isOpenAtRight());
}
public String toString() {
String s = "";
if (openAtTop) s+="1"; else s+="0";
if (openAtRight) s+="1"; else s+="0";
if (openAtBottom) s+="1"; else s+="0";
if (openAtLeft) s+="1"; else s+="0";
return s;
}
public int toInt() {
int s = 0;
if (openAtTop) s+=8;
if (openAtRight) s+=4;
if (openAtBottom) s+=2;
if (openAtLeft) s+=1;
return s;
}
}
PipeGameView.java
import java.awt.*;
import javax.swing.*;
// Subclass JFrame so you can display a window
public class PipeGameView extends JPanel {
private PipeGame game; // The model
private BoardPanel tiles;
private JButton[][] buttons;
private JProgressBar timeBar;
private JButton startStop;
private JRadioButton twoMinButton, tenMinButton, noLimitButton;
private JLabel statusLabel;
// This constructor builds the window
public PipeGameView(PipeGame g) {
game = g; // Store the model for access in update()
// Set up the components
tiles = new BoardPanel();
tiles.setLayout(new GridLayout(game.getRows(), game.getRows()));
buttons = new JButton[game.getRows()][game.getRows()];
// Add the buttons to the tile panel
ImageIcon ic = new ImageIcon("Pipes0000.GIF");
for (int r=0; r<game.getRows(); r++) {
for (int c=0; c<game.getRows(); c++) {
buttons[r][c] = new JButton(ic);
tiles.add(buttons[r][c]);
}
}
// Now layout the components using a gridbag layout
GridBagLayout layout = new GridBagLayout();
GridBagConstraints layoutConstraints = new GridBagConstraints();
this.setLayout(layout);
// Add the Start/Stop Button
startStop = new JButton("Start Game");
layoutConstraints.gridx = 0; layoutConstraints.gridy = 0;
layoutConstraints.gridwidth = 1; layoutConstraints.gridheight = 1;
layoutConstraints.fill = GridBagConstraints.BOTH;
layoutConstraints.insets = new Insets(2, 2, 2, 2);
layoutConstraints.anchor = GridBagConstraints.NORTHWEST;
layoutConstraints.weightx = 0.0; layoutConstraints.weighty = 0.0;
layout.setConstraints(startStop, layoutConstraints);
this.add(startStop);
// Add the JRadioButtons
twoMinButton = new JRadioButton("2 minutes");
tenMinButton = new JRadioButton("10 minutes");
noLimitButton = new JRadioButton("No Time Limit");
ButtonGroup group = new ButtonGroup();
group.add(twoMinButton); group.add(tenMinButton); group.add(noLimitButton);
layoutConstraints.gridx = 1;
layout.setConstraints(twoMinButton, layoutConstraints);
this.add(twoMinButton);
layoutConstraints.gridx = 2;
layout.setConstraints(tenMinButton, layoutConstraints);
this.add(tenMinButton);
layoutConstraints.gridx = 3;
layout.setConstraints(noLimitButton, layoutConstraints);
this.add(noLimitButton);
// Add the tiles
layoutConstraints.gridx = 0; layoutConstraints.gridy = 1;
layoutConstraints.gridwidth = 4; layoutConstraints.gridheight = 1;
layoutConstraints.fill = GridBagConstraints.BOTH;
layoutConstraints.insets = new Insets(2, 2, 2, 2);
layoutConstraints.anchor = GridBagConstraints.NORTHWEST;
layoutConstraints.weightx = 0.0; layoutConstraints.weighty = 0.0;
layout.setConstraints(tiles, layoutConstraints);
this.add(tiles);
// Add the label
statusLabel = new JLabel("Time Left: ");
statusLabel.setVisible(false);
layoutConstraints.gridx = 0; layoutConstraints.gridy = 2;
layoutConstraints.gridwidth = 1; layoutConstraints.gridheight = 1;
layoutConstraints.fill = GridBagConstraints.NONE;
layoutConstraints.insets = new Insets(2, 2, 2, 2);
layoutConstraints.anchor = GridBagConstraints.WEST;
layoutConstraints.weightx = 0.0; layoutConstraints.weighty = 0.0;
layout.setConstraints(statusLabel, layoutConstraints);
this.add(statusLabel);
timeBar = new JProgressBar(0, 100);
timeBar.setValue(100);
timeBar.setVisible(false);
layoutConstraints.gridx = 1; layoutConstraints.gridy = 2;
layoutConstraints.gridwidth = 3; layoutConstraints.gridheight = 1;
layoutConstraints.fill = GridBagConstraints.HORIZONTAL;
layoutConstraints.insets = new Insets(2, 2, 2, 2);
layoutConstraints.anchor = GridBagConstraints.EAST;
layoutConstraints.weightx = 5.0; layoutConstraints.weighty = 0.0;
layout.setConstraints(timeBar, layoutConstraints);
this.add(timeBar);
update();
}
// Get methods for the components
public JButton getButton(int r, int c) { return buttons[r][c]; }
public JButton getStartStopButton() { return startStop; }
public JProgressBar getTimeBar() { return timeBar; }
public JRadioButton getTwoMinButton() { return twoMinButton; }
public JRadioButton getTenMinButton() { return tenMinButton; }
public JRadioButton getNoLimitButton() { return noLimitButton; }
public void setGame(PipeGame g) { game = g; }
// This is called whenever the model has changed. Note that this code is not efficient. All ICONS should really
// be loaded upon game start and stored into a static array of ImageIcons. Then, these static icons should be
// used instead of re-creating icons each time.
public void update() {
// Update the look of the buttons
for (int r=0; r<game.getRows(); r++) {
for (int c=0; c<game.getRows(); c++) {
if (game.isOver())
buttons[r][c].setEnabled(false);
else
buttons[r][c].setEnabled(true);
if (game.getPipe(r,c) == null)
buttons[r][c].setSelected(false);
else {
// Determine the portion of the icon's filename that matches the pipe
String currentPipeCodes = "Start";
if (!game.getPipe(r,c).isValve())
currentPipeCodes = game.getPipe(r,c).toString();
buttons[r][c].setSelectedIcon(new ImageIcon("pipes"+ currentPipeCodes +".GIF"));
buttons[r][c].setSelected(true);
}
}
}
// Update the start/stop button
if (game.isOver())
startStop.setText("Start");
else
startStop.setText("Stop");
// Update the radio buttons
if (game.isOver()) {
twoMinButton.setEnabled(true);
tenMinButton.setEnabled(true);
noLimitButton.setEnabled(true);
}
else {
twoMinButton.setEnabled(false);
tenMinButton.setEnabled(false);
noLimitButton.setEnabled(false);
}
// Update the status label
if (game.isOver()) {
statusLabel.setText("Final Score: " + game.getPlacedPipes());
statusLabel.setVisible(true);
}
else {
if (game.getStyle() == 2) {
statusLabel.setVisible(false);
}
else {
statusLabel.setText("Time Left: ");
statusLabel.setVisible(true);
}
}
// Update the timer bar
if (game.isOver() || (game.getStyle() == 2)) {
timeBar.setVisible(false);
}
else {
timeBar.setValue((int)(game.getTimeRemaining() / (float)game.getTimeLimit() * 100));
timeBar.setVisible(true);
}
// Update the cursor
ImageIcon i;
if (game.isOver()) {
tiles.setCursor(Cursor.getDefaultCursor());
}
else {
if (game.getNextPipe().isValve())
i = new ImageIcon("pipesStart.GIF");
else
i = new ImageIcon("pipes"+ game.getNextPipe().toString() +".GIF");
tiles.setCursor(Toolkit.getDefaultToolkit().createCustomCursor(i.getImage(), new Point(0,0), "pipe"));
}
}
}

I didnt go through all your code but as a hint the function would look like this:
getScore( Pipe p ){
if ( p == null ) return 0;
int res = 1; // size of this pipe
res += getScore(leftPipe);
res += getScore(rightPipe);
...
return res;
}
hope this helps

I think you need to includes the row and col to calculate the pipes that are connected to the main starting pipe
public void connectedPipes(int row, int col){
if(row == null) return 0;
int res = 1; // size of this pipe
res += getScore(leftPipe);
res += getScore(rightPipe);
return res;
}

Related

Null Pointer Exception with a timer

I am having an issue with an assignment I have: I need to write a game with a timer component but I get a "Exception in thread "Timer-0" java.lang.NullPointerException" error. I am using the latest version of eclipse. Help would be appreciated.
The actual error:
Exception in thread "Timer-0" java.lang.NullPointerException
at GameFrame$MyTimerTask.run(GameFrame.java:152)
at java.util.TimerThread.mainLoop(Unknown Source)
at java.util.TimerThread.run(Unknown Source)
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class GameFrame extends JFrame implements ActionListener {
private final int NUM_BUTTONS1 = 5;
private final int NUM_BUTTONS2 = 8;
private final int NUM_BUTTONS3 = 10;
private final int NUM_LEVELS = 3;
private int[] columns,lines;
private int current_size,hours,minutes,seconds,score,selection_counter;
private int c1,c2,c3,c4,l1,l2,l3,l4;
private Color color1,color2,color3,color4;
private JButton [] buttons,selection;
private JButton [] levels;
private JPanel buttons_panel,levels_panel;
private JTextField timer_field,score_field;
private Timer timer;
public GameFrame() {
current_size = NUM_BUTTONS1;
setLayout(new BorderLayout());
buttons_panel = new JPanel();
buttons_panel.setLayout(new GridLayout(NUM_BUTTONS1,NUM_BUTTONS1));
//setup buttons
buttons = new JButton[NUM_BUTTONS3 * NUM_BUTTONS3];
for(int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
switch((int)(Math.random() * 4)) {
case 0:
buttons[i].setBackground(Color.BLUE);
break;
case 1:
buttons[i].setBackground(Color.RED);
break;
case 2:
buttons[i].setBackground(Color.GREEN);
break;
case 3:
buttons[i].setBackground(Color.YELLOW);
break;
}
buttons[i].addActionListener(this);
}
//add buttons to layout
for(int i = 0; i < NUM_BUTTONS1 * NUM_BUTTONS1; i++)
buttons_panel.add(buttons[i]);
levels_panel = new JPanel();
levels_panel.setLayout(new GridLayout(3,1));
levels = new JButton[NUM_LEVELS];
for(int i = 0; i < levels.length; i++) {
levels[i] = new JButton("level "+ (i + 1));
levels[i].addActionListener(this);
levels_panel.add(levels[i]);
}
selection_counter = 0;
selection = new JButton[4];
columns = new int [4];
lines = new int [4];
hours = 0;
minutes = 0;
seconds = 0;
timer = new Timer();
timer.schedule(new MyTimerTask(), 0,1000);
timer_field = new JTextField();
timer_field.setText(hours + ":" + minutes + ":" + seconds);
timer_field.setFont(new Font("random",0,50));
timer_field.setHorizontalAlignment(JTextField.CENTER);
timer_field.setBackground(Color.white);
timer_field.setForeground(Color.green);
add(timer_field,BorderLayout.SOUTH);
score_field = new JTextField();
score_field.setText("Game Score: " + score);
score_field.setFont(new Font("random",0,50));
score_field.setHorizontalAlignment(JTextField.CENTER);
score_field.setBackground(Color.white);
score_field.setForeground(Color.green);
add(score_field,BorderLayout.NORTH);
//add buttons layout and levels buttons layout
add(buttons_panel,BorderLayout.CENTER);
add(levels_panel,BorderLayout.WEST);
}
#Override
public void actionPerformed(ActionEvent event) {
//change levels
if (event.getSource() == levels[0] || event.getSource() == levels[1] || event.getSource() == levels[2]) {
if (event.getSource() == levels[0])
current_size = NUM_BUTTONS1;
else if (event.getSource() == levels[1])
current_size = NUM_BUTTONS2;
else if (event.getSource() == levels[2])
current_size = NUM_BUTTONS3;
buttons_panel.removeAll();
//redefine grid Layout to match the new current_size
buttons_panel.setLayout(new GridLayout(current_size, current_size));
for(int i = 0; i < current_size * current_size; i++)
buttons_panel.add(buttons[i]);
newGame(); //changing levels requires starting a new game
}
//select a rectangle on the board
else if (event.getSource() instanceof JButton) {
selection[selection_counter++] = (JButton)event.getSource();
if (selection_counter == 4) {
selection_counter = 0;
columns = findCoordinates(true);
lines = findCoordinates(false);
if (buttonsSelectionCheck()) {
updateBoard();
}
}
}
//update the window
timer_field.setText(hours + ":" + minutes + ":" + seconds);
score_field.setText("Game Score: " + score);
buttons_panel.validate();
repaint();
}
public class MyTimerTask extends TimerTask {
public void run() {
seconds++;
if (seconds == 60) {
minutes++;
seconds = 0;
}
if (minutes == 60) {
hours++;
minutes = 0;
}
timer_field.setText(hours + ":" + minutes + ":" + seconds);
}
}
private void newGame() {
score = 0;
seconds = 0;
minutes = 0;
hours = 0;
selection_counter = 0;
selection[0] = null;
selection[1] = null;
selection[2] = null;
selection[3] = null;
for(int i = 0; i < buttons.length; i++) {
switch((int)(Math.random() * 4)) {
case 0:
buttons[i].setBackground(Color.BLUE);
break;
case 1:
buttons[i].setBackground(Color.RED);
break;
case 2:
buttons[i].setBackground(Color.GREEN);
break;
case 3:
buttons[i].setBackground(Color.YELLOW);
break;
}
}
}
private int[] findCoordinates(boolean choice) {
int[] columns = new int[4];
int[] lines = new int[4];
for (int i = 0; i < selection.length; i++)
for (int j = 0; j < buttons.length; j++)
if (selection[i] == buttons[j]) {
if (choice)
columns[i] = j%current_size;
else
lines[i] = j/current_size;
}
if (choice)
return columns;
else
return lines;
}
public boolean buttonsSelectionCheck() {
c1 = columns[0];
c2 = columns[1];
c3 = columns[2];
c4 = columns[3];
l1 = lines[0];
l2 = lines[1];
l3 = lines[2];
l4 = lines[3];
color1 = selection[0].getBackground();
color2 = selection[1].getBackground();
color3 = selection[2].getBackground();
color4 = selection[3].getBackground();
if (color1 != Color.GRAY && color1 == color2 && color2 == color3 && color3 == color4)
if (c1 == c4 && c2 == c3 && l1 == l2 && l3 == l4 ) {
return true;
}
return false;
}
private void updateBoard() {
int b_column,b_line;
for (int i = 0; i < (current_size * current_size); i++) {
b_column = i%current_size;
b_line = i/current_size;
if (b_column >= c1 && b_column <= c2 && b_line >= l1 && b_line <= l4) {
if (buttons[i].getBackground() != Color.GRAY)
score+=10;
buttons[i].setBackground(Color.GRAY);
}
}
}
}
This line causes the MyTimerTask instance to be executed with a delay of 0 (no delay).
timer.schedule(new MyTimerTask(), 0,1000);
MyTimerTask accesses the field timer_field, which is initialized after the schedule statement.
timer_field = new JTextField();
So the timer_field is still null.
Solution:
// timer.schedule(new MyTimerTask(), 0,1000);
timer_field = new JTextField();
timer_field.setText(hours + ":" + minutes + ":" + seconds);
timer_field.setFont(new Font("random",0,50));
timer_field.setHorizontalAlignment(JTextField.CENTER);
timer_field.setBackground(Color.white);
timer_field.setForeground(Color.green);
timer.schedule(new MyTimerTask(), 0,1000);
So the schedule call should be a bit later.
your inner class MyTimerTask uses timer_field before it's initialised.
you can move these lines:
timer = new Timer();
timer.schedule(new MyTimerTask(), 0,1000);
to the end of the constructor, so that it is after this one which initialises timer_field:
timer_field = new JTextField();

Java jFrame canvas draws dots instead of lines

I've been wanting to design a generator for dragon curves.
(If you want info on that check this out, but it doesn't really matter for the issue)
A dragon curve is a repeating mathematical construct.
I've already written a generator for what the canvas should draw, it works by returning a char array consisting of 'r' or 'l', saying whether the line has to turn left or right next. In the code here, it's the method input(). This part works perfectly.
The problem is that whenever I want to draw it on the canvas (using drawLine), it only draws the first two lines as actual lines, the rest are just dots.
The dots are on the right positions and if you make the thing really big, you can't tell the difference anymore, but nevertheless, there are supposed to be lines there.
Image:
This is the code I used:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
*
* Description
*
* #version 1.0 from 4/20/2016
* #author
*/
public class CurveGen extends JFrame {
// start attributes
private Canvas display = new Canvas();
private JButton startButton = new JButton();
private JLabel jLabel1 = new JLabel();
private JTextArea outText = new JTextArea("");
private JScrollPane outTextScrollPane = new JScrollPane(outText);
private JLabel jLabel2 = new JLabel();
private JSlider xSlider = new JSlider();
private JSlider ySlider = new JSlider();
private JNumberField iterationsNF = new JNumberField();
private JNumberField sizeNF = new JNumberField();
// end attributes
public CurveGen(String title) {
// Frame-Init
super(title);
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
int frameWidth = 1022;
int frameHeight = 731;
setSize(frameWidth, frameHeight);
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
int x = (d.width - getSize().width) / 2;
int y = (d.height - getSize().height) / 2;
setLocation(x, y);
setResizable(false);
Container cp = getContentPane();
cp.setLayout(null);
// start components
display.setBounds(16, 64, 601, 601);
cp.add(display);
startButton.setBounds(736, 464, 241, 129);
startButton.setText("START!");
startButton.setMargin(new Insets(2, 2, 2, 2));
startButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
startButton_ActionPerformed(evt);
}
});
startButton.setFont(new Font("Dialog", Font.BOLD, 36));
cp.add(startButton);
jLabel1.setBounds(760, 96, 75, 41);
jLabel1.setText("Iterations:");
cp.add(jLabel1);
outTextScrollPane.setBounds(728, 392, 257, 57);
cp.add(outTextScrollPane);
jLabel2.setBounds(768, 144, 67, 41);
jLabel2.setText("Size:");
cp.add(jLabel2);
xSlider.setBounds(0, 8, 633, 49);
xSlider.setMinorTickSpacing(25);
xSlider.setMajorTickSpacing(100);
xSlider.setPaintTicks(true);
xSlider.setPaintLabels(true);
xSlider.setToolTipText("Starting point y-coordinate");
xSlider.setMaximum(600);
xSlider.setValue(300);
cp.add(xSlider);
ySlider.setBounds(624, 56, 65, 625);
ySlider.setMinorTickSpacing(25);
ySlider.setMajorTickSpacing(100);
ySlider.setPaintTicks(true);
ySlider.setPaintLabels(true);
ySlider.setOrientation(SwingConstants.VERTICAL);
ySlider.setMaximum(600);
ySlider.setInverted(true);
ySlider.setValue(300);
ySlider.setToolTipText("Starting point x-coordinate");
cp.add(ySlider);
iterationsNF.setBounds(856, 96, 81, 41);
iterationsNF.setText("");
cp.add(iterationsNF);
sizeNF.setBounds(856, 144, 81, 41);
sizeNF.setText("");
cp.add(sizeNF);
// end components
setVisible(true);
} // end of public CurveGen
// start methods
public static void main(String[] args) {
new CurveGen("CurveGen");
} // end of main
public char[] input(int iter) {
char oldOut[] = new char[0];
for (int i=1;i<=iter;i++) {
char newOut[] = new char[((int)Math.pow(2, i))-1];
for (int n=0;n<oldOut.length;n++) {
newOut[n] = oldOut[n];
if (oldOut[n]=='r') {
newOut[newOut.length-n-1] = 'l';
}
if (oldOut[n]=='l') {
newOut[newOut.length-n-1] = 'r';
} // end of if
} // end of for
newOut[oldOut.length]='l';
oldOut = newOut;
} // end of for
return oldOut;
}
public void startButton_ActionPerformed(ActionEvent evt) {
int iterations = iterationsNF.getInt();
int size = sizeNF.getInt();
char com[] = input(iterations);
outText.setText(String.valueOf(com));
int dir = 0;
int newDir = 0;
int lastPos[] = {xSlider.getValue(),ySlider.getValue()-size};
int newPos[] = {0,0};
Graphics g = display.getGraphics();
g.clearRect(0,0,601,601);
g.drawLine(xSlider.getValue(),ySlider.getValue(),xSlider.getValue(),ySlider.getValue()-size);
for (int i=0;i<=com.length-1;i++) {
dir = newDir;
if (dir==0) {
if (com[i]=='l') {
newPos[0] = lastPos[0]-size;
newPos[1] = lastPos[1];
newDir = 3;
}
if (com[i]=='r') {
newPos[0] = lastPos[0]+size;
newPos[1] = lastPos[1];
newDir = 1;
}
}
if (dir==1) {
if (com[i]=='l') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]-size;
newDir = 0;
}
if (com[i]=='r') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]+size;
newDir = 2;
}
}
if (dir==2) {
if (com[i]=='l') {
newPos[0] = lastPos[0]+size;
newPos[1] = lastPos[1];
newDir = 1;
}
if (com[i]=='r') {
newPos[0] = lastPos[0]-size;
newPos[1] = lastPos[1];
newDir = 3;
}
}
if (dir==3) {
if (com[i]=='l') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]+size;
newDir = 2;
}
if (com[i]=='r') {
newPos[0] = lastPos[0];
newPos[1] = lastPos[1]-size;
newDir = 0;
}
}
g.drawLine(lastPos[0],lastPos[1],newPos[0],newPos[1]);
lastPos=newPos;
} // end of for
} // end of startButton_ActionPerformed
// end methods
} // end of class CurveGen
Okay, so I've gone back over the code...
Mixing heavyweight (java.awt.Canvas) and lightweight (Swing) components is unadvisable as they can cause or sorts of painting issues
getGraphics is not how paint should be done. Instead, I'd start with a custom JPanel and override its paintComponent. See Painting in AWT and Swing and Performing Custom Painting for more details
Avoid using null layouts, pixel perfect layouts are an illusion within modern ui design. There are too many factors which affect the individual size of components, none of which you can control. Swing was designed to work with layout managers at the core, discarding these will lead to no end of issues and problems that you will spend more and more time trying to rectify
I believe the problem is associated with this...
lastPos=newPos;
All you are doing is making lastPos point to the same place in memory as newPos, so when you assign values to newPos, lastPos will have the same values, hence the reason you're seeing dots.
What I would do first, is separate the responsible for the generation of the data from the display.
I'd start with some kind of model (note, you could create a model which took iterations instead and which generated the data itself, but I was focusing on solving the initial problem)
public class DragonModel {
private Point startPoint;
private int size;
private char[] values;
public DragonModel(Point startPoint, int size, char[] values) {
this.startPoint = startPoint;
this.size = size;
this.values = values;
}
public Point getStartPoint() {
return startPoint;
}
public int getSize() {
return size;
}
public char[] getValues() {
return values;
}
}
and then the display...
public class DragonPane extends JPanel {
private DragonModel model;
public void setModel(DragonModel model) {
this.model = model;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (model != null) {
Graphics2D g2d = (Graphics2D) g.create();
int size = model.getSize();
int dir = 0;
int newDir = 0;
Point lastPos = model.getStartPoint();
Point newPos = new Point(0, 0);
for (char value : model.values) {
if (dir == 0) {
if (value == 'l') {
newPos.x = lastPos.x - size;
newPos.y = lastPos.y;
newDir = 3;
}
if (value == 'r') {
newPos.x = lastPos.x + size;
newPos.y = lastPos.y;
newDir = 1;
}
}
if (dir == 1) {
if (value == 'l') {
newPos.x = lastPos.x;
newPos.y = lastPos.y - size;
newDir = 0;
}
if (value == 'r') {
newPos.x = lastPos.x;
newPos.y = lastPos.y + size;
newDir = 2;
}
}
if (dir == 2) {
if (value == 'l') {
newPos.x = lastPos.x + size;
newPos.y = lastPos.y;
newDir = 1;
}
if (value == 'r') {
newPos.x = lastPos.x - size;
newPos.y = lastPos.y;
newDir = 3;
}
}
if (dir == 3) {
if (value == 'l') {
newPos.x = lastPos.x;
newPos.y = lastPos.y + size;
newDir = 2;
}
if (value == 'r') {
newPos.x = lastPos.x;
newPos.y = lastPos.y - size;
newDir = 0;
}
}
g.drawLine(lastPos.x, lastPos.y, newPos.x, newPos.y);
dir = newDir;
lastPos = new Point(newPos);
}
}
}
}
The idea here is to try and decouple of the responsibility a little, the responsibility for the generation and displaying of the data sit firmly in two different areas.
Then in your actionPerformed method you could simply do...
public void startButton_ActionPerformed(ActionEvent evt) {
int iterations = Integer.parseInt(iterationsNF.getText());
int size = Integer.parseInt(sizeNF.getText());
char com[] = input(iterations);
outText.setText(String.valueOf(com));
DragonModel model = new DragonModel(new Point(xSlider.getValue(), ySlider.getValue()), size, com);
display.setModel(model);
} // end of startButton_ActionPerformed
which could result in something like...
The drawing code should be inside the paint(Graphics) method to synchronize with the rendering loop properly. In an event handler, update the data model of the component (calculate the lines and keep them in a data structure inside the component), then call the method repaint() to trigger the event rendering loop, which will call your paint method.
There are some other variations of this, but the general idea is that you change the data and then request rendering. The rendering engine may call your paint method in other cases as well, not only when you change the data, so ideally paint() has all the data it needs to render fast, meaning it should not do calculations or heavy operations other than rendering on the Graphics object.
This means that you have to subclass JComponent in a new class, and implement paint inside it. This class should have an internal data structure with the lines ready to render at any point in time. Then use your new class in the JFrame.

Memory game does not call compare function correctly

I have coded a simple memory game. Card values are added to two arrays and after that, a compare function is called. But there is a problem with the logic of the compare function.
The specific problem seems related to the fact that the compare function is called on the third button click. So on first click it adds first value to first array , on second click second value to second array. But I must click for yet a third time to call the compare function to compare the match of two arrays.
The main problem is that after all cards are inverted (10 matches in 5x4 memory game), it does not show the result.
I have uploaded full code here : http://uloz.to/xcsJkYUK/memory-game-rar .
public class PEXESO5x4 extends JFrame implements ActionListener {
private JButton[] aHracieTlactika = new JButton[20];
private ArrayList<Integer> aHodnoty = new ArrayList<Integer>();
private int aPocitadlo = 1;
private int[] aTlacitkoIden = new int[2];
private int[] aHodnotaTlac = new int[2];
private JButton aTlacitkoExit;
private JButton aTlacitkoReplay;
private JButton[] aHracieTlacitko = new JButton[20];
private int aPocetTahov = 0;
public void vkladanieHodnot() {
for (int i = 0; i < 2; i++) {
for (int j = 1; j < (this.aHracieTlactika.length / 2) + 1; j++) {
this.aHodnoty.add(j);
}
}
Collections.shuffle(this.aHodnoty);
}
public boolean zhoda() {
if (this.aHodnotaTlac[0] == this.aHodnotaTlac[1]) {
return true;
}
return false;
}
public void zapisCislaDoSuboru() {
try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("Semestralka.txt", true)))) {
out.println("haha");
//more code
out.println("hahahahha");
//more code
}catch (IOException e) {
//exception handling left as an exercise for the reader
}
}
public void actionPerformed(ActionEvent e) {
int match = 0;
if (this.aTlacitkoExit == e.getSource()) {
System.exit(0);
}
if (this.aTlacitkoReplay == e.getSource()) {
}
for (int i = 0; i < this.aHracieTlactika.length; i++) {
if (this.aHracieTlactika[i] == e.getSource()) {
this.aHracieTlactika[i].setText("" + this.aHodnoty.get(i));
this.aHracieTlactika[i].setEnabled(false);
this.aPocitadlo++;
this.aPocetTahov += 1;
if (this.aPocitadlo == 3) {
if (this.zhoda()) {
match+=1;
if (match==10)
{
System.out.println("You win");
}
this.aHracieTlactika[this.aTlacitkoIden[0]].setEnabled(false);
this.aHracieTlactika[this.aTlacitkoIden[1]].setEnabled(false);
} else {
this.aHracieTlactika[this.aTlacitkoIden[0]].setEnabled(true);
this.aHracieTlactika[this.aTlacitkoIden[0]].setText("");
this.aHracieTlactika[this.aTlacitkoIden[1]].setEnabled(true);
this.aHracieTlactika[this.aTlacitkoIden[1]].setText("");
}
this.aPocitadlo = 1;
}
if (this.aPocitadlo == 1) {
this.aTlacitkoIden[0] = i;
this.aHodnotaTlac[0] = this.aHodnoty.get(i);
}
if (this.aPocitadlo == 2) {
this.aTlacitkoIden[1] = i;
this.aHodnotaTlac[1] = this.aHodnoty.get(i);
}
}
}
}
}

Making a calculator about letter grades

I am taking Maths and I want to make a calculator which tells me the each note I need to take in the final exam to get each letter grade. In the syllabus it tells us that our note is calculated by this:
MT1 - First midterm %26.6
MT2- Second midterm %26.6
F- Final % 26.6
Q - Quizzes % 10
HW- Homeworks % 10
These are the grade intervals:
A 80-100
A- 75-80
B+ 70-75
B 65-70
B- 60-65
C+ 55-60
C 50-55
C- 45-50
D+ 40-45
D+ 30-40
F 0-30
You enter MT1, MT2, Q, HW in the JTextFields and when you click the button it will update the jlabel's near the letter grades. When I run the code for the first time, it works but when I want to change it program doesn't update the numbers. Could you help?
Final_Calculator:
import javax.swing.*;
import java.awt.*;
public class Final_Calculator extends JFrame
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Final Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Results());
frame.pack();
frame.setVisible(true);
}
}
Grades:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Grades extends JPanel
{
private JLabel l1, l2, l3, l4;
private JTextField t1, t2, t3, t4;
private double sum,result, MT1, MT2, Q, HW;
private JButton button;
public Grades()
{
setPreferredSize(new Dimension(200,100));
l1 = new JLabel("MT1");
l2 = new JLabel("MT2");
l3 = new JLabel("Q");
l4 = new JLabel("HW");
t1 = new JTextField("100");
t2 = new JTextField("100");
t3 = new JTextField("100");
t4 = new JTextField("100");
button = new JButton("Click!");
TextListener listener = new TextListener();
button.addActionListener(listener);
add(l1);
add(l2);
add(l3);
add(l4);
add(t1);
add(t2);
add(t3);
add(t4);
add(button);
}
public double getMT1()
{
return Double.parseDouble(t1.getText());
}
public double getMT2()
{
return Double.parseDouble(t2.getText());
}
public double getQ()
{
return Double.parseDouble(t3.getText());
}
public double getHW()
{
return Double.parseDouble(t4.getText());
}
public void sum()
{
MT1 = getMT1();
MT2 = getMT2();
Q = getQ();
HW = getHW();
sum = (MT1 * 26.6) + (MT2 * 26.6) + (Q * 10) + (HW * 10);
}
public double getA()
{
sum();
result = (8000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getAminus()
{
sum();
result = (7500 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getBplus()
{
sum();
result = (7000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getB()
{
sum();
result = (6500 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getBminus()
{
sum();
result = (6000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getCplus()
{
sum();
result = (5500 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getC()
{
sum();
result = (5000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getCminus()
{
sum();
result = (4500 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getDplus()
{
sum();
result = (4000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
public double getD()
{
sum();
result = (3000 - sum) / 26.6;
if (result <= 0)
{
return 0;
}
return result;
}
private class TextListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
if(source == button)
{
MT1 = Double.parseDouble(t1.getText());
MT2 = Double.parseDouble(t2.getText());
Q = Double.parseDouble(t3.getText());
HW = Double.parseDouble(t4.getText());
sum();
getA();
getAminus();
getBplus();
getB();
getBminus();
getCplus();
getC();
getCminus();
getDplus();
getD();
}
}
}
}
Results:
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class Results extends JPanel
{
private JLabel f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,g1,g2,g3,g4,g5,g6,g7,g8,g9,g10,g11;
private JPanel panel1, panel2;
private Grades grades;
public Results()
{
grades = new Grades();
setPreferredSize(new Dimension(800,800));
setLayout(new BorderLayout());
panel1 = new JPanel();
panel1.setLayout(new GridLayout(11,2));
panel1.setPreferredSize(new Dimension(200,200));
panel2 = new JPanel();
panel2.setPreferredSize(new Dimension(400,400));
f1 = new JLabel("Final");
g1 = new JLabel("Grade");
f2 = new JLabel(Double.toString(grades.getA()));
g2 = new JLabel(" A");
f3 = new JLabel(Double.toString(grades.getAminus()));
g3 = new JLabel(" A-");
f4 = new JLabel(Double.toString(grades.getBplus()));
g4 = new JLabel(" B+");
f5 = new JLabel(Double.toString(grades.getB()));
g5 = new JLabel(" B");
f6 = new JLabel(Double.toString(grades.getBminus()));
g6 = new JLabel(" B-");
f7 = new JLabel(Double.toString(grades.getCplus()));
g7 = new JLabel(" C+");
f8 = new JLabel(Double.toString(grades.getC()));
g8 = new JLabel(" C");
f9 = new JLabel(Double.toString(grades.getCminus()));
g9 = new JLabel(" C-");
f10 = new JLabel(Double.toString(grades.getDplus()));
g10 = new JLabel(" D+");
f11 = new JLabel(Double.toString(grades.getD()));
g11 = new JLabel(" D");
panel1.add(f1);
panel1.add(g1);
panel1.add(f2);
panel1.add(g2);
panel1.add(f3);
panel1.add(g3);
panel1.add(f4);
panel1.add(g4);
panel1.add(f5);
panel1.add(g5);
panel1.add(f6);
panel1.add(g6);
panel1.add(f7);
panel1.add(g7);
panel1.add(f8);
panel1.add(g8);
panel1.add(f9);
panel1.add(g9);
panel1.add(f10);
panel1.add(g10);
panel1.add(f11);
panel1.add(g11);
panel2.add(grades);
add(panel2, BorderLayout.NORTH);
add(panel1, BorderLayout.CENTER);
}
}
From the looks of it/only working once, it looks like you are not updating the label after clicking the button.Label text have to updated via label.setText(""); just calling the method wont do anything.

Implementing ActionListener in the Following Code Inside

I'm having some trouble with my age calculating program on Java. It works fine when I preset the birth year, birth month and birth date values but when I try to have the user input their own birthdate into the text field and then try to work with those values, I just reach a dead-end. I tried asking on Yahoo Answers and the hint I got was "The return value of getActionCommand() is a string while the result is a JLabel. Can you compare them?" I'm not exactly sure what to do with that hint.
Here's what I have and the way I attempted to implement the whole "user input" idea. I'm pretty sure my coding is messy and inefficient, so bear with that please. I'd appreciate any help!
//Date: April 11, 2012
//Description: Calculates the age in terms of days depending on your birthdate.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class AgeCalculator extends Frame implements ActionListener {
JButton equal;
JTextField year, month, day;
JLabel result, first, second, third;
JFrame frame;
JPanel panel;
static int totaldaysalive;
static int daysaliveyr;
static int daysalivem;
static int birthyr;
static int birthm;
static int birthd;
static int currentyr = 2012;
public AgeCalculator(){
gui();
}
public void gui(){
frame = new JFrame ("Age Calculator");
panel = new JPanel(new GridBagLayout());
panel.setBackground(Color.LIGHT_GRAY);
GridBagConstraints x = new GridBagConstraints();
equal = new JButton ("Get Result");
x.insets = new Insets(3,0,3,0);
first = new JLabel("Year ");
x.gridx = 0;
x.gridx = 0;
panel.add(first, x);
year = new JTextField(10);
x.gridx = 5;
x.gridy = 0;
x.gridwidth = 3;
panel.add(year, x);
second = new JLabel ("Month ");
x.gridx = 0;
x.gridy = 1;
panel.add(second,x);
month = new JTextField(10);
x.gridx = 5;
x.gridy = 1;
x.gridwidth = 3;
panel.add(month,x);
third = new JLabel ("Day ");
x.gridx = 0;
x.gridy = 2;
panel.add(third,x);
day = new JTextField(10);
x.gridx = 5;
x.gridy = 2;
x.gridwidth = 3;
panel.add(day,x);
x.gridx = 6;
x.gridy = 3;
panel.add(equal,x);
result = new JLabel ("");
x.gridx = 5;
x.gridy = 5;
panel.add(result,x);
frame.add(panel);
frame.setVisible(true);
frame.setSize(350, 350);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Calc e = new Calc();
equal.addActionListener(e);
year.addActionListener(e);
month.addActionListener(e);
day.addActionListener(e);
}
class Calc implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
birthyr = Integer.parseInt(year.getText());
} catch (NumberFormatException a) {
result.setText("Illegal data for first field.");
result.setForeground(Color.red);
return;
}
try {
birthm = Integer.parseInt(month.getText());
} catch (NumberFormatException a) {
result.setText("Illegal data for second field.");
result.setForeground(Color.red);
return;
}
try {
birthd = Integer.parseInt(day.getText());
} catch (NumberFormatException a) {
result.setText("Illegal data for third field.");
result.setForeground(Color.red);
return;
}
if (e.getActionCommand().equals (equal)){
totaldaysalive = ageCalcYr() + ageCalcM() + birthd;
result.setText(Integer.toString(totaldaysalive));
}
}
public int ageCalcYr(){
for (int i = birthyr; i <= currentyr; i++){
if ((i % 4 == 0) && (!(i % 100 == 0) || (i % 400 == 0))){
daysaliveyr = daysaliveyr + 366;
}
else {
daysaliveyr = daysaliveyr + 365;
}
}
return daysaliveyr;
}
public int ageCalcM(){
if (birthm == 1){
daysalivem = daysalivem + 0;
}
else if (birthm == 2){
daysalivem = daysalivem + 30;
}
else if (birthm == 3){
daysalivem = daysalivem + 60;
}
else if (birthm == 4){
daysalivem = daysalivem + 90;
}
else if (birthm == 5){
daysalivem = daysalivem + 120;
}
else if (birthm == 6){
daysalivem = daysalivem + 150;
}
else if (birthm == 7){
daysalivem = daysalivem + 180;
}
else if (birthm == 8){
daysalivem = daysalivem + 210;
}
else if (birthm == 9){
daysalivem = daysalivem + 240;
}
else if (birthm == 10){
daysalivem = daysalivem + 270;
}
else if (birthm == 11){
daysalivem = daysalivem + 300;
}
else if (birthm == 12){
daysalivem = daysalivem + 330;
}
return daysalivem;
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
AgeCalculator gui = new AgeCalculator();
}
#Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
}
}
Fast healing:
if (e.getActionCommand ().equals ("Get Result")) { // equal)) {
totaldaysalive = ageCalcYr () + ageCalcM () + birthd;
result.setText (Integer.toString (totaldaysalive));
}
If you have some time, I can post you 20 improvements.
You extend Frame,
impl. ActionListener, but meanwhile AgeCalculator has a JFrame (which is better in a SwingContext than Frame, which is AWT) and has a seperate Actionlistener which is used.
Remove the declaration, and the the overriding method in the end.
public class AgeCalculator // extends Frame implements ActionListener
There follows a block of visual components and other attributes, the later ones are static - which prohibits using of 2 AgeCalculators on the same JVM. That's surely not a restriction by intent.
Don't make something static to shut up the compiler.
Make everything private, if you aren't sure you want to expose it.
Avoid Attributes where possible.
When will you ever retouch a Label?
JButton equal;
JTextField year, month, day;
JLabel result, ...
...
static int birthd;
static int currentyr = 2012;
Use simplified addition where appropriate:
daysaliveyr += 366;
To calc the days for month, pass the birthyr and the birthm as parameter:
int totaldaysalive = ageCalcYr (birthyr) + ageCalcM (birthm) + birthd;
result.setText (Integer.toString (totaldaysalive));
The livetime of the variable totaldaysalive can be reduced to 2 lines - a very small scope to search for an error, if there is any.
public int ageCalcM (int birthm) {
int daysalivem = 0;
if (birthm == 2) {
daysalivem += 30;
}
else if (birthm == 3) {
daysalivem += 60;
}
In the current state, ageCalcM is a provisorium. Else you could just say daysalivem = (birthm - 1) * 30;
Shorter code:
public int ageCalcM (int birthm) {
if (birthm == 2) {
return 30;
}
else if (birthm == 3) {
return 60;
}
However, such mass manipulation in stupid repetition can be solved with an simple array:
public int ageCalcM (int birthm) {
int[] mdays = {0, 30, 60, 90, ...};
return mdays [birthm];
}
In the main-Method you create an instance 'gui', which is never used. This is all you need:
public static void main (String [] args) {
new AgeCalculator ();
}
Gui, btw. is a bad name, if you already have a method of said name.
Since that method is never used, just move the whole thing into the ctor.
year/month/date don't need the ActionListener.
Other layouts are much better suited.
We need another calender reform to make your program work.
Input should not only be checked to be int, but valid month etc.
The actual date isn't used.
What is left?
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class AgeCalculator
{
JTextField year, month, day;
JLabel result;
public AgeCalculator () {
JFrame frame = new JFrame ("Age Calculator");
JPanel panel = new JPanel (new GridBagLayout ());
panel.setBackground (Color.LIGHT_GRAY);
GridBagConstraints x = new GridBagConstraints ();
JButton equal = new JButton ("Get Result");
x.insets = new Insets (3, 0, 3, 0);
JLabel first = new JLabel ("Year ");
// two times gridx = 0 here?
x.gridx = 0;
x.gridx = 0;
panel.add (first, x);
year = new JTextField (10);
x.gridx = 5;
x.gridy = 0;
x.gridwidth = 3;
panel.add (year, x);
JLabel second = new JLabel ("Month ");
x.gridx = 0;
x.gridy = 1;
panel.add (second, x);
month = new JTextField (10);
x.gridx = 5;
x.gridy = 1;
x.gridwidth = 3;
panel.add (month, x);
JLabel third = new JLabel ("Day ");
x.gridx = 0;
x.gridy = 2;
panel.add (third, x);
day = new JTextField (10);
x.gridx = 5;
x.gridy = 2;
x.gridwidth = 3;
panel.add (day, x);
x.gridx = 6;
x.gridy = 3;
panel.add (equal, x);
result = new JLabel ("");
x.gridx = 5;
x.gridy = 5;
panel.add (result, x);
frame.add (panel);
frame.setVisible (true);
frame.setSize (350, 350);
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
Calc e = new Calc ();
equal.addActionListener (e);
}
class Calc implements ActionListener {
public void actionPerformed (ActionEvent e) {
int birthyr;
int birthm;
int birthd;
try {
birthyr = Integer.parseInt (year.getText ());
} catch (NumberFormatException a) {
result.setText ("Illegal data for first field.");
result.setForeground (Color.red);
return;
}
try {
birthm = Integer.parseInt (month.getText ());
} catch (NumberFormatException a) {
result.setText ("Illegal data for second field.");
result.setForeground (Color.red);
return;
}
try {
birthd = Integer.parseInt (day.getText ());
} catch (NumberFormatException a) {
result.setText ("Illegal data for third field.");
result.setForeground (Color.red);
return;
}
if (e.getActionCommand ().equals ("Get Result")) { // equal)) {
int totaldaysalive = ageCalcYr (birthyr) + ageCalcM (birthm) + birthd;
result.setText (Integer.toString (totaldaysalive));
}
}
public int ageCalcYr (int birthyr) {
int currentyr = 2012;
int daysaliveyr = 0;
for (int i = birthyr; i <= currentyr; i++) {
if ((i % 4 == 0) && (! (i % 100 == 0) || (i % 400 == 0))) {
daysaliveyr += 366;
}
else {
daysaliveyr += 365;
}
}
return daysaliveyr;
}
public int ageCalcM (int birthm) {
int[] mdays = {0, 30, 60, 90, 120};
return mdays [birthm];
}
}
public static void main (String [] args) {
new AgeCalculator ();
}
}
Since you're using a button to kick off the calculation, only register an action listener on that button. Inside the action performed method read, parse and calculate the age in days.
I think you want to do equal.addMouseListener(e). Of course you'll have to change Calc to implement MouseListener. You'll probably only have to actually write the mouseClicked(MouseEvent) method. All of the others are for more specific things than what you're after.
That will respond to a click event on your button. I don't think you want any other listeners. If so, they should be KeyListeners or something other than ActionListeners.
On a side note, It's hard for me to see because your indentation is off, but I can't really tell why your int fields are static. I think that's probably unnecessary.

Categories