dealing with tictactoe detecting the buttons - java

So, I'm working on a project that uses a GridLayout and an array of tictactoetile, which is a class which extends JButton.
For an example of the first thing I'm trying to do, I want to find out what button is clicked, and then set that button's text to equal either x or o depending on which turn it is. I have the logic for that down, I just don't know how to get the row and column of the button clicked.
Sorry if this is not worded well.

public class tictactoetile extends JButton implements ActionListener {
private int cory;
private int corx;
//Create your own GameObj class with the necessary members
//Some examples for members below...
private GameObj game;
public tictactoetile(int x,int y,GameObj gam) {
cory = y;
corx = x;
game = gam;
super();
}
public void actionPerformed(ActionEvent e) {
this.setText(game.getTurnMarker()); //returns either x or o
game.updateGameState(game.getTurn(),cory,corx);
game.nextTurn();
}
}

Related

JButton child does not update text

I'm building a game where the object is to move a knight around a world and be able to fight other knights.
I've got a class Main that starts the game:
public class Main {
public static void main(String[] args) {
new Game();
}
}
A class Game that creates a JFrame:
import java.awt.GridLayout;
import javax.swing.JFrame;
public class Game {
public Game() {
JFrame frame = new JFrame();
frame.setTitle("Knights Tournament");
frame.add(new Board());
frame.setSize(700, 700);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
And a class Board which (you guessed it!) creates the GameBoard:
public class Board extends JPanel {
Tile[][] grid = new Tile[15][15];
public Board(){
// Create the grid
CreateGrid();
// Add the player
grid[0][0] = new Player(0, 0);
}
// Method that creates a grid of tiles
private void CreateGrid() {
setLayout(new GridLayout (15, 15));
for(int i = 0; i < 15; i++){
for(int j = 0; j < 15; j++){
grid[i][j] = new Tile(i, j);
add(grid[i][j]);
}
}
}
}
The grid initialy consists of 15x15 tiles.
public class Tile extends JButton implements ActionListener {
public int xCo;
public int yCo;
public Tile(int x, int y) {
setXCo(x);
setYCo(y);
}
public void setXCo(int x) {
this.xCo = x;
}
public void setYCo(int y) {
this.yCo = y;
}
public int getXCo() {
return xCo;
}
public int getYCo() {
return yCo;
}
}
The problem i'm facing is the following: I would like to replace grid[0][0] by another class Player that expands tile. The difference between tile and player would be that the Jbutton gets a text saying 'P' i've tried this:
public class Player extends Tile{
public Player(int x, int y) {
super(x, y);
this.setText("P");
}
}
In the constructor of the class board i tried changing grid[0][0] from tile to player so it would display P, but it doesn't do so for some reason (It does change the type of grid[0][0] to player...) I hope someone can help.
You shouldn't try and maintain the state of the object with the UI, per se. Rather the UI should visualise the state of the underlying logic of the game (or model). This allows you to modify the model, change the rules, add/remove elements (think adding new monsters or loot for example), without need to physically modify the UI or how it visualise this state (to a large degree).
The idea is, the Player attributes should be maintain with an class of it's own, which is managed by the model. The UI would then be used to visualise the state the model.
When clicked the Tile would notify the "controller". The controller would request stateful information from the games "model" and based on this information the "controller" would change the state of the button(s) to meet the requirements of the "model"
This would simply require the "controller" to update the button(s) information (text/icons) without needing to change the physical buttons.
This separates the responsibilities into defined layers and reduces the coupling of the code, so one or more layers can change, but the overall structure doesn't break down or need to be heavily modified to handle these changes.
The model is responsible for maintaining the virtual state of the game, for managing the interactions between the individual game objects (combat etc).
The UI is responsible for providing a visualisation of the model for the user and the controller is used to manage the interaction between the take, taking user input and pass it to the model, monitoring changes to the model's state and telling the UI when it needs to update.
The Model–view–controller paradigm is a common approach used in GUI development across different lanuguages. Take a look at Model–view–controller for more details.

Need Help adding a difficulty option for User functionality

Quick question, I have developed 3 A.I's each with a different depth.
Currently to choose what A.I you want to play against you have to go into the java file called Main.java and change it to whichever one you want. The line to change is:
chessGame.setPlayer(Piece.COLOR_BLACK, ai3);//Here A.I is assigned
I want to allow the user to have an option at the start of the game to choose the A.I. I was hoping for some help with the interface, I was thinking something something like a JOptionpane might work.
(I'm just not sure how to do one for the A.I selection)
Current A.I's
ai1
ai2
ai3
package chess;
import chess.ai.SimpleAiPlayerHandler;
import chess.gui.ChessGui;
import chess.logic.ChessGame;
import chess.logic.Piece;
public class Main {
public static void main(String[] args) {
// Creating the Game
ChessGame chessGame = new ChessGame();
// Creating the Human Player
//Human Player is the Object chessGui
ChessGui chessGui = new ChessGui(chessGame);
//Creating the A.I's
SimpleAiPlayerHandler ai1 = new SimpleAiPlayerHandler(chessGame);//Super Dumb
SimpleAiPlayerHandler ai2 = new SimpleAiPlayerHandler(chessGame);//Dumb
SimpleAiPlayerHandler ai3 = new SimpleAiPlayerHandler(chessGame);//Not So Dumb
// Set strength of AI, how far they can see ahead
ai1.maxDepth = 1;
ai1.maxDepth = 2;
ai3.maxDepth = 3;
//Assign the Human to White
chessGame.setPlayer(Piece.COLOR_WHITE, chessGui);
//Assign the not so dumb A.I to black
chessGame.setPlayer(Piece.COLOR_BLACK, ai3);
// in the end we start the game
new Thread(chessGame).start();
}
}
Thanks for any help.
You should probably use a JComboBox to allow the user to select among the 3 options available. If you make a splash JFrame with this JComboBox you can then create your main game frame afterward and pass it the value from the JComboBox.
For example, you could have the JComboBox give options of difficulty setting Easy, Medium, and Hard. Using an action listener on a JButton get the selected value from the JComboBox and convert it to int value appropriate for your minimax algorithm. That is, pass 1 for easy, 2 for medium, and 3 for hard.
Next change your ai class so that maxDepth is in the constructor. Then when you instantiate your ai, just give it the value that was passed forward from the previous frame and you will have created the only ai you need at the right difficulty setting.
EDIT:
It looks like you managed to get something similar working which is great! In case it helps you, I have included a brief example of how I would have done this below. Note that I also set it up such that your SimpleAiPlayerHandler constructor also takes an int value for instantiating the maxDepth variable. You'll need to add this. Since it uses classes I don't have, I can't compile it. However, if anyone else needs to do something similar, just remove everything in the DifficultyListener except the print statement and the line that get's the difficulty from the JComboBox and you'll see it working (and compiling).
import javax.swing.*;
import java.awt.event.*;
public class ChessSplash extends JFrame {
private final JComboBox<Difficulty> difficultySetting;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ChessSplash gui = new ChessSplash();
gui.setVisible(true);
}
});
}
public enum Difficulty {
EASY(1, "Easy"), MEDIUM(2, "Medium"), HARD(3, "Hard");
private final int intValue;
private final String stringValue;
private Difficulty(int intValue, String stringValue) {
this.intValue = intValue;
this.stringValue = stringValue;
}
#Override
public String toString() {
return stringValue;
}
};
public ChessSplash() {
super("Chess Game");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
difficultySetting = new JComboBox<>(Difficulty.values());
JButton startButton = new JButton("Start Game");
startButton.addActionListener(new DifficultyListener());
JPanel mainPanel = new JPanel();
add(mainPanel);
mainPanel.add(difficultySetting);
mainPanel.add(startButton);
pack();
}
private class DifficultyListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
//Declare AI
SimpleAiPlayerHandler ai;
//Declare and Instantiate Chess Game
ChessGame chessGame = new ChessGame();
//Human Player is the Object chessGui
ChessGui chessGui = new ChessGui(chessGame);
//Assign Human Player to White
chessGame.setPlayer(Piece.COLOR_WHITE, chessGui);
//Get the selected difficulty setting
Difficulty difficulty = (Difficulty)difficultySetting.getSelectedItem();
//Instantiate Computer AI pass it the maxDepth for use in the constructor
ai = new SimpleAiPlayerHandler(difficulty.intValue, chessGame);
//Assign Computer Player to Black
chessGame.setPlayer(Piece.COLOR_BLACK, ai);
//Demonstrate the enum combobox works
System.out.println(difficulty.intValue);
//Dispose of the splash JFrame
ChessSplash.this.dispose();
//Start your game thread (I would probably do something to move this
//onto the EDT if you're doing this is swing personally
new Thread(chessGame).start();
}
}
}

