how do I make this run constructor work right? - java

I have the following code:
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class TTT extends JFrame implements ActionListener { //DO NOT TOUCH!!!
//makes the array for the buttons
JButton spots[ ] = new JButton[ 9];
//keeps track of who's turn it is
int turn = 0;
//lets it go again
boolean go = true;
//gets the images for the X's and O's
ImageIcon red = new ImageIcon("x.PNG");
ImageIcon blue = new ImageIcon("o.PNG");
ImageIcon blank = new ImageIcon("blank.PNG");
public static void main (String []args ) {
TTT frame = new TTT(); //DO NOT TOUCH!!!
frame.setVisible(true);
}
public TTT( ) { //DO NOT TOUCH!!!
//set the frame default properties
setTitle ("Tic Tac Toe");
setSize ( 308, 308 );
setLocationRelativeTo ( null );
setResizable(false);
//register 'Exit upon closing' as a default close operation
setDefaultCloseOperation( EXIT_ON_CLOSE );
changeBkColor( );
}
private void changeBkColor() {
while (go) {
//declares some variables that we will use later
int newLine = 0;
int lineCount = 0;
//change background color to white
Container contentPane = getContentPane();
contentPane.setBackground(Color.WHITE);
contentPane.setLayout(null);
//puts the buttons on the screen
for (int i = 0; i < spots.length; i++) {
//make it first appear as a blank image
spots[ i] = new JButton (blank);
//checks if it needs a new row
if (i == 3 || i == 6) {
newLine++;
lineCount = 0;
}
//sets the positions of the buttons
spots[ i].setBounds(lineCount*100, newLine*100, 100, 100);
//add it to the container
contentPane.add(spots[ i]);
spots[ i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/*** Line 62 ***/ public void run() {
//check button pressed
for (int i = 0; i < spots.length; i++) {
if(e.getSource()==spots[ i]) {
//check turn
if (turn%2==0) {
spots[ i].setIcon(red);
} else {
spots[ i].setIcon(blue);
}
//disable the button so it can't be re-pressed
spots[ i].removeActionListener(this);
}
}
turn++;
//checks for wins
for(int i = 0; i < 3; i++) {
if (spots[ i].getIcon()==red && //checks for verticle x win
spots[ i+3].getIcon()==red &&
spots[ i+6].getIcon()==red) {
int again1 = JOptionPane.showConfirmDialog(null, "X Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again1 == JOptionPane.YES_OPTION) {
go = true;
} if (again1 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}else if (spots[ i].getIcon()==blue && //checks for verticle o win
spots[ i+3].getIcon()==blue &&
spots[ i+6].getIcon()==blue) {
int again2 = JOptionPane.showConfirmDialog(null, "O Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again2 == JOptionPane.YES_OPTION) {
go = true;
} if (again2 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}else if (spots[ i*3].getIcon()==red && //checks for horizontal x win
spots[ (i*3)+1].getIcon()==red &&
spots[ (i*3)+2].getIcon()==red) {
int again3 = JOptionPane.showConfirmDialog(null, "X Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again3 == JOptionPane.YES_OPTION) {
go = true;
} if (again3 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}else if (spots[ i*3].getIcon()==blue && //checks for horizontal o win
spots[ (i*3)+1].getIcon()==blue &&
spots[ (i*3)+2].getIcon()==blue) {
int again4 = JOptionPane.showConfirmDialog(null, "O Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again4 == JOptionPane.YES_OPTION) {
go = true;
} if (again4 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}else if (spots[ i].getIcon()==red && //checks for diagnol x win
spots[ 4].getIcon()==red &&
spots[ 8-i].getIcon()==red) {
int again5 = JOptionPane.showConfirmDialog(null, "X Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again5 == JOptionPane.YES_OPTION) {
go = true;
} if (again5 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}else if (spots[ i].getIcon()==blue && //checks for diagnol o win
spots[ 4].getIcon()==blue &&
spots[ 8-i].getIcon()==blue) {
int again6 = JOptionPane.showConfirmDialog(null, "O Wins! Do you want to play again?", "Play again?", JOptionPane.YES_NO_OPTION);
if (again6 == JOptionPane.YES_OPTION) {
go = true;
} if (again6 == JOptionPane.NO_OPTION) {
JOptionPane.showMessageDialog(null, "Okay then. Bye!");
go = false;
}
}
}
lineCount++;
}
}
});
}
} if (!go) {
System.exit(0);
}
}
}
my compile hates line 62 - public void run() { - and I need help fixing it. I copied and pasted the line for an already-working program, so I don't know how it doesn't work.
EDIT
sorry guys, here's my errors:
TTT.java:62: error: illegal start of expression
public void run() {
^
TTT.java:62: error: illegal start of expression
public void run() {
^
TTT.java:62: error: ';' expected
public void run() {
^

It appears that you have defined a method within another method declaration, namely run() within actionPerformed(ActionEvent e).
This is not allowed in Java.
It also appears that you have a misunderstanding about the declaration of static void run() this is not a constructor; it is a method declaration with a return type of void.

changeBkColor is an infinite loop so after the constructor is called frame.setVisible(true) is never called. Might be an issue.

Related

How to switch between 2 colors in Java Jbuttons after every click

I have been making a color-based Tic Tac Toe game using Java Swing and Java AWT and have more or less finished the project, however there is still one problem that needs to be fixed in order to be a proper Tic Tac Toe game. The colors that are supposed to be used is Orange (X) and blue (O), however for some reason even when checking each turn iteration it refuses to switch colors after every click and at this point I am lost. Any help is appreciated
Board.java:
public class Board extends JPanel {
boolean gameRunning = true;
private final JButton[][] grid = new JButton[3][3];
JFrame board;
JPanel panel;
public Board() {
initBoard();
}
private void makePanel() {
panel = new JPanel();
panel.setBackground(Color.lightGray);
panel.setLayout(new GridLayout(3, 3));
setBoard();
board.add(panel);
}
private void initBoard() {
int BOARD_WIDTH = 800;
int BOARD_HEIGHT = 600;
board = new JFrame();
board.setTitle("JTicTacToe");
board.setSize(BOARD_WIDTH, BOARD_HEIGHT);
board.setResizable(false);
board.setLocationRelativeTo(null);
board.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
makePanel();
board.setVisible(true);
}
private void setBoard() {
//Loop through 2D array
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
grid[row][col] = new JButton();
grid[row][col].setOpaque(true);
grid[row][col].setBorderPainted(false);
grid[row][col].addActionListener(new ButtonListener());
panel.add(grid[row][col]);
}
}
validate();
}
protected class ButtonListener implements ActionListener {
Color defaultColor = new Color(238,238,238);
protected void check(int moves) {
//Rows
for (int c = 0; c < 3; c++) {
if (!defaultColor.equals(grid[c][0].getBackground()) && grid[c][0].getBackground() == grid[c][1].getBackground() && grid[c][0].getBackground() == grid[c][2].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
}
//Verticals
for (int c = 0; c < 3; c++) {
if (!defaultColor.equals(grid[0][c].getBackground()) && grid[0][c].getBackground() == grid[1][c].getBackground() && grid[0][c].getBackground() == grid[2][c].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
}
//Check diagonals
if (!defaultColor.equals(grid[0][0].getBackground()) && grid[0][0].getBackground() == grid[1][1].getBackground() && grid[0][0].getBackground() == grid[2][2].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");}
if (!defaultColor.equals(grid[0][2].getBackground()) && grid[0][2].getBackground() == grid[1][1].getBackground() && grid[0][2].getBackground() == grid[2][0].getBackground()) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Game Over!");
}
//Check draw if game goes to 9 moves
if(moves == 9) {
gameRunning = false;
JOptionPane.showMessageDialog(null, "Draw!");
}
}
#Override
public void actionPerformed(ActionEvent e) {
int turns = 0;
if (e.getSource() == grid[0][0]) {
turns++;
if (turns % 2 == 0) {
grid[0][0].setBackground(Color.orange);
check(turns);
} else {
grid[0][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[0][1]) {
turns++;
if (turns % 2 == 0) {
grid[0][1].setBackground(Color.orange);
check(turns);
} else {
grid[0][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[0][2]) {
turns++;
if (turns % 2 == 0) {
grid[0][2].setBackground(Color.orange);
check(turns);
} else {
grid[0][2].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][0]) {
turns++;
if (turns % 2 == 0) {
grid[1][0].setBackground(Color.orange);
check(turns);
} else {
grid[1][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][1]) {
turns++;
if (turns % 2 == 0) {
grid[1][1].setBackground(Color.orange);
check(turns);
} else {
grid[1][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[1][2]) {
turns++;
if (turns % 2 == 0) {
grid[1][2].setBackground(Color.orange);
check(turns);
} else {
grid[1][2].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][0]) {
turns++;
if (turns % 2 == 0) {
grid[2][0].setBackground(Color.orange);
check(turns);
} else {
grid[2][0].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][1]) {
turns++;
if (turns % 2 == 0) {
grid[2][1].setBackground(Color.orange);
check(turns);
} else {
grid[2][1].setBackground(Color.blue);
check(turns);
}
} else if (e.getSource() == grid[2][2]) {
turns++;
if (turns % 2 == 0) {
grid[2][2].setBackground(Color.orange);
check(turns);
} else {
grid[2][2].setBackground(Color.blue);
check(turns);
}
} else {
JOptionPane.showMessageDialog(null, "Invalid");
}
System.out.println(turns);
}
}
}
If you want to make the code prettier:
The variable gameRunning is set but it is never used. You can remove it and the program will still behave the same. Or you can start using it. But just giving it values without using those values is unnecessary work.
The variables at the top should be private (grid is private, but eg board is not)
You can use a loop to shorten the actionPerformed method (note that I added a return;):
#Override
public void actionPerformed(ActionEvent e) {
for (int col = 0; col < 3; col++) {
for (int row = 0; row < 3; row++) {
if (e.getSource() == grid[col][row]) {
turns++;
if (turns % 2 == 0) {
grid[col][row].setBackground(Color.orange);
check(turns);
} else {
grid[col][row].setBackground(Color.blue);
check(turns);
}
System.out.println(turns);
return;
}
}
}
JOptionPane.showMessageDialog(null, "Invalid");
}
You set the variable turns to 0 every time a button is clicked (ie every time actionPerformed is called). You need to make turns global (same as eg grid).

Why is the else part of my code not triggering the reset function of the game?

I want the tic tac toe game to reset and show Draw if it's tied
But this doesn't seem to work.
package com.codewithmischief.tictactoe;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import org.w3c.dom.Text;
public class MainActivity extends AppCompatActivity {
boolean gameActive = true;
int activePlayer = 0;
int[] gameState = {2,2,2,2,2,2,2,2,2};
int[][] winPosition={
{0,1,2},{3,4,5},{6,7,8},
{0,3,6},{1,4,7},{6,7,8},
{0,4,8},{6,4,2}
};
public void tapBtn(View view) {
ImageView img = (ImageView) view;
int tappedImg = Integer.parseInt(img.getTag().toString());
if(!gameActive){
gameReset(view);
}
if(gameState[tappedImg] == 2) {
gameState[tappedImg] = activePlayer;
if (activePlayer == 0) {
img.setImageResource(R.drawable.x);
activePlayer = 1;
TextView status = findViewById(R.id.status);
status.setText("O's Turn");
} else {
img.setImageResource(R.drawable.o);
activePlayer = 0;
TextView status = findViewById(R.id.status);
status.setText("X's Turn");
}
}
//check if someone has won
for(int[] winPos : winPosition){
if(gameState[winPos[0]]==gameState[winPos[1]]
&& gameState[winPos[1]]==gameState[winPos[2]]
&& gameState[winPos[0]]!=2)
{
String winner;
gameActive=false;
if(gameState[winPos[0]]==0){
winner = "X won";
}
else if(gameState[winPos[0]]==1){
winner = "O won";
}
else{
winner="draw"; //this one is not working also i want it to reset the game when draw.
}
TextView status=findViewById(R.id.status);
status.setText(winner);
}
}
}
public void gameReset(View view) {
gameActive = true;
activePlayer = 0;
for(int i=0; i<gameState.length;i++){
gameState[i]=2;
}
((ImageView)findViewById(R.id.imageView0)).setImageResource(0);
((ImageView)findViewById(R.id.imageView1)).setImageResource(0);
((ImageView)findViewById(R.id.imageView2)).setImageResource(0);
((ImageView)findViewById(R.id.imageView3)).setImageResource(0);
((ImageView)findViewById(R.id.imageView4)).setImageResource(0);
((ImageView)findViewById(R.id.imageView5)).setImageResource(0);
((ImageView)findViewById(R.id.imageView6)).setImageResource(0);
((ImageView)findViewById(R.id.imageView7)).setImageResource(0);
((ImageView)findViewById(R.id.imageView8)).setImageResource(0);
TextView status = findViewById(R.id.status);
status.setText("X's Turn");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Just inside the for loop, you check
if (gameState[winPos[0]] == gameState[winPos[1]]
&& gameState[winPos[1]] == gameState[winPos[2]]
&& gameState[winPos[0]] != 2)
This means that somebody must have won: there are three of the same value in a row, and the value is not an empty tile.
When you then have your inner if statement:
if (gameState[winPos[0]] == 0) {
winner = "X won";
} else if (gameState[winPos[0]] == 1) {
winner = "O won";
} els e{
winner="draw"; //this one is not working also i want it to reset the game when draw.
}
Either X has won, or O has won, but it cannot be a draw, because the outer if statement has already determined that somebody has won.
To check for a draw, you just need to have the code exit the for loop without having set a winner, and then check that none of the tiles are empty.
EDIT: as requested, adding my suggestion as two code fragments.
First, replace the for loop with the following code. Notice that I pulled the winner string out of the loop and I added a break to exit the loop as soon as a winner is found. Similarly, I pulled the part that fetches and sets the label's text value out of the loop, so that it is not called for every iteration.
String winner = null;
for (int[] winPos : winPosition) {
// Did somebody win?
if (gameState[winPos[0]] == gameState[winPos[1]]
&& gameState[winPos[1]] == gameState[winPos[2]]
&& gameState[winPos[0]] != 2) {
gameActive = false;
if (gameState[winPos[0]] == 0) {
winner = "X won";
} else if (gameState[winPos[0]] == 1) {
winner = "O won";
}
// We found the winner, so exit the loop
break;
}
}
// If there is no winner yet, it might be a draw
if (winner == null && boardIsFull(gameState)) {
winner = "draw";
}
// Only set the label text if there is a value to set
if (winner != null) {
TextView status = findViewById(R.id.status);
status.setText(winner);
}
You will then need an implementation of the boardIsFull method, which is relatively straightforward:
private boolean boardIsFull(int[] gameState) {
for (int i = 0; i < gameState.length; ++i) {
if (gameState[i] == 2) {
return false;
}
}
return true;
}
In your code:
for(int[] winPos : winPosition){
if(gameState[winPos[0]]==gameState[winPos[1]]
&& gameState[winPos[1]]==gameState[winPos[2]]
/* A */ && gameState[winPos[0]]!=2)
{
String winner;
gameActive=false;
if(gameState[winPos[0]]==0){
winner = "X won";
}
else if(gameState[winPos[0]]==1){
winner = "O won";
}
/* B */ else{
winner="draw"; //this one is not working also i want it to reset the game when draw.
}
TextView status=findViewById(R.id.status);
status.setText(winner);
}
Line A means that the following code is only executed when gameState[winPos[0]] is not 2.
Line B however can only be reached if gameState[winPos[0]] is equal to 2, which cannot be due to the condition on line A.

JFrame does not wait for JOptionPane to execute

I am working on a project in which I create a simple game of Ping Pong. If a player wins, I would like that a JOptionPane pop up asking if the user would like to play a new Game or stop playing. When I add the JOptionPane, the method does not wait for the user to select a button, but keeps going and keeps creating JOptionPanes until it returns a Stack Overflow Error. The code that controls it is
int rightMinLeft = Right_Player_Score.getNumber()-Left_Player_Score.getNumber();
boolean rightWon = Right_Player_Score.getNumber() > 20 && rightMinLeft > 1;
if(rightWon)
{
Object[] options = {"New Game", "Finish"};
int i = JOptionPane.showOptionDialog(null, "Right Player has won", "Game Over", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
if(i == 0)
{
reset();
}
else
{
GameOver = true;
}
}
else if(Left_Player_Score.getNumber() > 20 && Left_Player_Score.getNumber()-Right_Player_Score.getNumber()>1)
{
Object[] options = {"New Game", "Finish"};
int i = JOptionPane.showOptionDialog(null, "Right Player has won", "Game Over", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
if(i == 0)
{
reset();
}
else
{
GameOver = true;
}
}
Any suggestions?
Edit:
Here is the full method:
public void update(Graphics window)
{
paint(window);
}
public void paint(Graphics window)
{
try{
if(pause)
{
Right_Player_Score.draw("Right Player Score", window, 600, 20);
Left_Player_Score.draw("Left Player Score", window, 0, 20);
leftPaddle.draw(window);
rightPaddle.draw(window);
if(U.LELatch(keys[4]))
{
pause = false;
}
}
else
{
ball.moveAndDraw(window);
leftPaddle.draw(window);
Right_Player_Score.draw("Right Player Score", window, Color.WHITE, 600, 20);
Left_Player_Score.draw("Left Player Score", window, Color.WHITE, 0, 20);
int LeftPaddleBottom = leftPaddle.getY()+(leftPaddle.getHeight());
int RightPaddleBottom = rightPaddle.getY()+(rightPaddle.getHeight());
int LeftPaddleTop = leftPaddle.getY();
int RightPaddleTop = rightPaddle.getY();
boolean inRangeLeft = ball.getY() > LeftPaddleTop && ball.getY() < LeftPaddleBottom;
boolean inRangeRight = ball.getY() > RightPaddleTop && ball.getY() < RightPaddleBottom;
if(ball.getX()<=10)
{
ball.setXSpeed(-ball.getXSpeed());
Right_Player_Score.increment();
}
else if(ball.getX()>=790)
{
ball.setXSpeed(-ball.getXSpeed());
Left_Player_Score.increment();
}
else if((inRangeLeft && ball.getX()<=leftPaddle.getX()+leftPaddle.getWidth()))
{
ball.setXSpeed(-ball.getXSpeed());
numTimes ++;
}
else if(inRangeRight && ball.getX()>=rightPaddle.getX())
{
ball.setXSpeed(-ball.getXSpeed());
numTimes ++;
}
if(!(ball.getY()>=10 && ball.getY()<=450))
{
ball.setYSpeed(-ball.getYSpeed());
}
if(keys[0] == true)
{
leftPaddle.moveUpAndDraw(window);
}
else if(keys[1] == true)
{
leftPaddle.moveDownAndDraw(window);
}
else
{
leftPaddle.draw(window);
}
if(keys[2] == true)
{
rightPaddle.moveUpAndDraw(window);
}
else if(keys[3] == true)
{
rightPaddle.moveDownAndDraw(window);
}
else
{
rightPaddle.draw(window);
}
int rightMinLeft = Right_Player_Score.getNumber()-Left_Player_Score.getNumber();
boolean rightWon = Right_Player_Score.getNumber() > 20 && rightMinLeft > 1;
if(rightWon)
{
Object[] options = {"New Game", "Finish"};
int i = JOptionPane.showOptionDialog(frame, "Right Player has won", "Game Over", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
//window.setColor(Color.BLACK);
//window.drawString("Right Player has won",200,400);
//Thread.currentThread().sleep(2000);
//int i = 1;
if(i == 0)
{
reset();
}
else
{
GameOver = true;
}
}
else if(Left_Player_Score.getNumber() > 20 && Left_Player_Score.getNumber()-Right_Player_Score.getNumber()>1)
{
Object[] options = {"New Game", "Finish"};
int i = JOptionPane.showOptionDialog(frame, "Left Player has won", "Game Over", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]);
//window.setColor(Color.BLACK);
//window.drawString("Left Player has won",200,400);
//Thread.currentThread().sleep(2000);
//int i = 1;
if(i == 0)
{
reset();
}
else
{
GameOver = true;
}
}
Right_Player_Score.draw("Right Player Score", window, 600, 20);
Left_Player_Score.draw("Left Player Score", window, 0, 20);
if(numTimes == 10)
{
numTimes = 0;
if(ball.getXSpeed() == Math.abs(ball.getXSpeed()))
{
ball.setXSpeed(ball.getXSpeed() + 1);
}
else
{
ball.setXSpeed(ball.getXSpeed() - 1);
}
if(ball.getXSpeed()>MAXSPEED)
{
ball.setXSpeed(MAXSPEED);
}
}
pause = U.LELatch(keys[4]);
}
}
catch(Exception e)
{
}
}
This is used in "public class GUI_Controller extends Canvas implements KeyListener, Runnable"
Note: The commented portions are a stopgap way of getting the user to at least see something.
The behavior you are seeing is because you are overloading the paint(Graphics g) method.
From the paint(Graphics g) JavaDoc
This method is called when the contents of the component should be painted; such
as when the component is first being shown or is damaged and in need
of repair.
In your case, what is likely happening is the call to JOptionPane.showOptionDialog() results in a JDialog showing over your Canvas which triggers another call to paint(). That in turn causes another call to JOptionPane.showOptionDialog() triggering another a call to paint() and so on... This will continue until you get a StackOverflowError or OutOfMemoryError.
In practice, paint() gets called quite frequently so it should be very efficient. Typically only your custom drawing should be done in the paint() method.
Other logic should live in different methods. You should move the logic for your scoring and user interaction outside of the paint() method and leave just the drawing in place.
Edit: Without seeing more of the code I can't give you a specific recommendation of where to move the logic which is not directly concerned with painting. You might find it helpful to review the Java Swing tutorial section on Performing Custom Painting.
It might help to give the JOptionPane your current frame as the first parameter instead of null.

Splitting Written code into Two Classes (JAVA)

I'm writing a tic-tac-toe game for my Java, I really suck at this so far, but got it to work with the examples he gave us in class. The problem I'm having now is that I realized wants us to have at least TWO classes for this program. I have no idea what he means by that or how I convert the code I've already put together into "Two Classes". From the instructions it looks like he wants the board in one class and the game in another class.
Is there a way to split this up into two classes without totally re-writing the whole thing?
/* Standard applet template
*/
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import javax.swing.*;
public class TicTacToeGame implements ActionListener {
/*Instance Variables*/
private JFrame window = new JFrame("Tic-Tac-Toe Game");
private JButton btn1 = new JButton("");
private JButton btn2 = new JButton("");
private JButton btn3 = new JButton("");
private JButton btn4 = new JButton("");
private JButton btn5 = new JButton("");
private JButton btn6 = new JButton("");
private JButton btn7 = new JButton("");
private JButton btn8 = new JButton("");
private JButton btn9 = new JButton("");
private JLabel lblTitle = new JLabel("Tic Tac Toe Game");
private JLabel lblBlank = new JLabel(" ");
private String letter = "";
private int count = 0;
private boolean win = false;
public TicTacToeGame(){
/*Create Window*/
window.setSize(400,300);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLayout(new GridLayout(3,3));
/*Add Buttons To The Window*/
window.add(btn1);
window.add(btn2);
window.add(btn3);
window.add(btn4);
window.add(btn5);
window.add(btn6);
window.add(btn7);
window.add(btn8);
window.add(btn9);
/*Add The Action Listener To The Buttons*/
btn1.addActionListener(this);
btn2.addActionListener(this);
btn3.addActionListener(this);
btn4.addActionListener(this);
btn5.addActionListener(this);
btn6.addActionListener(this);
btn7.addActionListener(this);
btn8.addActionListener(this);
btn9.addActionListener(this);
/*Make The Window Visible*/
window.setVisible(true);
}
public void actionPerformed(ActionEvent a) {
count++;
/*Calculate Who's Turn It Is*/
if(count == 1 || count == 3 || count == 5 || count == 7 || count == 9){
letter = "<HTML><font color=blue>X</font></HTML>";
} else if(count == 2 || count == 4 || count == 6 || count == 8 || count == 10){
letter = "<HTML><font color=red>O</font></HTML>";
}
/*Display X's or O's on the buttons*/
if(a.getSource() == btn1){
btn1.setText(letter);
btn1.setEnabled(false);
} else if(a.getSource() == btn2){
btn2.setText(letter);
btn2.setEnabled(false);
} else if(a.getSource() == btn3){
btn3.setText(letter);
btn3.setEnabled(false);
} else if(a.getSource() == btn4){
btn4.setText(letter);
btn4.setEnabled(false);
} else if(a.getSource() == btn5){
btn5.setText(letter);
btn5.setEnabled(false);
} else if(a.getSource() == btn6){
btn6.setText(letter);
btn6.setEnabled(false);
} else if(a.getSource() == btn7){
btn7.setText(letter);
btn7.setEnabled(false);
} else if(a.getSource() == btn8){
btn8.setText(letter);
btn8.setEnabled(false);
} else if(a.getSource() == btn9){
btn9.setText(letter);
btn9.setEnabled(false);
}
/*Checks to See Who Won*/
//horizontal win
if( btn1.getText() == btn2.getText() && btn2.getText() == btn3.getText() && btn1.getText() != ""){
win = true;
}
else if(btn4.getText() == btn5.getText() && btn5.getText() == btn6.getText() && btn4.getText() != ""){
win = true;
}
else if(btn7.getText() == btn8.getText() && btn8.getText() == btn9.getText() && btn7.getText() != ""){
win = true;
}
//virticle win
else if(btn1.getText() == btn4.getText() && btn4.getText() == btn7.getText() && btn1.getText() != ""){
win = true;
}
else if(btn2.getText() == btn5.getText() && btn5.getText() == btn8.getText() && btn2.getText() != ""){
win = true;
}
else if(btn3.getText() == btn6.getText() && btn6.getText() == btn9.getText() && btn3.getText() != ""){
win = true;
}
//diagonal wins
else if(btn1.getText() == btn5.getText() && btn5.getText() == btn9.getText() && btn1.getText() != ""){
win = true;
}
else if(btn3.getText() == btn5.getText() && btn5.getText() == btn7.getText() && btn3.getText() != ""){
win = true;
}
else {
win = false;
}
/*Show a dialog if someone wins or the game is tie*/
if(win == true){
JOptionPane.showMessageDialog(null, letter + " WINS!");
} else if(count == 9 && win == false){
JOptionPane.showMessageDialog(null, "Tie Game!");
}
}
public static void main(String[] args){
new TicTacToeGame();
}
}
There are multiple ways to split this class, but since it's not very big, most of them would end up rewriting much of it.
The cleanest way would be to split logic and UI into (at least) two separate classes:
Class TicTacToeGame would implement the logic: it has a method to query who's turn it is, some methods to query the state of the playing field, a method to enter the next move, a method to query the state of the game (playing, end), a method to query who has won and probably a way to register some listeners
Class TicTacToeUI just takes the information of an instance of the other class and displays it. It also calls the appropriate methods when one button is clicked.
The net effect will probably be more code (since the interaction between the two classes will need some code), but the code will be much cleaner and the game class can be tested independently of the UI.
Simple thing you can do is Make second class that implements ActionListener and then use that class to listen to all action events in your program. This is not the way you want that is one for board and one for game but this can be one for operation and one for presentation.
Joachim gave a nice answer. I just want to add that instead of doing this:
/*Display X's or O's on the buttons*/
if(a.getSource() == btn1){
btn1.setText(letter);
btn1.setEnabled(false);
...
} else if(a.getSource() == btn9){
btn9.setText(letter);
btn9.setEnabled(false);
}
You can do this:
JButton btn = (JButton) a.getSource();
btn.setText(letter);
btn.setEnabled(false);
I think your comments are a good hint as to logical splits. Put each section into a separate method so that your actionPerformed method would be something like the following.
public void actionPerformed(ActionEvent a) {
count++;
letter = calculateCurrentPlayer(count);
displayLetterOnButton(a.getSource());
win = checkForWin();
displayGameOver(win, count);
}
Each of the methods called from actionPerformed would then have a small tightly-defined unit of work to perform. These methods could pretty much be copy-and-paste from the sections of your current actionsPerformed method.

Knight's Tour recursive algorithm

Okay everybody, I know the knight's tour problem is popular for all cs students and I am having trouble getting mine to work. I use this recursive algorithm to progress through the moves, however, once I get to around move 50 I have to backtrack since no moves are available and I end up never completing the tour. I pass a ChessNode (holds things like if node has been visited, move it was visited, etc...), next row, next column, and previous node's move count.
private int moveRecur(ChessNode current, int row, int column, int moveV){
current.moveVisited = moveV+1;
if(current.moveVisited > 63){
return 0;
}
if(current.position==13 && aboard[row-1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column+2], row-1, column+2, current.moveVisited);
}
else if(current.position==22 && aboard[row-2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column+1], row-2, column+1, current.moveVisited);
}
else if(current.position == 50 && aboard[row+1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column-2], row+1, column-2, current.moveVisited);
}
else if(current.position == 41 && aboard[row+2][column-1].visited != 1){
current.visited =1;
moveRecur(aboard[row+2][column-1], row+2, column-1, current.moveVisited);
}
else if(current.position == 46 && aboard[row+2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column+1], row+2, column+1, current.moveVisited);
}
else if(current.position == 53 && aboard[row+1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column+2], row+1, column+2, current.moveVisited);
}
else if(current.position == 10 && aboard[row-1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column-2], row-1, column-2, current.moveVisited);
}
else if (current.position == 17 && aboard[row-2][column-1].visited != 1){
current.visited =1;
moveRecur(aboard[row-2][column-1], row-2, column-2, current.moveVisited);
}
if(row+1>=0 && row+1<8 && column+2>=0 && column+2<8){
if(aboard[row+1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column+2], row+1, column+2, current.moveVisited);
}
}
if(row+2>=0 && row+2<8 && column+1>=0 && column+1<8){
if(aboard[row+2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column+1], row+2, column+1, current.moveVisited);
}
}
if(row-1>=0 && row-1<8 && column-2>=0 && column-2<8){
if(aboard[row-1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column-2], row-1, column-2, current.moveVisited);
}
}
if(row-2>=0 && row-2<8 && column-1>=0 && column-1<8){
if(aboard[row-2][column-1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column-1], row-2, column-1, current.moveVisited);
}
}
if(row+1>=0 && row+1<8 && column-2>=0 && column-2<8){
if(aboard[row+1][column-2].visited != 1){
current.visited = 1;
moveRecur(aboard[row+1][column-2], row+1, column-2, current.moveVisited);
}
}
if(row+2>=0 && row+2<8 && column-1>=0 && column-1<8){
if(aboard[row+2][column-1].visited != 1){
current.visited = 1;
moveRecur(aboard[row+2][column-1], row+2, column-1, current.moveVisited);
}
}
if(row-1>=0 && row-1<8 && column+2>=0 && column+2<8){
if(aboard[row-1][column+2].visited != 1){
current.visited = 1;
moveRecur(aboard[row-1][column+2], row-1, column+2, current.moveVisited);
}
}
if(row-2>=0 && row-2<8 && column+1>=0 && column+1<8){
if(aboard[row-2][column+1].visited != 1){
current.visited = 1;
moveRecur(aboard[row-2][column+1], row-2, column+1, current.moveVisited);
}
}
//System.out.println(current.position + " "+current.moveVisited);
current.visited = 0;
return 0;
}
So, initially I check for the spots that can move to the corner board positions, and then I just make recursive calls based on available moves. So I guess my main question is am I doing something wrong? or is there another condition I can used to make the tour a little more intuitive?
Thanks in advance!
This is the Knight's tour code in java and has a brilliant layout. I did this using backtracking using recursion. This was my class assignment. Do contact me if you have any problem understanding or running this code.
package knights.tour;
import java.awt.*;
import java.awt.event.*;
import java.util.logging.*;
import javax.swing.*;
public class KnightsTour extends JFrame implements ActionListener{
//All the static variables used between action listeners and functions.
public static String path;
public static int btnPressed = 0;
public static int rowSelected;
public static String[] pathArray;
public static int[][] coordinatesArray;
public static int columnSelected;
public static int flag =0;
public static int increment = 0;
public static JPanel panel1 = new JPanel();
public static JPanel panel3 ;
public static JButton btnStart = new JButton("Start Animation");
public static JButton btnClear = new JButton("Clear");
public static JTextArea lblPath = new JTextArea();
public static JLabel lblStartRow = new JLabel();
public static JLabel lblStartColumn = new JLabel();
public static JButton[][] button;
public static int variableForIncrement=0;
static int row ;
static int column ;
static int[][] array = new int[row][column];
public static int count = 1;
KnightsTour(){
//Setting layout of the frame in the constructor and adding buttons to the panel and the frame.
getContentPane().setLayout(new GridLayout(2,1));
lblPath.setLineWrap(true);
lblPath.setColumns(10);
lblPath.setSize(700, 100);
lblPath.setEditable(false);
panel1.add(btnStart);
panel1.add(btnClear);
panel1.add(lblStartRow);
panel1.add(lblStartColumn);
panel1.add(lblPath);
panel3 = new JPanel(new GridLayout(row,column));
// Initializing Array of buttons for the user to click on the chess board.
button= new JButton[row][column];
array = new int[row][column];
coordinatesArray = new int[row*column][2]; // This array stores the coordinates as the Knight
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
button[i][j] = new JButton();
}
}
//Setting background of the buttons to black and white for chessboard layout.
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
if(i%2 ==j%2){
button[i][j].setBackground(Color.BLACK);
button[i][j].setForeground(Color.WHITE);
}
else{
button[i][j].setBackground(Color.WHITE);
}
panel3.add(button[i][j]);
button[i][j].addActionListener(this);
}
}
btnClear.addActionListener(this);
btnStart.addActionListener(this);
add(panel3);
add(panel1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// TODO code application logic here
String input =JOptionPane.showInputDialog("Enter the rows and columns in the format (row,column)");
String[] ar = input.split(",");
row = Integer.parseInt(ar[0]); // Finding out row and column from the user input.
column = Integer.parseInt(ar[1]);
pathArray = new String[row*column]; // This array is kept to store the path of the knight.
JFrame frame = new KnightsTour();
frame.setVisible(true);
frame.setSize(700,700);
}
//All the computation takes place in this function. It checks the neighbour and recursively calls itself.
public static void neighbourRecursion(int a,int b){
pathArray[increment] = Integer.toString(a) + "," + Integer.toString(b); // Storing the path of the Knight
increment++;
array[a][b] = count; //Stroing value of count.
button[a][b].setText(String.valueOf(count));
coordinatesArray[variableForIncrement][0] = button[a][b].getX(); //Finding coordinates of buttons to show animation
coordinatesArray[variableForIncrement][1] = button[a][b].getY();
count++;
variableForIncrement++;
//Checking for valid neighbours and calling itself recursively.
if(a <= row-3 && b<=column-2){
if(alreadyVisited(a+2,b+1)){
neighbourRecursion(a+2,b+1);
}
}
if(a<=row-3 && b>=1){
if(alreadyVisited(a+2,b-1)){
neighbourRecursion(a+2,b-1);
}
}
if(a>=2 && b<=column-2){
if(alreadyVisited(a-2,b+1)){
neighbourRecursion(a-2,b+1);
}
}
if(a>=2 && b>=1){
if(alreadyVisited(a-2,b-1)){
neighbourRecursion(a-2,b-1);
}
}
if(a<=row-2 && b>=2){
if(alreadyVisited(a+1,b-2)){
neighbourRecursion(a+1,b-2);
}
}
if(a<=row-2 && b<=column-3){
if(alreadyVisited(a+1,b+2)){
neighbourRecursion(a+1,b+2);
}
}
if(a>=1 && b>=2){
if(alreadyVisited(a-1,b-2)){
neighbourRecursion(a-1,b-2);
}
}
if(a>=1 && b <=column-3){
if(alreadyVisited(a-1,b+2)){
neighbourRecursion(a-1,b+2);
}
}
//Breaking condition of the function.
if(count == (row*column)+1){
}
// Backtracking condition if there is no neighbour.
else{
button[a][b].setText("");
array[a][b]=0;
count--;
variableForIncrement--;
if(increment >0){
increment--;
}
return ;
}
}
//This function checks if the neighbour is already visited.
public static boolean alreadyVisited(int a,int b){
if(array[a][b] != 0){
return false;
}
else{
return true;
}
}
#Override
public void actionPerformed(ActionEvent e) {
//when clear is pressed all arrays and global variables are set to initial conditon.
if(e.getSource() == btnClear){
for(int i =0;i<row;i++){
for(int j=0;j<column;j++){
array[i][j] = 0;
button[i][j].setText("");
count = 1;
lblPath.setText("");
lblStartRow.setText("");
lblStartColumn.setText("");
flag =0;
variableForIncrement=0;
increment =0;
path =" ";
}
}
}
//If start animation button is pressed animation is started.
else if(e.getSource() == btnStart){
animate();
}
// When the button is pressed.
else{
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
if(e.getSource() == button[i][j]){
if(flag == 1){
lblPath.setText(" Please press clear before clicking again"); // Button pressed twice without reset.
}
else{
rowSelected = i;
columnSelected =j;
// If odd * odd board and selected postion is odd then No path is possible.
if(row%2 ==1 && column%2 == 1 && rowSelected%2 ==0 && columnSelected%2 == 1 || row%2 ==1 && column%2 == 1 && rowSelected%2 ==1 && columnSelected%2 == 0){
lblPath.setText(" Path not possible from this point");
}
else{
int count;
lblStartRow.setText("Starting Row : "+String.valueOf(rowSelected + 1));
lblStartColumn.setText("Starting Column : "+String.valueOf(columnSelected + 1));
count = 1;
flag = 1;
startTour(); //Start tour function called.
for(int q=0;q<row;q++){
for(int w=0;w<column;w++){
if(array[i][j] == 0){
count++;
}
}
}
if(count > 2){
lblPath.setText(" No Path found");
}
//Printing path of the knight here.
else{
for(int k=0;k<pathArray.length;k++){
path = path+"->"+ pathArray[k];
}
lblPath.setText(" Path : \n"+ path.substring(5));
}
btnPressed = 1;
break;
}
}
}
}
}
} }
//Function for the animation.
void animate(){
if(btnPressed == 1){
btnPressed =0;
Graphics g = getGraphics();
for(int i=0;i<(row*column)-1;i++){
try {
Thread.sleep(600); // this function slows down drawing of lines.
} catch (InterruptedException ex) {
}
g.setColor(Color.RED); // setting colour or line to red.
g.drawLine((coordinatesArray[i][0]+65),(coordinatesArray[i][1]+50),(coordinatesArray[i+1] [0]+65),(coordinatesArray[i+1][1]+50));
}
}
else{
lblPath.setText(" Please clear, select a button to see the animation again"); //Animate button pressed twice without clear.
}
}
//This function calls the neighbour function with the selected row and column by the user.
static void startTour(){
neighbourRecursion(rowSelected,columnSelected);
for(int i=0;i<row;i++){
for(int j=0;j<column;j++){
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
}
I have an implementation of this program in C#. You can find it here:
http://github.com/danieltian/KnightBoard
It will only find the first solution though. I'm not saying to copy it, but you can take a look at it and see if it helps.

Categories

Resources