I have written Tic-Tac-Toe in Java. The issue I seem to be having is when there is a tie between the (human)player 1 and the (computer) player 2, the GUI freezes. I have created a tieCheck in both the "Buttonlistener" Class and the "Methods" to catch a tie.
The way my program works is that when a button is pressed, it passes a value to the array in the methods class. in this array, 1 = player 1, and 2 = player 2.
The human player always goes first, so when the human player has gone 4 times, I check for a tie before the last turn is taken with tieCheck(turncount); this method then utilizes the tieCheck() in the methods class which will place a 1 in the last place and then checks for a winner. if no winner is found, it returns true. then the tieCheck() from the ButtonListener class will disable all the buttons, and say "it is a tie". However, none of this is working. The program will still allow me to make the last move and will result in a frozen window I have to close using task manager. please help!
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class MediumPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JButton playAgain;
private JButton[] buttons = new JButton[9];
private JLabel label, turn;
public MediumPanel() {
ButtonListener listener = new ButtonListener();
Font f1 = new Font("Arial", Font.BOLD , 100);
Font f2 = new Font("Arial", Font.PLAIN, 50);
JPanel ButtonPanel = new JPanel();
ButtonPanel.setLayout(new GridLayout(3, 3));
for (int i = 0; i <= 8; i++) {
buttons[i] = new JButton("");
buttons[i].addActionListener(listener);
buttons[i].setBackground(Color.white);
buttons[i].setFont(f1);
ButtonPanel.add(buttons[i]);
}
playAgain = new JButton();
label = new JLabel();
label.setFont(f2);
turn = new JLabel("");
turn.setFont(f1);
playAgain.addActionListener(listener);
playAgain.setText("Click to Play Again");
playAgain.setFont(f2);
setBackground(Color.green);
setLayout(new BorderLayout());
setPreferredSize(new Dimension(500, 500));
add(playAgain, BorderLayout.SOUTH);
add(label, BorderLayout.NORTH);
add(ButtonPanel);
}
private class ButtonListener implements ActionListener {
Methods method = new Methods();
public void reset() {
label.setText("");
for (int i = 0; i <= 8; i++) {
buttons[i].setEnabled(true);
buttons[i].setText("");
}
method.reset();
}
// inserts
public void insertG(int num) {
for (int i = 0; i <= 8; i++) {
if (num == i) {
buttons[i].setText("O");
buttons[i].setEnabled(false);
}
}
}
public void disable() {
for(int i=0; i<=8; i++) {
buttons[i].setEnabled(false);
}
}
// Checks array using tieCheck from Methods class for a tie
public void tieCheck(int turncount) {
if (turncount == 4 && method.tieCheck() == true) {
disable();
label.setText("It's a tie!");
}
}
// Checks for buttons being pressed
public void actionPerformed(ActionEvent event) {
int turncount = 0;
//Resets array board, GUI buttons, and label when clicked
if (event.getSource() == playAgain) {
reset();
}
// Button 0
if (event.getSource() == buttons[0]) {
buttons[0].setText("X");
buttons[0].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(0, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 1
if (event.getSource() == buttons[1]) {
buttons[1].setText("X");
buttons[1].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(1, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 2
if (event.getSource() == buttons[2]) {
buttons[2].setText("X");
buttons[2].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(2, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 3
if (event.getSource() == buttons[3]) {
buttons[3].setText("X");
buttons[3].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(3, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 4
if (event.getSource() == buttons[4]) {
buttons[4].setText("X");
buttons[4].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(4, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 5
if (event.getSource() == buttons[5]) {
buttons[5].setText("X");
buttons[5].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(5, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
//Button 6
if (event.getSource() == buttons[6]) {
buttons[6].setText("X");
buttons[6].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(6, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// Button 7
if (event.getSource() == buttons[7]) {
buttons[7].setText("X");
buttons[7].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(7, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
//Button 8
if (event.getSource() == buttons[8]) {
buttons[8].setText("X");
buttons[8].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(8, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else {
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
}
}
}
import java.util.*;
public class Methods {
Random rand = new Random();
Scanner scan = new Scanner(System.in);
// represents Tick-Tack-Toe Play Field
int[] board = new int[9];
// resets board array
public void reset() {
for (int i = 0; i < 9; i++) {
board[i] = 0;
}
}
// inserts player on a specific spot
public void insertArray(int spot, int player) {
board[spot] = player;
}
// for hard mode
public void expertMove(int player1, int player2) {
}
// for medium
public int smartMove(int player1, int player2) {
boolean turntaken = false;
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player2;
if (winCheck(player2) == 1) {
return i;
} else {
board[i] = 0;
}
}
}
for (int i = 0; i < 9; i++) {
if (board[i] == 0) {
board[i] = player1;
if (winCheck(player1) != 1) {
board[i] = 0;
} else {
board[i] = player2;
return i;
}
}
}
// If the opposite player is not about to win, then Computer goes randomly
if (turntaken == false) {
return randomMove(player2);
}
return 0;
}
// For easy mode and also utilized in smartMove() for medium mode
public int randomMove(int player) {
int rnum = 0;
rnum = rand.nextInt(8);
while (emptyCheck(rnum) != true) {
rnum = rand.nextInt(8);
}
board[rnum] = player;
return rnum;
}
//Returns 1 if player won the game
public int winCheck(int player) {
for (int ii = 0; ii <= 2; ii++) {
if (board[ii] == player && board[ii + 3] == player && board[ii + 6] == player)
return 1;
}
for (int z = 0; z <= 6; z = z + 3) {
if (board[z] == player && board[z + 1] == player && board[z + 2] == player)
return 1;
}
if (board[0] == player && board[4] == player && board[8] == player) {
return 1;
}
if (board[2] == player && board[4] == player && board[6] == player) {
return 1;
}
return 0;
}
//Returns true if tie
public boolean tieCheck() {
for(int i=0;i < 9; i++) {
if(board[i] == 0) {
board[i] = 2;
if(winCheck(1) != 1 && winCheck(2) != 1) {
return true;
}else {
board[i] = 0;
}
}
}
return false;
}
// Checks if empty: True if empty/false if taken by player
public boolean emptyCheck(int rnum) {
if (board[rnum] == 0) {
return true;
} else {
return false;
}
}
}
import java.awt.Font;
import javax.swing.JFrame;
import javax.swing.JTabbedPane;
public class Driver {
public static void main(String []args) {
JTabbedPane difficulty = new JTabbedPane();
//difficulty.addTab("Easy", new EasyPanel());
difficulty.addTab("Medium", new MediumPanel());
//difficulty.addTab("Hard", new HardPanel());
Font f = new Font("Arial", Font.PLAIN, 20);
difficulty.setFont(f);
JFrame frame = new JFrame("Tic-Tac-Toe");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(difficulty);
frame.pack();
frame.setVisible(true);
}
On every click, you set turncount = 0:
// Checks for buttons being pressed
public void actionPerformed(ActionEvent event) {
int turncount = 0;
but in your method tieCheck:
// Checks array using tieCheck from Methods class for a tie
public void tieCheck(int turncount) {
if (turncount == 4 && method.tieCheck() == true) {
disable();
label.setText("It's a tie!");
}
}
you check if turncount == 4but it is always 1. You should change the turncount variable from local to global.
And then in method randomMove, you have an endless loop:
// For easy mode and also utilized in smartMove() for medium mode
public int randomMove(int player) {
int rnum = 0;
rnum = rand.nextInt(8);
while (emptyCheck(rnum) != true) { // <--------- HERE
rnum = rand.nextInt(8);
}
Like Peter1982 said in his answer, you should make turncount a class variable instead of a method variable so that it doesn't get reset every time you call the actionPerformed method.
To stop the game from getting frozen, you can create a boolean class variable that keeps track of if the game is over, such as gameOver. You then update gameOver in the tieCheck method, for example:
private class ButtonListener implements ActionListener {
boolean gameOver = false;
// ...
// Checks array using tieCheck from Methods class for a tie
public void tieCheck(int turncount) {
if (turncount == 4 && method.tieCheck() == true) {
gameOver = true; // <---- Update gameOver
disable();
label.setText("It's a tie!");
}
}
// Button 0
if (event.getSource() == buttons[0]) {
buttons[0].setText("X");
buttons[0].setEnabled(false);
turncount++;
tieCheck(turncount);
method.insertArray(0, 1);
if (method.winCheck(1) == 1) {
label.setText("You Won!");
disable();
} else if (!gameOver) { // <---- Check if the game is over
insertG(method.smartMove(1, 2));
if (method.winCheck(2) == 1) {
label.setText("You Lost!");
disable();
}
}
}
// ...
}
Make sure to reset turncount and tieCheck in your reset method.
Also, as an extra note, when I was looking through your code, I noticed that in your randomMove method you have the following: rnum = rand.nextInt(8);. Currently, this won't allow the computer to make a random move on the 9th button because rand.nextInt(8) will return a value of 0 through 7. This is because the 8 is exclusive. So just put 9 as the parameter like this: rand.nextInt(9) to get 0 through 8. I know it is trivial but I just wanted to point it out.
Related
I've wrote a program to play TicTacToe.
Here's the class, which contains the method, which checks, whether a player won:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class TicTacToe {
public static int count = 0;
public static String[][] board = new String[3][3];
public static void buttonClicked(JButton button) {
if(button.getText().equals("")) {
count++;
if(count % 2 == 1) {
button.setText("X");
}
if(count % 2 == 0) {
button.setText("O");
}
}
}
public static void gameRules(JButton button) {
//"X" or "O"?
String string = button.getText();
//Gives coordinates of the button
int x = Character.getNumericValue(button.getName().charAt(0));
int y = Character.getNumericValue(button.getName().charAt(1));
board[x][y] = string;
//diagonal
if(board[0][0].equals(board[1][1]) && board[1][1].equals(board[2][2])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
//other diagonal
else if(board[0][2].equals(board[1][1]) && board[1][1].equals(board[2][0])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
//draw?
else if(count==9) {
JOptionPane.showMessageDialog(null,"draw.");
}
else {
//row
for(int i = 0; i < 3; i++) {
if(board[i][0].equals(board[i][1]) && board[i][1].equals(board[i][2])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
}
//column
for(int j = 0; j < 3; j++) {
if(board[0][j].equals(board[1][j]) && board[1][j].equals(board[2][j])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
}
}
}
}
Here are the other two classes, so now you have the full code:
public class Control {
public static void main(String args[]) {
Gui gui = new Gui();
TicTacToe ticTacToe = new TicTacToe();
}
}
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Gui {
public Gui() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.setLayout(new java.awt.GridLayout(3, 3));
for (int i = 0; i < 3; i++){
for(int j = 0; j < 3; j++) {
final JButton button = new JButton();
String string = i + "" + j;
button.setText("");
button.setName(string);
button.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent e) {
TicTacToe.buttonClicked(button);
TicTacToe.gameRules(button);
}
});
button.setBorder(BorderFactory.createLineBorder(Color.BLACK));
panel.add(button);
}
}
frame.add(panel);
frame.setSize(400,400);
frame.setVisible(true);
}
}
My problem is that the program now recognizes when someone wins on a diagonal, but not on rows and columns.
I would appreciate any help to solve the problem.
You only need to import import javax.swing.*; for the TicTacToe.java.
Edit the win if statements and delete the static definitions:
if(board[0][0] != null && board[0][0].equals(board[1][1]) && board[1][1].equals(board[2][2])) {
JOptionPane.showMessageDialog(null,string + " won.");
} else if(board[0][2] != null && board[0][2].equals(board[1][1]) && board[1][1].equals(board[2][0])) {
JOptionPane.showMessageDialog(null,string + " won.");
} else if(count == 9) {
JOptionPane.showMessageDialog(null, "draw.");
} else {
for (int i = 0; i < 3; i++) {
if (board[i][0] != null && board[i][0].equals(board[i][1]) && board[i][0].equals(board[i][2])) {
JOptionPane.showMessageDialog(null, string + " won."); break;
}
if (board[0][i] != null && board[0][i].equals(board[1][i]) && board[0][i].equals(board[2][i])) {
JOptionPane.showMessageDialog(null, string + " won."); break;
}
}
}
Add TicTacToe ticTacToe = new TicTacToe(); to the Gui variables.
Change the action listener:
public void actionPerformed(ActionEvent e) {
ticTacToe.buttonClicked(button);
ticTacToe.gameRules(button);
}
Delete TicTacToe ticTacToe = new TicTacToe(); from the Control.
Always check your errors, you had more NullPointerException exception than you can count.
This should fix the null pointer exception.
public static void gameRules(JButton button) {
//"X" or "O"?
String string = button.getText();
//Gives coordinates of the button
int x = Character.getNumericValue(button.getName().charAt(0));
int y = Character.getNumericValue(button.getName().charAt(1));
board[x][y] = string;
//diagonal
if(board[0][0] != null && board[1][1] != null && board[2][2] != null &&
board[0][0].equals(board[1][1]) && board[1][1].equals(board[2][2]){
JOptionPane.showMessageDialog(null,string + " won.");
} else if(board[0][2] != null && board[1][1] != null && board[2][0] != null &&
board[0][2].equals(board[1][1]) && board[0][2].equals(board[2][0]) && board[1][1].equals(board[2][0])) { //other diagonal
JOptionPane.showMessageDialog(null,string + " won.");
} else if(count==9) { //draw?
JOptionPane.showMessageDialog(null,"draw.");
} else {
//row
for(int i = 0; i < 3; i++) {
if(board[i][0] != null && board[i][1] != null && board[i][2] != null &&
board[i][0].equals(board[i][1]) && board[i][1].equals(board[i][2])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
}
//column
for(int j = 0; j < 3; j++) {
if(board[0][j] != null && board[1][j] != null && board[2][j] != null &&
board[0][j].equals(board[1][j]) && board[1][j].equals(board[2][j])) {
JOptionPane.showMessageDialog(null,string + " won.");
}
}
}
}
I am an AP Computer Science student and I need help with my assignment for the class. My assignment is to create a simple GUI or game using Eclipse. I made a simple player vs. player tic-tac-toe game, but I do not know how to create a "reset" button for my GUI. I tried multiple times, but I can't get it to work or show up in my GUI. I would appreciate some pointers on how to implement a functional reset button, so I would not have exit out of my GUI multiple times to start playing again. Here is the code I have written so far.
package gui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TicTacToeGUI implements ActionListener
{
JFrame window = new JFrame("Tic-Tac-Toe");
JButton[] button;
JButton reset = new JButton("Reset");
String letter = "";
public int count = 0;
public boolean win = false;
public TicTacToeGUI()
{
button = new JButton[9];
window.setSize(300,300);
window.setLayout(new GridLayout(3,3));
JButton dummy = new JButton("");
Font font = dummy.getFont();
Font bigFont = font.deriveFont(font.getSize2D() * 5.0f);
JButton reset = new JButton("Reset");
for(int i = 0; i < 9; i++)
{
button[i] = new JButton("");
button[i].setFont(bigFont);
button[i].addActionListener(this);
window.add(button[i]);
}
window.setVisible(true);
}
public void actionPerformed(ActionEvent a)
{
count++;
if(count % 2 == 1)
{
letter = "X";
}
else
{
letter = "O";
}
Object but = a.getSource();
for(int i = 0; i < 9; i++)
{
if(but == button[i])
{
button[i].setText(letter);
button[i].setEnabled(false);
break;
}
}
if( button[0].getText() == button[1].getText() && button[1].getText() == button[2].getText() && button[0].getText() != "")
{
win = true;
}
else if(button[3].getText() == button[4].getText() && button[4].getText() == button[5].getText() && button[3].getText() != "")
{
win = true;
}
else if(button[6].getText() == button[7].getText() && button[7].getText() == button[8].getText() && button[6].getText() != "")
{
win = true;
}
else if(button[0].getText() == button[3].getText() && button[3].getText() == button[6].getText() && button[0].getText() != "")
{
win = true;
}
else if(button[1].getText() == button[4].getText() && button[4].getText() == button[7].getText() && button[1].getText() != "")
{
win = true;
}
else if(button[2].getText() == button[5].getText() && button[5].getText() == button[8].getText() && button[2].getText() != "")
{
win = true;
}
else if(button[0].getText() == button[4].getText() && button[4].getText() == button[8].getText() && button[0].getText() != "")
{
win = true;
}
else if(button[2].getText() == button[4].getText() && button[4].getText() == button[6].getText() && button[2].getText() != "")
{
win = true;
}
else
{
win = false;
}
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 TicTacToeGUI();
}
}
You might want to try this:
window.setLayout(new BorderLayout());
JPanel panel = new JPanel( new GridLayout(3, 3));
window.add(panel, BorderLayout.CENTER); // add panel to window center
window.add(reset, BorderLayout.SOUTH); // add reset button to window bottom
Of course, you will have to add your 9 buttons to panel now, not to window.
But why don't you just reset automatically after the user confirmed the dialog at the end of the game?
Reset your board after a tie or win. An example reset method. Otherwise you are going to have to make room on your Frame to hold a button to do this.
private void ResetBoard() {
for(int i = 0; i < 9; i++) {
button[i].setText("");
button[i].setEnabled(true);
count = 0;
}
}
Then use this method when a check is made to see if a player won or the game ends in a tie as below:
if(win == true)
{
JOptionPane.showMessageDialog(null, letter + " WINS!");
ResetBoard();
}
else if(count == 9 && win == false)
{
JOptionPane.showMessageDialog(null, "Tie Game!");
ResetBoard();
}
I am making a little game for my university coursework and got stuck at the menu creation. Been trying to solve this for a while. Here goes the code:
Before trying to fiddle around the loop and noLoop() functions and before I moved the arrow placement from void setup to void keypressed my game has worked. Now the program freezes before running draw.
What I want is to only display the menu background before the key, in this case s for start, has been pressed. If anyone could come up with some directions it would be of a great help.
Thanks in advance.
int totalArrows = 6;
arrowclass[] theArrows = new arrowclass[totalArrows];
PImage[] imgList = new PImage[4];
PImage bg;
PImage life;
PImage menu;
int score;
int loose = 3;
void setup() {
size(400, 600);
bg = loadImage("bck.jpg");
life = loadImage("life.png");
menu = loadImage("menu.jpg");
background(menu);
// loading the arrow imgs
for (int i= 0; i<4; i++) {
println(i+".png");
imgList[i] = loadImage(i+".png");
}
noLoop();
}
void draw() {
textSize(32);
text(score,30,100);
// active area
fill(255,31,31);
rect(0,500,width,100);
//lifetrack
if (loose==3){
image(life,10,10);
image(life,45,10);
image(life,80,10);
}
if (loose==2){
image(life,10,10);
image(life,45,10);
}
if (loose==1){
image(life,10,10);
}
// calling class action, movement
for (int i = 0; i<totalArrows; i++) {
theArrows[i].run();
if (theArrows[i].y>475 && theArrows[i].y<600) {
theArrows[i].inactive = true;
}
if(theArrows[i].did == false && theArrows[i].y>598) {
theArrows[i].lost = true;
}
if(theArrows[i].lost && theArrows[i].did == false && theArrows[i].wrongclick == false){
loose--;
theArrows[i].lost = false;
}
}
if (loose == 0){
textSize(32);
text("gameover",width/2,height/2);
for(int i=0; i<totalArrows;i++){
}
}
}
void keyPressed() {
if (key == 'p'){
// placing tha arrows. (i*105 = positioning) THIS PART IS AN ISSUE FOR SURE. SEE ARROW CLASS
for (int i= 0; i<totalArrows; i++) {
theArrows[i] = new arrowclass(-i*105);
}
loop();
}
}
void keyReleased() {
for (int i= 0; i<totalArrows; i++) {
if (theArrows[i].inactive && theArrows[i].did == false) {
if (keyCode == UP && theArrows[i].id == 3){
score++;
theArrows[i].did = true;
}
if (keyCode != UP && theArrows[i].id == 3){
loose--;
theArrows[i].wrongclick = true;
}
if (keyCode == DOWN && theArrows[i].id == 0){
score++;
theArrows[i].did = true;
}
if (keyCode != DOWN && theArrows[i].id == 0){
loose--;
theArrows[i].wrongclick = true;
}
if (keyCode == RIGHT && theArrows[i].id == 2){
score++;
theArrows[i].did = true;
}
if (keyCode != RIGHT && theArrows[i].id == 2){
loose--;
theArrows[i].wrongclick = true;
}
if (keyCode == LEFT && theArrows[i].id == 1){
score++;
theArrows[i].did = true;
}
if (keyCode != LEFT && theArrows[i].id == 1){
loose--;
theArrows[i].wrongclick = true;
}
}
}
}
And the arrow class:
class arrowclass{
int y;
int id;
boolean did;
boolean inactive;
boolean lost;
boolean wrongclick;
// proprieties of the class
arrowclass(int initY){
y = initY;
id = int(random(4));
did = false;
inactive = false;
lost = false;
wrongclick = false;
}
//actions
void run(){
image(imgList[id],width/2,y);
// score goes up, speed goes up
y += 2+score;
// reset arrow to default
if (y>600) {
y = -50;
id = int(random(4));
inactive = false;
did = false;
lost = false;
wrongclick = false;
}
}
}
I have got a problem with minimax algorithm. I want to make tic tac toe game with AI. I used JFrame to make that.
So my minimax algorithm returns always number 9 and I don't know why. What's wrong ?
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class Zadanie2 extends JFrame implements ActionListener {
/**
*
*/
JButton button0 = new JButton("");
JButton button1 = new JButton("");
JButton button2 = new JButton("");
JButton button3 = new JButton("");
JButton button4 = new JButton("");
JButton button5 = new JButton("");
JButton button6 = new JButton("");
JButton button7 = new JButton("");
JButton button8 = new JButton("");
JButton button9 = new JButton("");
int playerSign = 1;
String computerMark, opponentMark;
public static final long serialVersionUID = 1L;
JButton[] buttonArray = { button0, button1, button2, button3, button4,
button5, button6, button7, button8, button9 };
Object[] options = { "GRAJ OD NOWA", "ZAKOŃCZ GRĘ" };
Object[] startOptions = { "GRACZ", "KOMPUTER", "OPUŚĆ GRĘ" };
boolean canMove;
boolean computerStarted;
int bb = 1;
public Zadanie2() {
super("KÓŁKO I KRZYŻYK");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300, 300);
setResizable(false);
setLocation(470,400);
setLayout(new GridLayout(3,3));
for(int i = 1; i <= 9; i++){
add(add(buttonArray[i]));
buttonArray[i].addActionListener(this);
}
setVisible(true);
int y = JOptionPane.showOptionDialog(null,"WYBIERZ KTO MA ZACZĄĆ GRĘ","WIADOMOŚĆ", JOptionPane.INFORMATION_MESSAGE,
JOptionPane.INFORMATION_MESSAGE,
null,
startOptions,
startOptions[0]);
if (y == 2) {
System.exit(1);
}
if (y == 1) { // COMPUTER
computerStarted = true;
computerMark = "X";
opponentMark = "O";
canMove = true;
computerMove();
}
if (y == 0) { // PLAYER
computerStarted = false;
computerMark = "O";
opponentMark = "X";
}
}
public static void main(String[] args) {
new Zadanie2();
}
public void close() {
playerSign = 1;
dispose();
}
private void computerMove() {
if(canMove){
System.out.println("AI: "+AI(buttonArray));
buttonArray[AI(buttonArray)].doClick();
}
canMove = false;
}
private int AI(JButton[] buttonArray2){
int ruch, i, m, mmx;
ruch = 0;
mmx = -10;
for(i = 1; i < 9; i++)
if(buttonArray[i].getText() == "");
{
buttonArray[i].setText(computerMark);
m = minimax(buttonArray, computerMark);
buttonArray[i].setText("");
if (m > mmx) {
mmx = m;
ruch = i;
}
}
return ruch;
}
public int minimax(JButton[] buttonArray,String gracz){
int m, mmx;
if(win(buttonArray,gracz)) return (gracz == computerMark) ? 1 : -1;
if(tie(buttonArray)){
return 0;}
gracz = (gracz == computerMark) ? opponentMark : computerMark;
mmx = (gracz == opponentMark) ? 10 : -10;
for(int i = 1; i <= 9; i++)
if(buttonArray[i].getText() == "")
{
buttonArray[i].setText(gracz);
m = minimax(buttonArray,gracz);
buttonArray[i].setText("");
if(((gracz == opponentMark) && (m < mmx)) || ((gracz == computerMark) && (m > mmx))){mmx = m;}
}
return mmx;
}
private void checkWin() {
if(win(buttonArray,"X")){
winX();
}
if(win(buttonArray,"O")){
winO();
}
if(tie(buttonArray)){
sayTie();
}
}
private void winX() {
int n = JOptionPane.showOptionDialog(null, "WYGRAŁ GRACZ X ",
"WIADOMOŚĆ", JOptionPane.INFORMATION_MESSAGE,
JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
if (n == 0) {
close();
new Zadanie2();
}
if (n == 1) {
System.exit(1);
}
dispose();
}
private void winO() {
int n = JOptionPane.showOptionDialog(null, "WYGRAŁ GRACZ O ",
"WIADOMOŚĆ", JOptionPane.INFORMATION_MESSAGE,
JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
if (n == 0) {
close();
new Zadanie2();
}
if (n == 1) {
System.exit(1);
}
dispose();
}
private void sayTie() {
int n = JOptionPane.showOptionDialog(null, "REMIS! ", "WIADOMOŚĆ",
JOptionPane.INFORMATION_MESSAGE,
JOptionPane.INFORMATION_MESSAGE, null, options, options[0]);
if (n == 0) {
close();
new Zadanie2();
}
if (n == 1) {
System.exit(1);
}
dispose();
}
public boolean tie(JButton[] buttonArray2){
for(int i = 1; i <= 9; i++){
if(buttonArray2[i].getText() == ""){
return false;
}
}
return true;
}
private boolean win(JButton[] buttonArray2, String g) {
if (buttonArray2[1].getText() == buttonArray2[2].getText()
&& buttonArray2[1].getText() == buttonArray2[3].getText()
&& buttonArray2[2].getText() == buttonArray2[3].getText() && buttonArray2[1].getText() == g) {
return true;
}
if (buttonArray2[3].getText() == buttonArray2[7].getText()
&& buttonArray2[3].getText() == buttonArray2[5].getText()
&& buttonArray2[7].getText() == buttonArray2[5].getText() && buttonArray2[3].getText() == g) {
return true;
}
if (buttonArray2[7].getText() == buttonArray2[8].getText()
&& buttonArray2[7].getText() == buttonArray2[9].getText()
&& buttonArray2[8].getText() == buttonArray2[7].getText() && buttonArray2[7].getText() == g) {
return true;
}
if (buttonArray2[4].getText() == buttonArray2[5].getText()
&& buttonArray2[4].getText() == buttonArray2[6].getText()
&& buttonArray2[5].getText() == buttonArray2[6].getText() && buttonArray2[4].getText() == g) {
return true;
}
if (buttonArray2[1].getText() == buttonArray2[5].getText()
&& buttonArray2[1].getText() == buttonArray2[9].getText()
&& buttonArray2[5].getText() == buttonArray2[9].getText() && buttonArray2[1].getText() == g) {
return true;
}
if (buttonArray2[1].getText() == buttonArray2[4].getText()
&& buttonArray2[1].getText() == buttonArray2[7].getText()
&& buttonArray2[4].getText() == buttonArray2[7].getText() && buttonArray2[1].getText() == g) {
return true;
}
if (buttonArray2[2].getText() == buttonArray2[8].getText()
&& buttonArray2[2].getText() == buttonArray2[5].getText()
&& buttonArray2[8].getText() == buttonArray2[5].getText() && buttonArray2[2].getText() == g) {
return true;
}
if (buttonArray2[3].getText() == buttonArray2[6].getText()
&& buttonArray2[3].getText() == buttonArray2[9].getText()
&& buttonArray2[6].getText() == buttonArray2[9].getText() && buttonArray2[3].getText() == g) {
return true;
}
return false;
};
#Override
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
for (int i = 1; i <= 9; i++) {
if (source == buttonArray[i] ) {
playerSign++;
if (playerSign % 2 == 0 && buttonArray[i].getText() == "") {
buttonArray[i].setText("X");
}
if (playerSign % 2 != 0 && buttonArray[i].getText() == "") {
buttonArray[i].setText("O");
}
if (computerStarted && playerSign % 2 != 0) {
canMove = true;
computerMove();
}
if (!computerStarted && playerSign % 2 == 0) {
canMove = true;
computerMove();
}
}
}
System.out.println("PS: " + playerSign);
if(playerSign > 3){
checkWin();}
}
}
Any ideas on how I may solve this problem?
You should use .equals instead of == whenever you compare two Objects.
E.g. there should be computerMark.equals(gracz) instead of gracz == computerMark.
Edit:
Also, You should replace 1 and -1 with 10 and -10 respectively here:
if(win(buttonArray,gracz)) return (gracz == computerMark) ? 1 : -1;
Reference
I am a beginner at programming and I have been teaching myself as much as I can. I need help in a simpler way of checking for a victory instead of hard coding every possible combination.
I have no idea what to do.
here is my current code:
import java.awt.*;
import javax.swing.event.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class connectfour extends JFrame implements ActionListener
{
JLabel board[][] = new JLabel[8][7];
//JLabel board[] = new JLabel[64];
JButton action[] = new JButton[8];
JButton start;
JButton clear;
JFrame Frame = new JFrame();
ImageIcon red = new ImageIcon("red piece.jpeg");
ImageIcon black = new ImageIcon("blackpiece.jpeg");
boolean players = true;
//Integer[] numclick = new Integer[8];
int x;
int numclick1 = 7;
int numclick2 = 7;
int numclick3 = 7;
int numclick4 = 7;
int numclick5 = 7;
int numclick6 = 7;
int numclick7 = 7;
int numclick0 = 7;
public connectfour()
{
Frame.setSize(100,120);
Frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
Frame.setLayout(null);
Frame.setVisible(true);
start = new JButton("Start");
start.setBounds(0,0,100,100);
start.setVisible(true);
start.addActionListener(this);
Frame.add(start);
}
public void game()
{
for(int x = 0; x < 8 ; x++)
{
action[x] = new JButton();
action[x].setSize(100,40);
action[x].setLocation((x*100) + 50, 0);
action[x].addActionListener(this);
action[x].setVisible(true);
Frame.add(action[x]);
}
/**
board[1][1] = new JLabel();
board[1][1].setBounds(50,40,100,100);
board[1][1].setVisible(true);
board[1][1].setOpaque(true);
board[1][1].setBorder(BorderFactory.createLineBorder(Color.black));
Frame.add(board[1][1]);
**/
for(int i = 0; i < 8; i++)
{
for(int j = 0; j < 7; j++)
{
board[i][j] = new JLabel();
board[i][j].setSize(100,100);
board[i][j].setLocation((i*100)+50,(j*100)+40);
board[i][j].setOpaque(true);
board[i][j].setVisible(true);
board[i][j].setBorder(BorderFactory.createLineBorder(Color.black));
Frame.add(board[i][j]);
}
}
clear = new JButton("Clear");
clear.setBounds(850,100,100,50);
clear.addActionListener(this);
clear.setVisible(true);
Frame.add(clear);
}
public void boardsize()
{
Frame.setSize(950,800);
}
public static void main(String args[])
{
new connectfour();
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == start)
{
boardsize();
start.setVisible(false);
game();
}
for(x = 0;x < 8 ;x ++)
{
if(e.getSource() == action[x])
{
//numclick[x]++;
if(x == 0)
{
numclick0--;
if(players == true)
{
board[x][numclick0].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick0].setIcon(black);
players = true;
break;
}
}
if(x == 1)
{
numclick1--;
if(players == true)
{
board[x][numclick1].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick1].setIcon(black);
players = true;
break;
}
}
if(x == 2)
{
numclick2--;
if(players == true)
{
board[x][numclick2].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick2].setIcon(black);
players = true;
break;
}
}
if(x == 3)
{
numclick3--;
if(players == true)
{
board[x][numclick3].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick3].setIcon(black);
players = true;
break;
}
}
if(x == 4)
{
numclick4--;
if(players == true)
{
board[x][numclick4].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick4].setIcon(black);
players = true;
break;
}
}
if(x == 5)
{
numclick5--;
if(players == true)
{
board[x][numclick5].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick5].setIcon(black);
players = true;
break;
}
}
if(x == 6)
{
numclick6--;
if(players == true)
{
board[x][numclick6].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick6].setIcon(black);
players = true;
break;
}
}
if(x == 7)
{
numclick7--;
if(players == true)
{
board[x][numclick7].setIcon(red);
players = false;
break;
}
if(players == false)
{
board[x][numclick7].setIcon(black);
players = true;
break;
}
}
System.out.println(x);
System.out.println();
}
}
if(e.getSource() == clear)
{
for(int x = 0; x < 8; x++)
{
for(int y = 0; y < 7; y++)
{
board[x][y].setIcon(null);
numclick1 = 7;
numclick2 = 7;
numclick3 = 7;
numclick4 = 7;
numclick5 = 7;
numclick6 = 7;
numclick7 = 7;
numclick0 = 7;
players = true;
for(int j = 0; j < 8 ; j++)
{
action[j].setEnabled(true);
}
}
}
}
if(numclick0 == 0)
{
action[0].setEnabled(false);
}
if(numclick1 == 0)
{
action[1].setEnabled(false);
}
if(numclick2 == 0)
{
action[2].setEnabled(false);
}
if(numclick3 == 0)
{
action[3].setEnabled(false);
}
if(numclick4 == 0)
{
action[4].setEnabled(false);
}
if(numclick5 == 0)
{
action[5].setEnabled(false);
}
if(numclick6 == 0)
{
action[6].setEnabled(false);
}
if(numclick7 == 0)
{
action[7].setEnabled(false);
}
}
public void winner()
{
}
}
I would use a recursive method that checks the horizontal, vertical, and both diagonals.
As i was reading your code I realized you don't keep track(may have missed it) of where players are.. I recommend and array for this called grid[][] Mapping an array to your JLabels will go a long way.
Ill give an example of negative vertical check..
public Boolean checkVertical(Boolean player, int x, int y){
if(solveHelper(player, x, y, -1, 0) => 4) return true;
return false;
}
public int solveHelper(Boolean player, int x, int y, int addX, int addY){
if(x == 0 || x == size || y == 0 || y == size || grid[x][y].player != player)
return 0;
return solverHelper(player, x+addX, y+addY, addX, addY) + 1);
}
Now how can you create and use these methods for yourself?
you need to create a new methods for each of the horizontal, vertical, and both diagonals to check for all of them you call solveHelper with different properties in addX and addY that correspond with the direction you want to go. For instance, if you want to check the horizontal you need do make addY == 1 and addY == -1 with both values for addX == 0 by doing a solveHelper + solverHelper with these two values changed.
Other notes...
Some things you need to need to keep in mind is that how connect four actually runs. When you click on a row a piece falls down to the smallest unoccupied element in that particular column. Just something you should keep in mind when writing your game logic.
Cheers.