I coded this to check if someone won, but it looks like it will only check for if someone won by horizontal, any ideas to check if someone won by vertical and diagonal?
public boolean checkForVictory() {
int xInRow = 0;
int oInRow = 0;
boolean playerOneWins = false;
boolean playerTwoWins = false;
//loop through the map and check if every cell contains x or o and then add the number. If in the next cell is another character, then put it back to 0
for(int i=0; i<7; i++){
for(int j=0; j<6; j++){
if(j == 0){
xInRow = 0;
oInRow = 0;
}
if(Map.getInstance().map[i][j].contains("x")){
xInRow++;
oInRow = 0;
}
if(Map.getInstance().map[i][j].contains("o")){
oInRow++;
xInRow = 0;
}
if(xInRow == 4)
playerOneWins = true;
if(oInRow == 4)
playerTwoWins = true;
}
}
if(playerOneWins){
GameModel.getInstance().player1.playerVictory = true;
return true;
}
if(playerTwoWins){
GameModel.getInstance().player2.playerVictory = true;
return true;
}
return false;
}
Related
I am relatively new to coding and Java and for my CS-173 class, I was tasked with creating a Tic Tac Toe game. However, when it came to creating the method for determining a winner, whenever I achieved a "win", the code never ran saying I won. I do have the code to check each way to win however, I pulled it from the code in order to do some personal troubleshooting. Also, my apologies for the bad code.
public static void playGame(char[][] board, int size){
Scanner input = new Scanner(System.in);
int turn = 0;
int spaces = board.length * board.length;
boolean valid = false;
boolean winner = false;
for (int i = 0; i<spaces; i++){
int startchecker = 3;
int xcord = 0;
int ycord = 0;
do{
do{
System.out.println("Player 1 please type your coordinates with a space");
xcord = input.nextInt();
ycord = input.nextInt();
valid = isValid (board, xcord, ycord);
if(i >= spaces){
}
}while(!valid);
board[xcord][ycord] = 'X';
printBoard(board);
winner = isWinner(board);
do{
System.out.println("Player 2 please type your coordinates with a space");
xcord = input.nextInt();
ycord = input.nextInt();
valid = isValid (board, xcord, ycord);
winner = isWinner(board);
}while(!valid);
board[xcord][ycord] = 'O';
printBoard(board);
if(i >= spaces){
winner = true;
System.out.println("It is a tie!");
}
}while(!winner);
}
}
public static boolean isWinner (char[][] board){
boolean determiner = false;
int XCounter = 0;
int OCounter = 0;
int size = board.length-1;
int winner = 3;
//Check Horizontal
for(int j = 0; j > size; j++){
for(int i = 0; i > size; i++){
if(board[i][j]=='X'){
XCounter++;
}
else if(board[i][j]=='O'){
OCounter++;
}
if(XCounter == winner){
determiner = true;
System.out.println("Player 1 Wins!");
}
else if(OCounter == winner){
System.out.println("Player 2 Wins!");
determiner = true;
}
}
}
return determiner;
}
Your isWinner method does not check for all the ways to win.
I would recommend using 2 for-loops (one for horizontal lines and the other for vertical) for clarity, and 2 if-statements (outside of the loops) to check for diagonals.
For example,
for(int i=0; i<size; i++){
boolean flag = true; // Assume this line is a winning line
for(int j=0; j<size; j++){ // Check each tile to see if it has a tile
// Set the flag to false when it is not the tile you're looking for
}
}
My check vertical win and check horizontal win work perfectly fine, however i dont know what to do with my check diagonal code to make it actually check diagonal. Some guidance would be much appreciated and this is in java. Thank you.
private boolean checkVerticalWin()
{
PieceType type = myBoard[myLastPoint.x][myLastPoint.y];
System.out.println("check vert");
for(int j = 0; j < myNumColumns; j++)
{
for(int i = 0; i < myNumRows; i++)
{
if(myBoard[i][j] == type && myBoard[i][j] != null )
{
count++;
if(count == 1)
{
myWinBegin = new Point(i,j);
}
}
else
{
myWinBegin = null;
count = 0;
}
System.out.println(count);
if(count == myWinLength)
{
myWinEnd = new Point(i,j);
return true;
}
}
}
myWinBegin = null;
return false;
}
private boolean checkHorizontalWin()
{
System.out.println("test");
PieceType type = myBoard[myLastPoint.x][myLastPoint.y];
for(int i = 0; i < myNumRows; i++)
{
for(int j = 0; j < myNumColumns; j++)
{
if(myBoard[i][j] == type && myBoard[i][j] != null)
{
count++;
if (count == 1)
{
myWinBegin = new Point(i,j);
}
}
else
{
myWinBegin = null;
count = 0;
}
if(count == myWinLength)
{
myWinEnd = new Point(i,j);
return true;
}
}
}
myWinBegin = null;
return false;
}
private boolean checkDiagonalWin()
{
PieceType type = myBoard[myLastPoint.x][myLastPoint.y];
for(int i = 0; i < myNumRows; i++)
{
for (int j = 0; j < myNumColumns; j++)
{
if(myBoard[i][j] == type && myBoard[i][j] != null )
{
count++;
myWinBegin = new Point(i,j);
}
else
{
count = 0;
myWinEnd = new Point(i,j);
}
if(count == myWinLength)
{
return true;
}
}
}
for(int j = 0; j < myNumColumns; j--)
{
for (int i = 0; i < myNumRows; i--)
{
if(myBoard[i][j] == type && myBoard[i][j] != null )
{
count++;
myWinBegin = new Point(i,j);
}
else
{
count = 0;
}
if(count == myWinLength)
{
myWinEnd = new Point(i,j);
return true;
}
}
}
for(int j = 0; j < myNumColumns; j++)
{
for (int i = 0; i < myNumRows; i--)
{
if(myBoard[i][j] == type && myBoard[i][j] != null )
{
count++;
}
else
{
myWinBegin = new Point(i,j);
count = 0;
}
if(count == myWinLength)
{
myWinEnd = new Point(i,j);
return true;
}
}
}
for(int j = 0; j < myNumColumns; j--)
{
for (int i = 0; i < myNumRows; i++)
{
if(myBoard[i][j] == type && myBoard[i][j] != null )
{
count++;
myWinBegin = new Point(i,j);
}
else
{
count = 0;
}
if(count == myWinLength)
{
myWinEnd = new Point(i,j);
return true;
}
}
}
return false;
}
So basically, you need a start point, you then need to determine in which direction to move
With that idea in hand, you could use something like...
boolean win = true;
for (int count = 0; count < 4; count++) {
if (row < myNumRows && row >= 0 && col < myNumColumns && col >= 0) {
int test = myBoard[row][col];
if (test != check) {
win = false;
break;
}
} else {
break;
}
row += rowDelta;
col += colDelta;
}
As the basic algorithm. All this does is checks each cell from a start point, to a total of 4 cells, the algorithm moves by the specified delta/direction and keeps checking while each cell matches the check value.
Now, I'd wrap this in a simple method
public boolean didWin(int[][] grid, int check, int row, int col, int rowDelta, int colDelta) {
boolean win = true;
for (int count = 0; count < 4; count++) {
if (row < ROWS && row >= 0 && col < COLUMNS && col >= 0) {
int test = grid[row][col];
if (test != check) {
win = false;
break;
} else {
break;
}
}
row += rowDelta;
col += colDelta;
}
return win;
}
which makes it simpler to call, know given any point, you can do something like...
int startRow = ...;
int startCol = ...;
int player = ...;
if (didWin(myBoard, player, startRow, startCol, 1, 0) || // Vertical, down
didWin(myBoard, 1, startRow, startCol, 0, 1) || // Right
didWin(myBoard, 1, startRow, startCol, 0, -1) || // Left
didWin(myBoard, 1, startRow, startCol, 1, 1) || // Right/down
didWin(myBoard, 1, startRow, startCol, -1, -1) || // Left/Up
didWin(myBoard, 1, startRow, startCol, 1, -1) || // Down/Left
didWin(myBoard, 1, startRow, startCol, -1, 1) // Up/Right
) {
// You be the winner
}
nb: I've left out check a vertical up direction, because it's unlikely that you could actually win this way
ps: I'd be even more lazy and would just have a didWin method, which did the above checks and returned true or false, but I'm lazy
So, the startRow and startCol would represent the anchor point around which you want to check and would, in this example, represent the last drop.
This example uses a int to represent the player/token, but you could use anything, all this does is compares the token you supply with the values in the array
This is a class that creates the game connect four in console and drawing panel, and I am having trouble in the connectedFour method where it determines if someone has gotten 4 discs in a row. The problem is, is that I am not sure how to set up my for loops to check through the array for four discs in a row
Here is my code:
import java.util.*;
import java.awt.*;
public class ConnectFour{
public static void main(String[] args){
//board
DrawingPanel panel = new DrawingPanel(550,550);
int rowAvailable;
Graphics g = panel.getGraphics();
g.drawLine(0,0,0,500);
g.drawLine(0,0,500,0);
g.drawLine(500,0,500,427);
g.drawLine(0,427,500,427);
for(int i = 0; i< 6; i++){
for(int j= 0; j<= 6; j++){
g.setColor(Color.YELLOW);
g.fillRect(j*71,i*71,71,71);
g.setColor(Color.WHITE);
g.fillOval(j*71,i*71,71,71);
}
}
//setBlankArray
Scanner console = new Scanner(System.in);
char[][] board = new char[6][7];
for(int j = 0;j <= 6; j++){
for(int i= 0; i < 6; i++){
board[i][j] = ' ';
}
}
boolean isBlack = true;
boolean isRed = false;
int column = 0;
boolean playersTurn = true;
boolean rightNum = false;
//oneTurn
while(getWinner(board, playersTurn)){
//while(playersTurn == true){
rightNum = false;
if(isBlack == true){
// displayCurrentPlayer
System.out.println("Black's Turn");
g.setColor(Color.WHITE);
g.drawString("Red Disc's Turn",200, 450);
g.setColor(Color.BLACK);
g.drawString("Black Disc's Turn",200, 450);
}
else{
// displayCurrentPlayer
System.out.println("Red's Turn");
g.setColor(Color.WHITE);
g.drawString("Black Disc's Turn",200, 450);
g.setColor(Color.RED);
g.drawString("Red Disc's Turn",200, 450);
}
System.out.print("Choose a column to place your disk (1-7): ");
while(rightNum == false){
column = (console.nextInt()) -1;
if(column >= 0 && column < 7 && board[0][column] == ' '){
rightNum = true;
}
else{
System.out.print("Try again: ");
}
}
drawBoard(column, board, isBlack, isRed, board, g);
isBlack = !isBlack;
}
if(isBlack == false){System.out.println("Congratulations Black Player");}
else{System.out.println("Congratulations Red Player");}
// use the while loop to say try again if the column is filled.
}
public static void drawBoard(int column, char[][] board, boolean isBlack, boolean isRed, char[][] availability,Graphics g){
char player = ' ';
if(isBlack == true){
g.setColor(Color.BLACK);
player = 'b';
}
else{
g.setColor(Color.RED);
player = 'r';
}
int x = 0;
int row = 5;
while(board[row-x][column] != ' '){
x++;
}
row = row-x;
g.fillOval((column * 71),(row * 71), 71,71);
board[row][column] = player;
}
public static boolean getWinner(char[][] board, boolean playersTurn){
int verticalCount = 0;
boolean isVertical = false;
for(int i = 6; i >= 0; i--){
verticalCount = 0;
for(int j = 5; j > 0; j--){
if(board[j][i] == board[j-1][i] && board[j][i] != ' '){
verticalCount++;
}
if(verticalCount == 4){
isVertical = true;
}
}
}
int horizontalCount = 0;
boolean isHorizontal = false;
for(int i =1; i <= 5; i++){
for(int j =1; j<6; j++){
if(board[j][i] == board[j][i+1] && board[j][i] != ' '){
horizontalCount++;
}
if(horizontalCount == 3){
isHorizontal = true;
}
}
}
int diagonalCount = 0;
boolean isDiagonal = false;
// for(int i = 0; i<=6; i++){
// for(int j =0; j<6; j++){
// if(board[i][j-1] == board[i][j]){
// diagonalCount++;
// }
// }
// }
if(isVertical || isHorizontal || isDiagonal){
playersTurn = false;
}
else{
playersTurn = true;}
return playersTurn;
}
}
I would implement this by checking if the game-winning condition is met after a disc has been placed. This way you aren't iterating over the entire board after each move.
Regardless, try this:
replace
while (gameWon == false ){
with
while (!connectedFour(board, playersTurn)) {
I don't think this will completely fix your problems as it looks like there are a handful of other things wrong with the code you've posted.
I've tried to create a Tic Tac Toe game class with the play and hasWon methods.
public class TicTacToe {
private enum State{Blank, X, O}
private int grid;
private State[][] board = new State[grid][grid];
private int moves;
//Default Constructor
public TicTacToe(int grid){
board = new State[grid][grid];
moves = 0;
}
public void play(State s, int m, int n){
if (board[m][n] == State.Blank){
board[m][n] = s;
}
moves++;
}
public boolean hasWon(State[][] board){
//check winner in rows
boolean state = false;
int j = 0;
int i = 0;
while(j <= grid) {
for (i = 0; i <= grid; i++) {
if (board[j][i] == board[j][i + 1])
state = true;
else state = false;
break;
}
if(state == false)
j++;
else return true;
}
//check winner in columns
while(j <= grid) {
for (i = 0; i < grid; i++) {
if (board[i][j] == board[i + 1][j])
state = true;
else state = false;
break;
}
if (state == true)
j++;
else return true;
}
//check winner in top diagonal
while(j <= grid && i <= grid){
if (board[i][j] == board[i+1][j+1])
state = true;
else state = false;
break;
i++;
j++;
return true;
}
//check winner in bottom diagonal
int k = grid;
int l = grid;
while(k >= 0 && l >= 0){
if (board[k][l] == board[k-1][l-1])
state = true;
else state = false;
break;
k--;
l--;
return true;
}
return false;
}
}
However when called in the Main class the program behaves erratically. Is there a logical problem in the code.
When checking your rows with
for (i = 0; i < n; i++) {
if (board[j][i] == board[j][i + 1])
state = true;
}
this code always sets the state to true if the last two chars in the row are the same, independently of the chars previous in that row.
The same thing for columns and the diagonal (of which you are checking only as Todd said).
You want to stop comparing values for that row if you find some values that are not equal:
for (i = 0; i < n; i++) {
if (board[j][i] == board[j][i + 1]) {
state = true;
} else {
state = false;
break;
}
}
Same for rows and diagonal(s).
Edit:
Furthermore: You are not setting your field grid in the constructor, so it always is 0 and you are not checking your complete rows, columns, diagonals
Missing:
this.grid = grid;
This is a movie ticket theatre seller program. The task is create a method that takes the price of the user's input, finds the first seat and replaces it with a 0, denoting a sold seat. I keep fiddling with it but it keeps wanting to change all instances of the price input to 0 instead of the first found.
public boolean getByPrice(int price) {
boolean retVal = false; //initially false, have not found
System.out.println("You chose to buy a ticket with price: $" + price);
if (price == 10) {
for (int i = 0;i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS; j++) {
if (seats[i][j] == 10) {
retVal = true;
seats[i][j] = 0;
}
pricesAvailable[0] = pricesAvailable[0] - 1;
}
}
}
if (price == 20) {
for (int i = 0; i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS;j++) {
if (seats[i][j] == 20) {
retVal = true;
seats[i][j] = 0;
}
pricesAvailable[1] = pricesAvailable[1] - 1;
}
}
}
if (price == 30) {
for (int i = 0; i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS; j++) {
if (seats[i][j] == 30) {
retVal = true;
seats[i][j] = 0;
}
pricesAvailable[2] = pricesAvailable[2] - 1;
}
}
}
if (price == 40) {
for (int i = 0; i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS;j++) {
if (seats[i][j] == 20) {
retVal = true;
seats[i][j] = 0;
}
pricesAvailable[3] = pricesAvailable[3] - 1;
}
}
}
if (price == 50) {
for (int i = 0; i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS;j++) {
if (seats[i][j] == 50) {
retVal = true;
price = 0;
}
pricesAvailable[4] = pricesAvailable[4] - 1;
}
}
}
return retVal;
}
Also, the other part is to implement the same type of method using location
public boolean getByLoc(int row, int col) {
boolean retVal = false; //initially false
System.out.println("You chose row: " + row + ", col: " + col);
//************YOUR SOLUTION GOES HERE************//
for (int i = 0;i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS; j++) {
}
}
return retVal; //return value
}
I am not sure how use to make the location method work at all
Your loop does not exit when you found a seat. You could use break like:
for (int i = 0; i<NUM_ROWS && !retVal; i++){
for (int j = 0; j<NUM_COLS && !retVal; j++){
if (seats[i][j] == 10){
retVal = true;
seats[i][j] = 0;
break;
}
}
if (retVal) break;
}
or you could add a condition to your loops like:
for (int i = 0; i<NUM_ROWS && !retVal; i++){
for (int j = 0; j<NUM_COLS && !retVal; j++){
...
}
}
I would also recomend to reduce the code duplication by having the same loop in multiple ifs. How about summarizing it like this? (I assumed the pricesAvailable should only be lowerd when a seat has been found)
if (price == 0) { throw new IllegalArgumentException("Not giving away freebies"); }
for (int i = 0; i<NUM_ROWS && !retVal; i++){
for (int j = 0; j<NUM_COLS && !retVal; j++){
if (seats[i][j] == price){
retVal = true;
seats[i][j] = 0;
pricesAvailable[(price/10)-1]--;
}
}
}
Edit: Of couse returning inside the loops would also work if this is all you want to do in this method:
if (price == 0) { throw new IllegalArgumentException("Not giving away freebies"); }
for (int i = 0; i<NUM_ROWS; i++){
for (int j = 0; j<NUM_COLS; j++){
if (seats[i][j] == price){
seats[i][j] = 0;
pricesAvailable[(price/10)-1]--;
return true;
}
}
}
return false;
You'll probably want to utilise a break; somewhere if you intend to keep your code as it is.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html
http://www.c4learn.com/java/java-break-statement/
You need to break the for-loop when you have found a matching seat, otherwise it will continue to check all the other seats.
You have two nested loops, but you want to break out of both. There are a few ways to do this, but as this is relatively simple code, a label will suffice. Take a look at http://docs.oracle.com/javase/tutorial/java/nutsandbolts/branch.html.
As the comments have pointed out, this is obviously homework, so I won't post a full code listing, instead, here is a snippet:
rows:
for (int i = 0; i < NUM_ROWS; i++)
{
cols:
for (int j = 0; j < NUM_COLS; j++)
{
if (seats[i][j] == 30)
{
retVal = true;
seats[i][j] = 0;
}
pricesAvailable[2] = pricesAvailable[2] - 1;
break rows;
}
}
Also, please use braces around if-statements, it's just another way to introduce bugs.
That is because you keep looping even after you have found the first seat with that price. The best thing here would be to use a method, like below, and return after you're done with the first one. This will solve both your refactoring problems and your incorrect values:
public boolean findFirst(int cost){
for (int i = 0;i<NUM_ROWS;i++)
for (int j = 0; j<NUM_COLS; j++)
if (seats[i][j] == cost){
seats[i][j] = 0;
pricesAvailable[cost / 10 - 1] -= 1;
return true;
}
return false;
}
Then call it from your getByPrice function like this:
public boolean getByPrice(int price) {
boolean retVal = false; //initially false, have not found
System.out.println("You chose to buy a ticket with price: $" + price);
if (price == 10)
retval = findFirst(10);
//rest of the code...
You should break the loop as soon as the place is found. Otherwise you'll put 0 on all places that have the price == 10.
if (price == 10) {
for (int i = 0;i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS; j++) {
if (seats[i][j] == 10) {
retVal = true;
seats[i][j] = 0; //and here break/return.
}
pricesAvailable[0] = pricesAvailable[0] - 1;
}
}
}
Also your basically copying the same code 5 times. What if there were 100 different prices? Whould you copy that code 100 times?
You should consider putting the code that is duplicated inside a method and the variable part (price in this example) should be an input parameter.
Moreover variable pricesAvailable is quite problematic. First it's not named the best way. Maybe seatsAvailableAtPrice would sound better? And I don't think that array is the best container for that - you should try using Map where first integer would be the price, and the second would be the number of seats left for that price.
Map<Integer, Integer> seatsAvailableAtPrice = new HashMap<Integer, Integer>();
Putting it all together you could create a method like that:
private void reserveFirstAvailableSeatForPrice(final int price) {
for (int i = 0;i<NUM_ROWS;i++) {
for (int j = 0; j<NUM_COLS; j++) {
if (seats[i][j] == price) {
seats[i][j] = 0;
seatsAvailableAtPrice.put(price, seatsAvailableAtPrice.get(price) - 1);
return;
}
}
}
}
As for the second part - isn't that just checking if i=row and j=col? And if so making a reservation (setting price to 0)?