I currently developing a Chess Game in java using the eclipse IDE,
I Have all the movement of the pieces down apart from the Pawn which is the hardest because the Pawn has to be able to make to different moves
The Pawn should be able to move twice at the start and then only one after that
Currently I have set the pawn to only move twice but I am stuck on getting the rest of the logic to work
I have been working with the idea of an if/else statement
I could use some help writing it
Here is the Code so far for the Pawn and I have included comment's for your use
Update to Problem it is only with the black pawn is not moving right I was able to set the white one the right way but not the black I dont know why it doesnt work
//Pawn Movement
private boolean isValidPawnMove(int sourceRow, int sourceColumn, int targetRow, int targetColumn) {
boolean isValid = false;
if( isTargetLocationFree() ){
if( sourceColumn == targetColumn){
if( sourcePiece.getColor() == Piece.COLOR_WHITE ){
// White Pawn
if( sourceRow+1 == targetRow || sourceRow == 1 && targetRow == 3){//Pawns can move to at the start then only 1 after that
isValid = true;
}else{
isValid = false;
}
}
else{
// Black Pawn
if( sourceRow-1 == targetRow || sourceRow == -1 && targetRow == -3){
isValid = true;
}else{
isValid = false;
}
}
}else{
//If you try to move left or right into a different Column
isValid = false;
}
//Take square occupied by an opponent’s piece, which is diagonally in front
}else if( isTargetLocationCaptureable() ){
if( sourceColumn+1 == targetColumn || sourceColumn-1 == targetColumn){
//One column to the right or left
if( sourcePiece.getColor() == Piece.COLOR_WHITE ){
//White Piece
if( sourceRow+1 == targetRow ){
//Move one up
isValid = true;
}else{
//Not moving one up
isValid = false;
}
}else{
//Black Piece
if( sourceRow-1 == targetRow ){
//Move one down
isValid = true;
}else{
//Not moving one down
isValid = false;
}
}
}else{
//Not one column to the left or right
isValid = false;
}
}
return isValid;
}
Thanks for any help you can provide
I think the easiest solution is to explicitly check the source and target rows as white pawns can only move two forward from the second rank, so your logic becomes (for white):
if( sourceRow+1 == targetRow || sourceRow == 2 && targetRow == 4) {
Obviously you will also need to check that (sourceColumn, 3) is also empty.
In your class for the pawns, you can have an instance boolean, say,
boolean hasMoved
and initially make it false. If this boolean is false, then the pawn can move one OR two units. Whenever you move a pawn, you check this boolean, and if it's false, set it to true after moving it. That should work out.
In chess a pawn can choose if it wants to go one or two squares forward if it has never moved and therefore still stands on the second row. You have to ask, if it's on the second row and the two squares in front of it are empty and not only the "target location".
if( sourcePiece.getColor() == Piece.COLOR_WHITE ){
// White Pawn
if( sourceRow+1 == targetRow ){
isValid = true;
} else if (sourceRow+2 == targetRow && sourceRow == ROW_2) {
if ((isFreeSquare(sourceColumn+1) && isFreeSquare(sourceColumn+2)) {
isValid = true;
} else {
isValid = false;
}
} else {
isValid = false;
}
}
else{
// Black Pawn
...
}
You can leave the isFreeSquare(sourceColumn+2) code because you asked it with isTargetLocationFree() already. For black you have to ask if the pawn is still on ROW_7.
Related
So I've searched on overflow for about 30min now and I can't find anything that I think would've helped me. So here I am.
I'm doing a maze algorithm basically and working on this recursive method but idk if what I'm doing works. Sounds stupid ik...it won't display the maze with the arrows(directions) on my displayer for one, two apparently I need to "pass a coordinate next to it (say, the above cell, for example)" and I need to code it this way somehow. Here is my method.
private boolean findPath(char[][] maze, int r, int c) {
// Base Case #1: If Current Cell == 'H'
if(maze[r][c] == 'H') {
return true; // Stop Recursion, Conclusion: Path Found from 'G' to 'H'
}
// Base Case #2: If Current Cell == '#' (Wall)
else if(maze[r][c] == '#') {
return false; // Stop Recursion, Conclusion: Path NOT Found
}
// Base Case #3: If Current Cell == '.' (Blocked Path/Dead End)
else if(maze[r][c] == '.') {
return false; // Stop Recursion, Conclusion: Path NOT Found
}
// Recursive Cases:
if(maze[r][c] == ' ') { // Check If Current Cell == ' '
maze[r][c] = '^'; // If Yes, Place Symbol
findPath(maze, r-1, c); // Recursively Go Up
// code here ???? add missing code??? HELP MEEEE
if(maze[r][c] == 'H') { // Check If We Have Reached The End
return true; // If Yes, Return True
}
}
// Viewing Purposes
for (int x = 0; x < maze.length; x++) { // Go Through Rows
display.newLine(); // Viewing Purposes
for (int y = 0; y < maze[x].length; y++) { // Go Through Columns
display.writeC(maze[x][y]); // Viewing Purposes
}
}
return false; // If End of Method Reached. Therefore, Hansel Hasn't Been Found Yet
}
A very important thing to do when writing a recursive method is if the method returns a value, make use of the return value returned by the recursive call. If you are not making use of it, like you are doing here:
if(maze[r][c] == ' ') { // Check If Current Cell == ' '
maze[r][c] = '^'; // If Yes, Place Symbol
// you are discarding the return value here!
findPath(maze, r-1, c); // Recursively Go Up
Then you are probably going something wrong.
The return value of findPath tells you whether a path can be found from a certain position. You can make use of this information. If a path can be found by going up, then you know you've marked the right path, and can return true. If a path can't be found by going up, then you know that going up isn't the right direction, so you check another direction. If after checking all directions, and you still haven't found a path, you know that you are on the wrong path, so you set maze[r][c] back to ' ' and return false.
private static boolean findPath(char[][] maze, int r, int c) {
// Base Case #1: If Current Cell == 'H'
if(maze[r][c] == 'H') {
return true; // Stop Recursion, Conclusion: Path Found from 'G' to 'H'
}
// (Your other base cases are covered by the last "return false" statement)
// Recursive Cases:
if(maze[r][c] == ' ') { // Check If Current Cell == ' '
maze[r][c] = '^';
if (findPath(maze, r-1, c)) {
return true;
}
maze[r][c] = 'v';
if (findPath(maze, r+1, c)) {
return true;
}
maze[r][c] = '>';
if (findPath(maze, r, c+1)) {
return true;
}
maze[r][c] = '<';
if (findPath(maze, r, c-1)) {
return true;
}
maze[r][c] = ' ';
}
return false; // If End of Method Reached. Therefore, Hansel Hasn't Been Found Yet
}
Example usage:
char[][] maze = {
"#####H#####".toCharArray(),
"#G# # # # #".toCharArray(),
"# # # # # #".toCharArray(),
"# # # # # #".toCharArray(),
"# #".toCharArray(),
"###########".toCharArray(),
};
boolean hasPath = findPath(maze, 1, 1);
System.out.println(hasPath);
for (char[] row : maze) {
System.out.println(row);
}
Output:
true
#####H#####
#v# #^# # #
#v# #^# # #
#v# #^# # #
#>>>>^ #
###########
Note that my code assumes that the maze has walls or H all around. If your maze doesn't have that, you need to check that c and r are within the bounds of the 2D array first. If they are out of bounds, you should return false.
So I'm writing a program to make a robot explore a maze to find a specified cavern. There are four types of Cells: Cavern, Start, Wall, and Passage. Robots can only move to a passage or a cavern. I implemented my method so that a robot can't move to a visited cell or go out of bounds. But once it moves to a cell where there isn't a valid adjacent cell, the program stops. So how do I make my robot backtrace to where there is a valid cell? I'm using a recursion for this. Below is my code. Any help will be great. Thank you!
public void explore (Cell cavern, Maze maze) throws InterruptedException {
// for debugging
System.out.println(row + " " + col);
System.out.println(cavern.getRow() + " " + cavern.getCol());
System.out.println(visited.toString());
TimeUnit.MILLISECONDS.sleep(10); // delay program
//base case
if (row == cavern.getRow() && col == cavern.getCol()) {
foundCavern = true;
return;
}
else {
// move right
if ((col+1) < maze.getNumCols() && !visited.contains(maze.getCell(row, col+1)) && (maze.getCell(row, col+1).isPassage() || maze.getCell(row, col+1).isCavern())) {
visited.add(maze.getCell(row, col+1));
setRobotLocation(row,col+1);
explore(cavern, maze);
}
// move down
else if ((row+1) < maze.getNumRows() && !visited.contains(maze.getCell(row+1, col)) && (maze.getCell(row+1, col).isPassage() || maze.getCell(row+1, col).isCavern())) {
visited.add(maze.getCell(row+1, col));
setRobotLocation(row+1,col);
explore(cavern, maze);
}
// move left
else if ((col-1) >= 0 && !visited.contains(maze.getCell(row, col-1)) && (maze.getCell(row, col-1).isPassage() || maze.getCell(row, col-1).isCavern())) {
visited.add(maze.getCell(row, col-1));
setRobotLocation(row,col-1);
explore(cavern, maze);
}
// move up
else if ((row-1) >= 0 && !visited.contains(maze.getCell(row-1, col)) && (maze.getCell(row-1, col).isPassage() || maze.getCell(row-1, col).isCavern())) {
visited.add(maze.getCell(row-1, col));
setRobotLocation(row-1,col);
explore(cavern, maze);
}
else {
foundCavern = false;
return;
}
}
}
I think you are in the right direction.
What I think you should do is keep checking for all direction unless you found the cavern.
Right now you are checking for only one direction in each iteration because of the else clause. So when the call to explore returns you can't keep checking a different direction and essentially you don't backtrack.
If you make your explore function return a Boolean field indicating whether you reached the cavern changing your code like this may work:
// move right
if ... // your condition to check if moving right is possible and you didn't visit
// code to move right
found = explore()
//move down if didn't find cavern
if (!found) // and moving down is possible and didn't visit
// code to move down
found = explore()
// keep checking other directions
i am developing a chessgame and have been able to made my Pawn piece move both one and two squares forward but i am having difficulty preventing it from moving two squares forward after its first move. Please i will be grateful if someone can help me with a logic or idea on how to implement it.
Here is my code:
private boolean isValidPawnMove(int sourceRow, int sourceColumn, int targetRow, int
targetColumn) {
boolean isValid = false;
if(isTargetLocationFree()){
if(sourceColumn == targetColumn){
//same column
if(sourcePiece.getColor() == Piece.YELLOW_COLOR){
//yellow
if(sourceRow + 1 == targetRow ){
//move one up
isValid = true;
}else if(sourceRow + 2 == targetRow ){
isValid = true;
}else{
//not moving one up
isValid = false;
}
}else{
//brown
if(sourceRow - 1 == targetRow){
//move one down
isValid = true;
}else if(sourceRow - 2 == targetRow){
isValid = true;
}else{
//not moving one down
isValid = false;
}
}
}else{
//not the same column
isValid = false;
}
}else if(isTargetLocationCaptureable()){
if(sourceColumn + 1 == targetColumn || sourceColumn - 1 == targetColumn ){
//one column to the right or left
if(sourcePiece.getColor() == Piece.YELLOW_COLOR){
//yellow
if(sourceRow + 1 == targetRow){
//move one up
isValid = true;
}else{
//not moving one up
isValid = false;
}
}else{
//brown
if(sourceRow - 1 == targetRow ){
//move one down
isValid = true;
}else{
//not moving one down
isValid = false;
}
}
}else{
//One column to the left or right
isValid = false;
}
}
return isValid;
}
private boolean isTargetLocationCaptureable(){
if(targetPiece == null){
return false;
}else if( targetPiece.getColor() != sourcePiece.getColor()){
return true;
}else{
return false;
}
}
private boolean isTargetLocationFree(){
return targetPiece == null;
}
I won't write the code for you, but your condition should be based on the sourceRow.
If your source row is the original row the pawn started on (second or seventh row, depending on which player), only then can the pawn move two rows.
For yellow pieces, just check that sourceRow is 1 (or 2, depending on how you are numbering rows):
...
}else if(sourceRow == 1 && targetRow == 3){
// double-row first move
isValid = true;
}else{
...
Do a similar thing for the brown pieces.
Assuming you have a class for your Pawn, then you should create a field in the class called firstmove or numMoves. This would be set to true or 0 respectively, and after the first move set to false or numMoves++. Then, in your validity checker, you can say
if p.firstMove
//accept 1 or 2
else
//accept only 1
I'd do it one of two ways:
Check if the pawn is in the row it starts in. If it is, allow 2-space moves, otherwise, don't.
Give each pawn a boolean that is false if it hasn't been moved, and true if it has, than check that. (Wouldn't recommend this as it doesn't seem you're making Pawn an object so it'd be very difficult to implement)
I been having some issues checking poker hands. So in this code we choose how many decks we want to play with and then the rest is like video poker. My issue is that some of the hands checked are "seen". For the straight, I assume because I have it set as though my arraylist is sorted by assumption, how would I fix that?
Also, for two pair, my friend said that a few times it would not properly check if I actually had the two pair, saying it wasn't checking correctly. Here are my check algorithms, can anyone tell me how to fix them? Also, if there are any problems you see besides the straight and two pair having issues. I haven't hit full house or greater yet to test. The .get(#) gets the card suit or rank (getsuit or getrank) from my hand (arraylist). I also think my royal flush may be incorrect.
private boolean flush(){
if (currentHand.get(0).getSuit() == currentHand.get(1).getSuit()
&& currentHand.get(1).getSuit() == currentHand.get(2).getSuit()
&& currentHand.get(2).getSuit() == currentHand.get(3).getSuit()
&& currentHand.get(3).getSuit() == currentHand.get(4).getSuit()){
return true;
}
return false;
}
private boolean royal(){
if ((currentHand.get(0).getRank() == 1)
&& (currentHand.get(1).getRank() == 10)
&& (currentHand.get(2).getRank() == 11)
&& (currentHand.get(3).getRank() == 12)
&& (currentHand.get(4).getRank() == 13)) {
return true;
}
return false;
}
private boolean straight(){//look up
if (currentHand.get(0).getRank() + 1 == currentHand.get(1).getRank()
&& currentHand.get(1).getRank() + 1 == currentHand.get(2).getRank()
&& currentHand.get(2).getRank() + 1 == currentHand.get(3).getRank()
&& currentHand.get(3).getRank() + 1 == currentHand.get(4).getRank()) {
return true;
}
return false;
}
private boolean four(){
if (currentHand.get(0).getRank() == currentHand.get(1).getRank()
&& currentHand.get(1).getRank() == currentHand.get(2).getRank()
&& currentHand.get(2).getRank() == currentHand.get(3).getRank()) {
return true;
} else if (currentHand.get(1).getRank() == currentHand.get(2).getRank()
&& currentHand.get(2).getRank() == currentHand.get(3).getRank()
&& currentHand.get(3).getRank() == currentHand.get(4).getRank()) {
return true;
}
return false;
}
private boolean fullHouse() {
if (currentHand.get(0).getRank() == currentHand.get(1).getRank()
&& currentHand.get(1).getRank() == currentHand.get(2).getRank()) {
if (currentHand.get(3).getRank() == currentHand.get(4).getRank()) {
return true;
}
}else if(currentHand.get(0).getRank() == currentHand.get(1).getRank()){
if(currentHand.get(2).getRank() == currentHand.get(3).getRank()
&& currentHand.get(3).getRank() == currentHand.get(4).getRank()){
return true;
}
}
return false;
}
private boolean threeOfKind(){
if ((currentHand.get(0).getRank() == currentHand.get(1).getRank()
&& currentHand.get(1).getRank() == currentHand.get(2).getRank())
|| (currentHand.get(1).getRank() == currentHand.get(2).getRank()
&& currentHand.get(2).getRank() == currentHand.get(3).getRank())
|| (currentHand.get(2).getRank() == currentHand.get(3).getRank()
&& currentHand.get(3).getRank() == currentHand.get(4).getRank())){
return true;
}
return false;
}
private boolean twoPair() {
if (currentHand.get(0).getRank() == currentHand.get(1).getRank()
&& currentHand.get(2).getRank() == currentHand.get(3).getRank()){
return true;
}
else if((currentHand.get(1).getRank() == currentHand.get(2).getRank())&&
(currentHand.get(3).getRank() == currentHand.get(4).getRank())){
return true;
}
else if((currentHand.get(0).getRank() == currentHand.get(1).getRank())&&
(currentHand.get(3).getRank() == currentHand.get(4).getRank())){
return true;
}else
return false;
}
private boolean jackOrBetter() {
for (int i = 11; i <= 14; i++) {
int comp;
if (i == 14)
comp =1;
else comp = i;
for (int j = 0; j < 4; j++) {
if (currentHand.get(j).getRank() ==comp ) {
if (currentHand.get(j).getRank() == currentHand.get(j + 1).getRank()) {
return true;
}
}
}
}
return false;
Typically the kind of code you'll find in the known (and very fast) poker evaluators are much lower-level than that: no fancy OO or anything like that. Just plain fast bit manipulation and crazy, crazy fast table lookups. The fast hand evaluators out there can evaluate hundreds of millions (!) of hands... Per second! But let's leave that aside and start from your OOish code.
I take it you want a five cards evaluator and then if you play, say, Texas Hold'em then you're going to test the C(7,5), which gives 21, possible ways to take 5 cards out of seven (5 on the board + 2 holecards). And keep the best hand.
So on to your five-cards evaluator.
A "trick" is simplify your job by keeping intermediate information. Your logic is then greatly simplified.
Here's one way you could do it (once again: this is an over-simplification compared to real fast evaluators but it should help you get the job done):
final boolean isFlush = flush();
final int[] nbPerRank = findNumberForEachRank();
final boolean isStraight = straight( nbPerRank );
Where the nbPerRank array for, say, "Queens full of five" (three queens and two fives) may look like this:
; 2 3 4 5 6 7 8 9 T J Q K A
int[] nbPerRank = [ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0 ]
Then your main method shall look a bit like this:
if ( isStraight ) {
final int highCard = findStraightHighCard();
if ( isFlush ) {
if ( highCard == 13 ) { // starting with the 'A'
System.out.println( "You have a royal flush" );
else if ( highCard = 4 ) { // starting with the '5'
System.out.println( "You have a wheel straight flush" );
} else {
System.out.println( "You have a straight flush " );
}
} else {
... // rinse and repeat for normal straight
}
} else {
...
Note that seen that your evaluator is a 5 card evaluator, once you have a straight you know there are only two possible cases: straight and straight flush (with five cards, it is impossible to have even a pair if you already have a straight with these five cards).
So by now you already have taken the straight flush and the straight into account, you now need to check, in order, for :
four of a kind
full house / boat
flush (but not straight flush anymore)
set
two pairs
one pair
To check if you have four of kind you then see if you have the number 4 in your nbPerRank int array.
Pseudo-code could be like this:
// no need to test for straight an straight flush anymore...
if ( hasFourSameRank ) {
" You have four of a kind ";
} else if ( hasThreeSameRank && hasTwoSameRank ) {
" You have a full house ";
} else if ( isFlush ) {
" You have a flush";
} else if ( hasThreeSameRank ) {
" You have a set ";
} else if ( hasTwoSameRank ) {
// two possible cases here: two pairs or one pair
if ( hasTwoPairs ) {
"You have two pairs";
} else {
"You have one pair";
} else {
"You have no pair";
}
The nested if / else are quite normal in such evaluators (at least the ones not using lookup tables / LUT).
Note that this is just one way to do it. You can go "fancier" and instead of returning simply an int[] containing the number of each card per rank you can also return the max card, the max number of similar rank, etc.
You'll then have to find a way to assign a value (hence the "evaluator" name) for each hand, so that "two pairs, eights and deuces, kicker jack" beats "two pairs, eights and deuces, kicker nine" etc.
But this should get you started.
Another solution would be to simply reuse one of the existing evaluator out there (which, in addition to be tried and tested, shall be really fast: it's only bit manipulation and lookup tables, no slow OO).
(slightly related) you may also want to read my old answer here: On Two Plus Two poker hand evaluator, how do you get the best 5 cards combination out of the 7 that you passed to it?
I have the following code. The only problem is that we run it through a checkstyle program and it comes up with the error Cyclomatic Complexity is 11 (max allowed is 10). I would like to know how can remove one of the if statement to make it do the same thing and let the program pass the test.
/**
* Check if there is a winner on the board
* #return the winner if BLANK there is no winner
**/
public char checkWinner(){
this.winner = BLANK;
int totalTiles = GRIDSIZE*GRIDSIZE;
//Check if the game has a win
for (int i=0; i < GRIDSIZE; i++) {
if((grid[i][0] == grid[i][1]) && (grid[i][1] == grid[i][2])){
winner = grid[i][0];
return winner;
}
if((grid[0][i] == grid[1][i]) && (grid[1][i] == grid[2][i])){
winner = grid[0][i];
return winner;
}
}
if((grid[0][0] == grid[1][1]) && (grid[1][1] == grid[2][2])){
winner = grid[0][0];
return winner;
}
if((grid[0][2] == grid[1][1]) && (grid[1][1] == grid[2][0])){
winner = grid[0][2];
return winner;
}
//Check if the game is a tie
if (movesMade == totalTiles){
winner = TIE;
}
return winner;
}
I don't know how the checker works but how about this:
if(((grid[0][0] == grid[1][1]) && (grid[1][1] == grid[2][2])) ||
((grid[0][2] == grid[1][1]) && (grid[1][1] == grid[2][0]))) {
winner = grid[1][1];
return winner;
}
If this does work, the irony of course is that this seems a little less readable than your code.
You could extract methods for checking rows and column and rewrite your code something like this:
public char checkWinner()
{
for (int i=0; i < GRIDSIZE; i++) {
if (checkRow(i)) return winner;
if (checkColumn(i)) return winner;
}
if (checkDiagTopLeft()) return winner;
if (checkDiagBottomLeft()) return winner;
}
Easier to read and less complexity.
Side note: Obviously, the winner stuff could use a redesign, but that was not part of the question and is left as an exercise for the reader (and commenters) if they feel like it.
The solution is already up there (combining the if statements), but I would not let Cyclomatic Complexity dictate my coding if the code of a method fits on a single page. The measure you want to aim for in a big project is readability and ease of understanding. Remember that code will be written potentially only once, but read quite a few times.
The first step can be to remove some redundancy from the equal expression. The allEqual makes the intent a bit clearer.
Assinging the winner to a field is strange. I've removed that in the refactoring. If you really need the assignment you could do it in a separate method calling checkWinner. The problem with returning and assigning is that it's unexpected for a caller to have this side effect.
public char checkWinner() {
// Check if the game has a win
for (int i = 0; i < GRIDSIZE; i++) {
if (allEqual(grid[i][0], grid[i][1], grid[i][2])) return grid[i][0];
if (allEqual(grid[0][i], grid[1][i], grid[2][i])) return grid[0][i];
}
if (allEqual(grid[0][0], grid[1][1], grid[2][2])) return grid[0][0];
if (allEqual(grid[0][2], grid[1][1], grid[2][0])) return grid[0][2];
// Check if the game is a tie
int totalTiles = GRIDSIZE * GRIDSIZE;
return movesMade == totalTiles ? TIE : BLACK;
}
private boolean allEqual(char... c) {
for(int i=1;i<c.length;i++) if(c[i-1] != c[i]) return false;
return true;
}
Open Problems:
The char[][] array is not the most efficient data structure to represent the board. You could use a BitSet.
You defined GRIDSIZE constant but you're could would break down if you actually changed it from 3 to another value.
You can use the fact that checking row/columns and diagonals is symmetric. The parameters have to be transposed use this.
Using the GRIDSIZE constant you do not have to address all cells explicitly:
public char checkWinner() {
// Check if the game has a win
for (int i = 0; i < GRIDSIZE; i++) {
if (rowEqual(i)) return grid[i][0];
if (columnEqual(i)) return grid[0][i];
}
if (diagonalLeftToRightEqual()) return grid[0][0];
if (diagonalRightToLefttEqual()) return grid[0][GRIDSIZE];
// Check if the game is a tie
int totalTiles = GRIDSIZE * GRIDSIZE;
return movesMade == totalTiles ? TIE : BLACK;
}
private boolean rowEqual(int r) {
for(int i=1;i<GRIDSIZE;i++) if(grid[r][i-1] != grid[r][i]) return false;
return true;
}
private boolean diagonalLeftToRightEqual() {
for(int i=1;i<GRIDSIZE;i++) if(grid[i-1][i-1] != grid[i][i]) return false;
return true;
}
Cyclometric complexity is a measure of the number of paths through your code. Your function is composed almost exclusively of if statements.
You can combine two or more if statements with or:
if(a)
do_something();
if(b)
do_something();
Should be replaced by:
if(a || b)
do_something();