Highlighting "Legal Moves" In chess-like game on panel array- Java - java

this is more of a logic question than syntax but I'm sure you guys have better ways to do it than me anyway. So I have some pieces (JLabels) on a board (11x11 Grid of JPanels on a JPanel) all in a frame. I'm trying to highlight the "possible moves" for these pieces (I.E. how many panels they can cross in a move) very similar to in many online chessgames. I have the logic that checks if movement follows the rules, and it works perfect, I just can't seem to figure out how to find all of those legal moves at once and use them.
This is the code that I use to check if movement is legal:
public void movePieces(MouseEvent me)
{
MouseEvent e = me;
if (turnCount%2 == 1 && pieceCheck[(e.getY()/yInc)][(e.getX()/xInc)])
{
if (playerOne && (logic[(e.getY()/yInc)][(e.getX()/xInc)] == 0 || logic[(e.getY()/yInc)][(e.getX()/xInc)] == 2 || logic[(e.getY()/yInc)][(e.getX()/xInc)] == 4))
{
otherCount = logic[(e.getY()/yInc)][(e.getX()/xInc)];
tempX = e.getX();
tempY = e.getY();
paintPossible(tempX, tempY);
turnCount++;
}
if (!playerOne && (logic[(e.getY()/yInc)][(e.getX()/xInc)] == 1 || logic[(e.getY()/yInc)][(e.getX()/xInc)] == 3 || logic[(e.getY()/yInc)][(e.getX()/xInc)] == 5))
{
otherCount = logic[(e.getY()/yInc)][(e.getX()/xInc)];
tempX = e.getX();
tempY = e.getY();
turnCount++;
}
}
else if ((turnCount%2 == 0 && logic[(e.getY()/yInc)][(e.getX()/xInc)] == -1 && !pieceCheck[(e.getY()/yInc)][(e.getX()/xInc)]) && (Math.abs(tempX - e.getX()) <= xInc && (Math.abs(tempY - e.getY()) <= yInc) || ((Math.abs(tempX - e.getX()) <= 2*xInc) && (Math.abs(tempY - e.getY()) < yInc/4)) || ((Math.abs(tempX - e.getX()) < xInc/4) && (Math.abs(tempY - e.getY()) <= 2*yInc))))
{
panels[(e.getY()/yInc)][(e.getX()/xInc)].add(pieces[otherCount]);
logic[(e.getY()/yInc)][(e.getX()/xInc)] = otherCount;
pieceCheck[(e.getY()/yInc)][(e.getX()/xInc)] = true;
pieceCheck[tempY/yInc][tempX/xInc] = false;
panels[tempY/yInc][tempX/xInc].setBackground(veryDarkGray);
panels[tempY/yInc][tempX/xInc].setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
playerOne = !playerOne;
turnCount++;
}
....
}
Basically the first if-statement and what's inside is for when you first click a piece, and then if it's your turn then it will set that piece as the next in line to put down, and grab the X-Y coordinates of where it is.
The else-if then activates the next time you click due to the rotation of my turnCount, and makes sure there's no piece where you're clicking and that the space is within a certain# of pixels to where your piece is before you move.
I need to take that same checking of validity in where you can move, and apply it in a separate method that will loop through the 2d array of JPanels that is my board and color the valid moves. The method would be called where "paintPossible(tempX, tempY)" is, and in the same spot in the "if" below.

Related