Calling repaint from another class JFrame

I'm trying to call repaint from another class. But it does not work. I have to draw on a frame.
public class Tester extends JFrame{
public static dtest d ;
public static void main(String[] args) {
Tester t = new Tester();
d = new dtest();
test tnew = new test();
}
public static class dtest extends JFrame implements MouseMotionListener{
public static int x,y;
dtest()
{
super("title");
setSize(500,500);
setVisible(true);
addMouseMotionListener(this);
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
public void paint(Graphics g)
{
System.out.println("I am called");
}
}
public static class test {
public test()
{
for(int i = 0 ; i < 5 ; i++)
{
System.out.println("I am called from run");
d.repaint();
}
}
}
}
this prints
I am called from run
I am called from run
I am called from run
I am called from run
I am called from run
so it does not executing the paint() portion. d.repaint() is not working. why?
Take a look at this page and look at the first answer. It's a similar if not exact question to yours.
JFrame's paint() method has been deprecated. The compiler, or your IDE, should be complaining a bit, especially if you place the #Override tag directly above the method (use this to test if this method can be rewritten... aka what you're trying to do).
This means that its use has been discouraged and some functionality may have been removed. When using javax.swing, you'll want to learn the system completely about JPanels and JComponents. To paint something on a screen, you'll want to add a custom class that extends JPanel with the add(Component c) method. Then, override the paintComponent(Graphics g) method in that class. Make sure to have the first line in that method be super.paintComponent(g); so that the window can refresh itself.
For completeness:
public class MyWindow extends JFrame {
MyPanel thePanel;
public MyWindow(int x, int y) {
setSize(x, y);
thePanel = new MyPanel(x, y);
this.add(thePanel);
}
}
public class MyPanel extends JPanel {
public MyPanel(int x, int y)
setSize(x, y);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(ImageManager.getImage("Cute Puppy"), 40, 40, null); // Or whatever
}
}
So, when the repaint() or revalidate() method is called on the MyWindow, the Panel will recieve a paintComponent call.
Please let me know in the comments if you need any additional help.
Edited:
Since you need to use MouseMotionListener, and I'm still not quite understanding the context and trouble of "I need to call repaint from another class"... I will try my best.
Firstly, check out this tutorial on the Oracle pages. Also, check out the others on GUI's. You'll learn a lot about organization and displaying that will make you realize how their system can work with yours.
Now, for your questions:
i have to use MouseMotionListener.
Not quite... it is a good way for set up but you can run a Thread (something that constantly runs methods over and over) to check the Mouse coordinates. You'll want to start doing this when you get into games and other miscellaneous applications.
new Thread() {
public void run() {
Point mouse;
int mousex;
int mousey;
while (true) {
mouse = MouseInfo.getPointerInfo().getLocation();
mousex = mouse.x - theWindow.getLocationOnScreen().x - 3; // You'll need to get the
// x coordinate, subtract the window's x coordinate, and subtract 3 because of
// the blue border around a standard pc window.
mousey = mouse.y - theWindow.getLocationOnScreen().y - 29; // 29 is top bar height
SomeOtherClass.processMove(mousex, mousey);
}
}
}.start();
Next: I tried that with JPanel but i could not do that. If you read the tutorial at the top of my edit, you see they implement MouseMotionListener with ease.
Next: I prefer to do it with JFrame. If you wish to process the mouse in the JFrame, do the following: Have your JFrame the listener, but the JPanel be where the mouse data comes from. As follows:
public class MyWindow extends JFrame implements MouseMotionListener {
public MyPanel thePanel;
public int x;
public int y;
public MyWindow() {
thePanel = new MyPanel();
thePanel.addMouseMotionListener(this);
// Make this JFrame get called when the mouse
// moves across the panel.
}
#Override
public void mouseDragged(MouseEvent e) {
x = e.getX();
y = e.getY();
thePanel.repaint();
}
#Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
}
public class MyPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Other painting stuff
}
}
Next: Now i have to update the frame from another class. I could not find a way to update the GUI(the frame) from another class.
Simple. Since the JPanel is what needs to be updated, add the following method to the MyWindow class:
public void repaintWindow() {
thePanel.repaint();
}
And add this to whenever you need to update it:
MyWindow theWindow = new MyWindow();
theWindow.repaintWindow();
Next: all the answers here extended JPanel. So i could not find my answer.
I apologize, but you NEED a panel. It is possible to do with JFrames, but if you want to start doing things raw and low-level, you need to learn how these things work by learning to read the oracle tutorials and the oracle documentation. For now, use JPanels in any ways I've shown you.
Next: from another class I have to draw something on JFrame.Is that possible?
Yes, indeed! Whenever you want to draw something:
MyWindow theWindow = new MyWindow();
Graphics g = theWindow.thePanel.getGraphics();
BufferedImage someRandomImage = SomeRandomClass.getRandomImage();
g.drawImage(someRandomImage, 200, 481, null);
theWindow.repaintWindow();
I really hope I've helped but to program in java you need to use the tools they give you, especially when it comes to high level things like Swing. There are tutorials everywhere for this stuff. Please read them before asking for specific help in the future.

Find index of button in 2D Array Java?

I just have a question on the following. I've got a 2D array of buttons that require me to run another method when I click on them. My current method relies on the following input, a String (which I can get from the user easily) and two integer values. These are dictated by the buttons position in the array.
I have a button listener attached to these buttons but I am not too sure how I can work out what the button's position actually is. I've made my own button class (because I wanted some specific settings and I thought it would be easier) and when making it I implemented a method called getXPos and getYPos which basically hold the values for the actual button in the array when it was created. Thing is I don't know how to retrieve these values now as the listener doesn't actually know what button is being pressed does it?
I can use the getSource() method but I then don't know how to invoke that source's methods. For example I tried to do the following.
int x = event.getSource().getXPos(); but I am unable to do this. Is there any way of telling what button I have pressed so I can access it's internal methods or something similar? Thanks!
To call a method on the source, you have to cast it first. If you're never adding your ActionListener to anything but an instance of your special MyButton with its x and y variables, you can do this:
MyButton button = (MyButton) event.getSource();
int x = button.getXPos();
int y = button.getYPos();
Then MyButton contains the x and y:
public class MyButton extends JButton {
private int xPos;
private int yPos;
// ...
public int getXPos() {
return xPos;
}
public int getYPos() {
return yPos;
}
}
And make sure you're always adding your listener to instances of MyButton:
MyButton myButton = new MyButton();
// ...
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
MyButton button = (MyButton) e.getSource();
int xPos = button.getXPos();
int yPos = button.getYPos();
// Do something with x and y
}
});