Tic Tac Toe winner [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 6 years ago.
I have created an x-o game with GUI and almost finished it, but I have difficulties declaring the winner, I managed to do it manually but it took alot of code lines and it looks messy, here's what I did:
if((buttons[0].getText()=="X" && buttons[1].getText()=="X" && buttons[2].getText()=="X") ||
(buttons[0].getText()=="X" && buttons[3].getText()=="X" && buttons[6].getText()=="X") ||
(buttons[4].getText()=="X" && buttons[8].getText()=="X" && buttons[2].getText()=="X") ||
(buttons[0].getText()=="O" && buttons[1].getText()=="O" && buttons[2].getText()=="O") ||
(buttons[0].getText()=="O" && buttons[3].getText()=="O" && buttons[6].getText()=="O") ||
(buttons[4].getText()=="O" && buttons[8].getText()=="O" && buttons[2].getText()=="O") ||
(buttons[2].getText()=="X" && buttons[5].getText()=="X" && buttons[8].getText()=="X") ||
(buttons[1].getText()=="X" && buttons[4].getText()=="X" && buttons[7].getText()=="X") ||
(buttons[6].getText()=="X" && buttons[7].getText()=="X" && buttons[8].getText()=="X") ||
(buttons[2].getText()=="O" && buttons[5].getText()=="O" && buttons[8].getText()=="O") ||
(buttons[1].getText()=="O" && buttons[4].getText()=="O" && buttons[7].getText()=="O") ||
(buttons[6].getText()=="O" && buttons[7].getText()=="O" && buttons[8].getText()=="O") ||
(buttons[3].getText()=="X" && buttons[4].getText()=="X" && buttons[5].getText()=="X") ||
(buttons[3].getText()=="O" && buttons[4].getText()=="O" && buttons[5].getText()=="O") ||
(buttons[0].getText()=="X" && buttons[4].getText()=="X" && buttons[8].getText()=="X") ||
(buttons[0].getText()=="O" && buttons[4].getText()=="O" && buttons[8].getText()=="O") )
So I wanted to shorten this and add it in a loop, but it didnt work.
for(int i=0;i<9;i++)
{
if(i%3==0){
y+=50; x=40;
}
buttons[i]=new JButton();
buttons[i].setSize(50, 50);
buttons[i].setLocation(x, y);
int temp=i;
buttons[temp].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String currentPlayer = turnCount % 2 == 0 ? "X" : "O";
buttons[temp].setText(currentPlayer);
buttons[temp].setFont(new Font("Arial", Font.PLAIN, 30));
buttons[temp].setMargin(new Insets(0, 0, 0, 0));
buttons[temp].setEnabled(false);
turnCount++;
if(buttons[temp].getText()==buttons[temp+1].getText())
{
System.out.println("GAME OVER!");
for(int i=0;i<9;i++)
buttons[i].setEnabled(false);
turnCount = 0;
}
}
});
myForm.add(buttons[i]);
x+=50;
}
It should print the code inside the if statement whenever 2 following buttons have the same value, but it doesn't work.
This is exactly what needs to be changed somehow
if(buttons[temp].getText()==buttons[temp+1].getText())
Thank you.
If temp=i and he just instanciated buttons[i],, then buttons[temp+1] is null at this moment. Also, when temp reaches 8, buttons[temp+1] will be out of bound (I suspect your Button array is of size 9 ?)
Plus this won't be a condition for victory, you just test if the next button is of the same value, which means:
XX-
O--
---
Will be a victory for X.
As you can see from you big if, your duplicating too much code, you can do:
/**Checks if player X or O won **/
public boolean isWinner(Button[] buttons){
return playerWins(buttons, 'X') || playerWins(buttons, 'O');
}
/**Checks if a player has 3 buttons aligned **/
private boolean playerWins(Button[] buttons, char player) {
return lineWin(buttons,player,0,1,2) ||
lineWin(buttons,player,0,3,6) ||
lineWin(buttons,player,3,4,5); //TODO add the 5 others conditions
}
/** Checks if the buttons at i,j and k belongs the player **/
private boolean buttonsBelongToPlayer(Button[] buttons, char player, int i, int j, int k) {
return buttons[i].getText()==player && buttons[j].getText()==player && buttons[k].getText()==player;
}
Strings should be compared using equals(), not ==.
So:
if(buttons[temp].getText().equals(buttons[temp+1].getText()))

Collision detection with KeyListener and scrolling background

Im having a very strange problem with my code. Im making a little game for fun, but iv run into a problem with collisions. The really strange part is, the collisions are being detected, yet nothing is happening. Here is the code:
public void keyPressed(KeyEvent e){
int key = e.getKeyCode();
int x = player.getCurX();
int y = player.getCurY();
for(int col = 0; col < X_AMOUNT; col++){
for(int row = 0; row < Y_AMOUNT; row++){
MazeBlock check = field[col][row];
if(check.getState() == false){
int cX = check.getX()-(player.backX);
int cY = check.getY()-(player.backY);
if((y <= cY+BLOCK_SIZE && y >= cY) || (y+PLAYER_WIDTH >= cY && y+PLAYER_WIDTH <= cY+BLOCK_SIZE)){ // if on same y axis
if(x+PLAYER_WIDTH >= cX && x+PLAYER_WIDTH <= cX+BLOCK_SIZE){ // if coming from left
System.out.println("is coming from left");
player.setVelX(0);
} else {
if(key == KeyEvent.VK_RIGHT|| key == KeyEvent.VK_D)
player.setVelX(1);
}
if(x <= cX+BLOCK_SIZE && x >= cX){ //if coming from right
System.out.println("is coming from right");
player.setVelX(0);
} else {
if(key == KeyEvent.VK_LEFT || key == KeyEvent.VK_A)
player.setVelX(-1);
}
}
}
}
}
if(key == KeyEvent.VK_UP || key == KeyEvent.VK_W)
player.setVelY(-1);
if(key == KeyEvent.VK_DOWN || key == KeyEvent.VK_S)
player.setVelY(1);
}
Im going to explain all of this, because it is a lot to look at.
-Variables x and y are the positions of the player.
-cX and cY are the positions of the block under it.
-player.setVelX sets the movement on the X plane. It is added to the current location of the player in order to move the player.
-the println statements show you what side the playing if coming to the block from.
-check.getState checks if the block that is being checked is a wall block
So whenever I touch a wall block, I get the correct message in the console, yet I'm still able to move around into the block. Does anybody have any ideas on how to fix it, or is it a lost cause?