Why isn't my object moving on MouseMoved?

Simple question – why wouldn't an object move if it's the object of .move() inside onMouseMoved()? I'm trying to write Breakout as part of the Stanford 106A exercises on iTunes U and for some reason I can't get the paddle to track the mouse. I'm a java noob, so I'm sure it's something really simple. Could someone please take a look at this code?
/** Runs the Breakout program. */
public void run() {
setupBoard();
addMouseListeners();
}
/** Provides the initial GCanvas and blocks for the game */
private void setupBoard(){
this.setSize(APPLICATION_WIDTH,APPLICATION_HEIGHT);
addBricks();
paddle = new GRect(PADDLE_WIDTH, PADDLE_HEIGHT);
add(paddle, WIDTH/2-PADDLE_WIDTH/2,HEIGHT-PADDLE_Y_OFFSET);
}
public void MouseMoved(MouseEvent e){
paddle.move(e.getX()-paddle.getX(), 0);
}
private GRect paddle;
}
I'm not sure if having paddle be an instance variable is appropriate in this case, since its "value" doesn't change (the paddle's always the paddle), but if I just define it as a new GRect within setupBoard I get an error in the MouseMoved() method.
Your class that has the mouseMoved() method needs to implement the interface MouseMotionListener, and add the motion listener. Moreover, the event handler is mouseMoved() not MouseMoved(). So, e.g.:
public class Game extends JPanel implements MouseMotionListener {
public void run() {
addMouseMotionListener(this);
//...
}
public void mouseMoved(MouseEvent e) {
paddle.move(e.getX()-paddle.getX(), 0);
}
//...
};

Categories