Keeping track of JButtons generated in a for loop

I am working on a Java tic-tac-toe game but I'm having trouble keeping track of my JButtons because I'm using a for loop to create 9 buttons:
for(int i=0;i<button.length;i++){
button[i] = new JButton();
button[i].setText(Integer.toString(i+1));
frame.add(button[i]);
button[i].addActionListener(this);
}
I want to check if my button text matches (in rows/columns/diagonal) and if so, display that you win.
Here is all my code:
public class TicTacToe extends Board implements ActionListener{
JButton button[] = new JButton[9];
boolean win = false;
int count = 0;
String letter = "";
public TicTacToe(){
//create + add JButtons to JFrame
for(int i=0;i<button.length;i++){
button[i] = new JButton();
button[i].setText(Integer.toString(i+1));
frame.add(button[i]);
button[i].addActionListener(this);
}
}
public void actionPerformed(ActionEvent e) {
for(int i=0;i<button.length;i++){
if(i%2 == 0){
letter = "X";
}else{
letter = "O";
}
if(e.getSource() == button[i]){
button[i].setText(letter);
button[i].setEnabled(false);
count = i+1;
}
//check win
if(){ //<---------------NEED HELP HERE. THANK YOU
win = true;
JOptionPane.showMessageDialog(null, "YOU WIN");
}
}
}
}
How can I keep track of dynamically created JButtons?
The win conditions for tic tac toe are:
X - - - X - - - X
X - - or - X - or - - X
X - - - X - - - X
private boolean colWinner() {
for (int i = 0; i < 3; i++) {
String mark = button[i].getText();
if (mark.equals(button[i+3].getText()) &&
mark.equals(button[i+6].getText()) {
return true;
}
}
return false;
}
or
X X X - - - - - -
- - - or X X X or - - -
- - - - - - X X X
private boolean rowWinner() {
for (int i = 0; i < 3; i++) {
String mark = button[3*i].getText();
if (mark.equals(button[3*i+1].getText()) &&
mark.equals(button[3*i+2].getText()) {
return true;
}
}
return false;
}
or
X - - - - X
- X - or - X -
- - X X - -
private boolean diagWinner() {
String mark = button[4].getText();
return
(mark.equals(button[0].getText()) && mark.equals(button[8].getText()) ||
(mark.equals(button[2].getText()) && mark.equals(button[6].getText());
}
This naive approach checks all possible win conditions, which isn't really necessary if you are checking for wins after each turn. You only need to check the conditions for:
the row the new mark was made
the col the new mark was made
one diagonal if the mark is in a corner or both diagonals if the mark is in the center.
I'll leave it to you to figure that out.
First I will answer your question, but judging by your code (or lack thereof), I will then address some other things I think you should be aware of as a Java programmer working with Graphical User Interfaces (GUIs) and Java Swing.
Part 1: The Answer
There are two approaches I can think of to solve this.
The following code uses a two-dimensional array of pieces to represent the 3x3 board of JButtons (note sure why you don't use a 2D array, actually very confused on why you don't). Additionally, it assumed that the text of all JButtons is initially set to "." since this is much easier than checking if the text is one of 9 different string numbers.
Approach A: Static Cases
Since the board is so small, it's feasible to simply check for each of the cases where a player would win the tic tac toe game and verify if one of them is true. The following graphic illustrates the eight cases that result in a winning outcome for a player.
Note that "O" can just as easily be substituted for "X" below, the important thing is that each one belongs to the same player. Additionally, any "." marks are just placeholders, as it doesn't matter whether this actually represents "X," "O," or "null" on the board.
// Case 1
// if each location across the top row is not empty
if (board[0][0].getText() != "." && board[0][1].getText() != "." && board[0][2].getText() != ".") {
// if each location has the same text
if (board[0][0].getText() == board[0][1].getText() &&
board[0][0].getText() == board[0][2].getText()) {
// if the player is X then X is winner, else player is O and O is winner
if (board[0][0].player() == Player.X)
return Status.X_WINNER;
else if (board[0][0].player() == Player.O)
return Status.O_WINNER;
}
}
This can then be repeated seven times to achieve our goal. However, this is a lot of repetitive code, and clever programmers will attempt to avoid this when possible.
But, there's also the case of a tie or "cat's game" in tic tac toe, and how do we address this? Well, if there are no winning cases present AND the board is full of pieces, then we have a stalemate.
Approach B: Dynamic Checking
I'll admit, this method is a behemoth and I'm sure it could use some smart refactoring, but it's functional and solves the problem dynamically. There are many conditionals to try and make the algorithm more efficient by only continuing when absolutely necessary.
Note that I check the surrounding neighbors of a piece, which is critical for properly checking if a diagonal has won the game.
// track if game won
boolean won = false;
// constant for board width and height
int BOARD_SIZE = 3;
// track pieces on board
int numPieces = 0;
// track who won
String winner = "";
// loop through the board first time
for (int row1 = 0; row1 < board.length; row1++) {
for (int col1 = 0; col1 < board.length; col1++) {
// if piece exists here
if (board[row1][col1].getText() != ".") {
// increment number of pieces on board
numPieces++;
// check pieces around first piece
for (int row2 = row1 - 1; row2 <= row1 + 1; row2++) {
for (int col2 = col1 - 1; col2 <= col1 + 1; col2++) {
// ensure within bounds of board
if ((row2 >= 0 && row2 < BOARD_SIZE) && (col2 >= 0 && col2 < BOARD_SIZE)) {
// ignore checking with first piece (itself)
if (board[row2][col2] != board[row1][col1]) {
// if second piece equal to first piece
if (board[row2][col2].getText() == board[row1][col1].getText()) {
// check pieces around second piece
for (int row3 = row2 - 1; row3 <= row2 + 1; row3++) {
for (int col3 = col2 - 1; col3 <= col2 + 1; col3++) {
// ensure within bounds of board
if ((row3 >= 0 && row3 < BOARD_SIZE) && (col3 >= 0 && col3 < BOARD_SIZE)) {
// ignore checking pieces we already have
if (board[row3][col3] != board[row2][col2] && board[row3][col3] != board[row1][col1]) {
// if third piece equal to first piece (and so also equal to second)
if (board[row3][col3].getText() == board[row1][col1].getText()) {
// if three pieces are all on same row
if (row1 == row2 && row1 == row3) {
if (board[row1][col1].getText() == "X")
winner = "X";
else
winner = "O";
won = true;
break;
}
// else if three pieces are all on same column
else if (col1 == col2 && col1 == col3) {
if (board[row1][col1].getText() == "X")
winner = "X";
else
winner = "O";
won = true;
break;
}
// else if three pieces are all on different rows and columns (winning diagonal)
else if ((row1 != row2 && row1 != row3 && row2 != row3) && (col1 != col2 && col1 != col3 && col2 != col3)) {
if (board[row1][col1].getText() == "X")
winner = "X";
else
winner = "O";
won = true;
break;
}
}
}
}
}
}
}
}
}
}
}
}
}
}
if (winner == "X") {
JOptionPane.showMessageDialog(null, "X wins");
}
else if (winner == "O") {
JOptionPane.showMessageDialog(null, "O wins");
}
// if board is full and hasn't resulted in any winners
if (!won && numPieces == BOARD_SIZE * BOARD_SIZE)
JOptionPane.showMessageDialog(null, "Cats game");
Of course, less lines of code do not necessarily guarantee better performance, as we are again lucky that this is such a small board. Looping through multiple times (i.e. brute force approach) like this on a large board would spell disastrous run times, so this is another design choice to consider.
Part 2: Going Further
I don't think this can really be all your code, as your provided code can't be executed without a main method.
Additionally, if you're extending a "Board" class, you must have written your own since Java doesn't come with such a class.
Here are some things you should be aware of as a Java Swing GUI programmer.
A. Java Swing
You don't seem to have a strong grasp on Java Swing, so here's an introductory tutorial to start you off.
B. Layout Managers
Layout managers can be your friend but also your enemy when trying to configure your GUI layout. Here's a good resource for your exploration.
C. Model-View-Controller (MVC)
Decoupling dependencies is key to future management of large code bases. MVC is a popular software architectural pattern that helps reduce dependencies when dealing with user interfaces. Check this out.
D. My Implementation
You inspired me to work on my own Java Swing implementation of tic-tac-toe. Here it is!
Cheers and happy coding!

My edge collision algorithm is not working properly

if(pl.y+pl.height >= a.y && pl.x+pl.width >= a.x+1 && pl.x <= a.x+a.width-1 && pl.y<=a.y) { //TOP
colUP=true;
}
else colUP=false;
if(pl.y <= a.y+a.height && pl.x+pl.width >= a.x+1 && pl.x <= a.x+a.width-1 && pl.y+pl.height>=a.y+a.height) { //BOTTOM
colDOWN=true;
}
else colDOWN=false;
if(pl.x <= a.x+a.width && pl.x+pl.width>a.x+a.width && pl.y+pl.height >= a.y && pl.y <= a.y+a.height){ //RIGHT
colRIGHT=true;
}
else colRIGHT=false;
if(pl.x+pl.width >= a.x && pl.x<a.x && pl.y+pl.height >= a.y && pl.y <= a.y+a.height){ //LEFT
colLEFT=true;
}
else colLEFT=false;
I setup a debug that will tell me which of the 4 Booleans is being set to true, and they don't show that when I put the box 'pl' on top of box 'a' colUP is not equal to true, and they will only come true in weird instances where box 'pl' is colliding with several box 'a's , and the collision for a certain side might be true when it isn't but if colUP is true then colRIGHT is true for some reason. (This code is inside a for loop that goes through an array list of Rectangles and sets the current Rectangle equal to the variable 'a' so that a.x is the box's x position)
You have right logic but you set false for each condition separately. In reality all conditions should be true. So, use one boolean variable - isInRectangle=true; then check all conditions - left,right,top,bottom. If any is not true then isInRectangle=false;
It is simple AND logical operation for all 4 conditions.

Avoid out of bounds exception in 2D array

I'm trying to solve a problem which uses a 2D array, the problem of a rat in a maze.
While checking the conditions trying to compile, it finds an Array index out of bounds exception... how can I check the values so it doesn't go out of the array bounds?
static void solveMaze(){
int nSteps = 0; // Number of steps.
int x = 0; int y = 0; // Starting point.
boolean mazeCompleted = false;
while (!mazeCompleted){
if(x == maze.mazeMatrix.length && y == maze.mazeMatrix.length)
mazeCompleted = true;
else if(maze.mazeMatrix[x+1][y] == 0){ // Move right.
maze.mazeMatrix[x+1][y] = 2;
x++; nSteps++;
}
else if(maze.mazeMatrix[x-1][y] == 0){ // Move left.
maze.mazeMatrix[x-1][y] = 2;
x--; nSteps++;
}
else if(maze.mazeMatrix[x][y+1] == 0){ // Move down.
maze.mazeMatrix[x][y+1] = 2;
y++; nSteps++;
}
else if(maze.mazeMatrix[x][y-1] == 0){ // Move up.
maze.mazeMatrix[x][y-1] = 2;
y--; nSteps++;
}
}
maze.printMatrix();
System.out.println("Maze COMPLETE! - With a total of " + nSteps + " steps.");
}
Tried before with two "for" loops to prevent the out of bounds but I just can't go diagonal in this problem.
You have a pretty crucial bug in your program. You will never reach the end of the maze!
if(x == maze.mazeMatrix.length && y == maze.mazeMatrix.length)
references indices that are out of bounds! It should be
if(x == maze.mazeMatrix.length - 1 && y == maze.mazeMatrix.length - 1)
You also need to check to see whether you can & should move before you try to move there. I.E. :
while (!mazeCompleted){
boolean moveRight = (x + 1 < mazeMatrix.length && maze.mazeMatrix[x+1][y] == 0 ? true : false);
boolean moveLeft = (x - 1 >= 0 && maze.mazeMatrix[x-1][y] == 0 ? true : false);
boolean moveUp = (y + 1 < mazeMatrix[x].length && maze.mazeMatrix[x][y+1] == 0 ? true : false);
boolean moveDown = (y - 1 >= 0 && maze.mazeMatrix[x][y-1] == 0 ? true : false);
And:
else if(moveRight) { // Move right.
maze.mazeMatrix[x+1][y] = 2;
x++; nSteps++;
}
etc. Although it does seem like this is something that should be solved recursively, as if there are any loops in the maze you will end up getting stuck and infinite looping.

Categories