I wrote a program that solves a peg solitaire in java.
My program gets a starting board and a destination board and try to finish the game.
I have a sort of counter that count my turn because I have a destination with more the 1 peg rest and as assume that if I have to remove only 2 pegs so I can solve it in only 2 moves.
I have an board class that I create:
public class Board {
private int board[][] = new int[7][7];
public Board(String place)
{
board[0][0]=2;
board[1][0]=2;
board[5][0]=2;
board[6][0]=2;
board[0][1]=2;
board[1][1]=2;
board[5][1]=2;
board[6][1]=2;
board[0][5]=2;
board[1][5]=2;
board[5][5]=2;
board[6][5]=2;
board[0][6]=2;
board[1][6]=2;
board[5][6]=2;
board[6][6]=2;
int loca=0;//location on the string of place
for(int i=0;i<7;i++){
for(int j=0;j<7;j++){
if(board[i][j]!=2) {
if (place.charAt(loca) == 'O') {
loca++;
board[i][j] = 1;
} else if (place.charAt(loca) == '.') {
loca++;
board[i][j] = 0;
}
}
System.out.print(board[i][j]);//print for test
}
System.out.println();//print for test
}
System.out.println();
}
public Board(Board copy){
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
board[i][j]=copy.getValue(i,j);
}
}
}
public int getValue(int x, int y)
{
return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
{
return false;
}
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,0);
board.setValue(x+1,y,0);
board.setValue(x+2,y,1);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,0);
board.setValue(x-1,y,0);
board.setValue(x-2,y,1);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,0);
board.setValue(x,y-1,0);
board.setValue(x,y-2,1);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,0);
board.setValue(x,y+1,0);
board.setValue(x,y+2,1);
return board;
}
else{
System.out.println("there is not such direction, method turn on board class");
return null;//just for caution
}
}
public boolean isLegal(int x, int y){
if(board[x][y]==2)
{
return false;
}
else{
return true;
}
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right"))
{
if(x<5) {
if (board[x][y] == 1 && board[x + 1][y] == 1 && board[x + 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("left"))
{
if(x>1) {
if (board[x][y] == 1 && board[x - 1][y] == 1 && board[x - 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("up"))
{
if(y>1) {
if (board[x][y] == 1 && board[x][y - 1] == 1 && board[x][y - 2] == 0) {
return true;
}
}
}
else if(direction.equals("down"))
{
if(y<5) {
if (board[x][y] == 1 && board[x][y + 1] == 1 && board[x][y + 2] == 0) {
return true;
}
}
}
else{
System.out.println("there is not such direction, method canTurn on board class");
return false;//just for caution
}
return false;
}
public void setValue(int x, int y, int value)
{
board[x][y]=value;
}
}
and I wrote my "solver" class.
public class PegSolver {
public int peg =1;
Board destinationBoard = new Board("OOOOOOOOOOOOOOOOO..OOOOOOOOOOOOOO");
Board board = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
public void start(){
solve(0,board);
}
public boolean solve(int turn, Board board){
Board temp = new Board(board);
if(turn>peg)
{
return false;
}
else if(turn==peg){
//todo:check if solve
if(temp.isFinished(destinationBoard))
{
System.out.println("solution");
return true;
}
else
{
return false;
}
}
else//lower then 8
{
for(int i=0;i<7;i++){
for (int j=0;j<7;j++)
{
if(board.isLegal(i,j)) {
if(board.canTurn("right",i,j) && solve(turn++, temp.turn(temp, "right", i, j)))
{
return true;
}
else if(board.canTurn("left",i,j) && solve(turn++, temp.turn(temp, "left", i, j)))
{
return true;
}
else if(board.canTurn("up",i,j) && solve(turn++, temp.turn(temp, "up", i, j)))
{
return true;
}
else if(board.canTurn("down",i,j) && solve(turn++, temp.turn(temp, "down", i, j)))
{
return true;
}
}
}
}
}
return false;
}
}
When the program finds a solution, it needs to print "solution" but for some reason my program can't find a solution even when it's a basic destination with one move.
Can someone help me please?
Please review the modified code.
Many of the changes are related to indices and directions inconsistency across the code: where x represents horizontal index and y represents vertical index: array index should be board[y][x] (and not board[x][y]).
Many "magic numbers" were changed to constants for better readability of the code.
A toString method was added to the Boardclass to print out a board state. It uses special characters to make a nice printout :
This is helpful when debugging.
public class PegSolver {
private final Board startBoard, destinationBoard;
public PegSolver(Board startBoard, Board destinationBoard) {
super();
this.startBoard = startBoard;
this.destinationBoard = destinationBoard;
}
public void start(){
solve(0,startBoard);
}
private boolean solve(int turn, Board board){
//check if solve
if(board.isFinished(destinationBoard))
{
System.out.println("solved after "+ turn +" turns");
return true;
}
for(int x=0;x<board.boardSize();x++){
for (int y=0;y<board.boardSize();y++)
{
if(board.isLegal(x,y)) {
if(board.canTurn("right",x,y)
//turn++ changed to turn+1 so turn is incremented before invoking next solve
//and avoid changing the value of turn
&& solve(turn+1, board.turn(new Board(board), "right", x, y)))
return true;
else if(board.canTurn("left",x,y)
&& solve(turn+1, board.turn(new Board(board), "left", x, y)))
return true;
else if(board.canTurn("up",x,y)
&& solve(turn+1, board.turn(new Board(board), "up", x, y)))
return true;
else if(board.canTurn("down",x,y)
&& solve(turn+1, board.turn(new Board(board), "down", x, y)))
return true;
}
}
}
return false;
}
public static void main(String[] args) {
Board[] destinationBoards = {
//by order of number of turns
new Board("OOOOOOOOOOOOOO..OOOOOOOOOOOOOOOOO"), //one right turn
new Board("OOO.OOOO.OOOOO.OOOOOOOOOOOOOOOOOO"), //right, down
new Board("OOO.OO..OOOOOO.OOOOOOOOOOOOOOOOOO"), //right, down,right
new Board("OOO.OOO.OOOOO..OOOOO.OOOOOOOOOOOO"), //right, down,right,up
new Board("OOOOOOO..OOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up
new Board(".OO.OOO.OOOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up,down
new Board(".OO.OOO.OOOOO...OOOOO..OOOOOOOOOO"), //right, down,right,up,up,down, left
new Board(".OO.OOO.OOOOO...OOOOO.OOOOO.OO.OO"), //right, down,right,up,up,down,left,up
new Board(".OO.OO..O.OOO...OOOOO.OOOOO.OO.OO"), //10 turns
new Board("..O..O.O..OOO...OOOO..OOOOO..O..O"), //15 turns
new Board(".........O................O......"), //30 turns
new Board("...................O............."), //31 turns
};
Board startBoard = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
for(Board destinationBoard : destinationBoards ){
new PegSolver(startBoard, destinationBoard).start();
}
}
}
class Board {
//int representation of the three states of a board cell
private final static int EMPTY = 0, PEG = 1, BORDER = 2;
/*cahr representation of the three states of a board cell
special chars are used to get nice printout
todo: change board to char[][] to avoid the need for two
representations (int and char)
*/
private final static char[] CHAR_REPRESENTATION = {9898,9899,10062};
private final static char ERROR = '?';
private final int BOARD_SIZE=7, CORNER_SIZE=2;
private final int board[][] = new int[BOARD_SIZE][BOARD_SIZE];
public Board(String place) {
int loca=0;
for(int y=0;y<BOARD_SIZE;y++){
for(int x=0;x<BOARD_SIZE;x++){
if(isWithinBoard(x,y)) {
if (place.charAt(loca) == 'O') {
loca++;
board[y][x] = PEG;
} else if (place.charAt(loca) == '.') {
loca++;
board[y][x] = EMPTY;
}
}else{
board[y][x] = BORDER;
}
}
}
//for testing
//System.out.println(this);
}
//copy constructor
public Board(Board copy){
for(int x=0;x<BOARD_SIZE;x++)
{
for(int y=0;y<BOARD_SIZE;y++)
{
board[y][x]=copy.getValue(x,y);
}
}
}
public int getValue(int x, int y)
{
return board[y][x]; //and not return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<BOARD_SIZE;i++)
{
for(int j=0;j<BOARD_SIZE;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
return false;
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,EMPTY);
board.setValue(x+1,y,EMPTY);
board.setValue(x+2,y,PEG);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,EMPTY);
board.setValue(x-1,y,EMPTY);
board.setValue(x-2,y,PEG);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y-1,EMPTY);
board.setValue(x,y-2,PEG);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y+1,EMPTY);
board.setValue(x,y+2,PEG);
return board;
}
System.out.println("there is not such direction, method turn on startBoard class");
return null;
}
public boolean isLegal(int x, int y){
if(board[y][x]==BORDER) //and not if(board[x][y]==BORDER)
return false;
return true;
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right") && x < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y][x + 1] == PEG && board[y][x + 2] == EMPTY)
return true;
}
else if(direction.equals("left") && x > 1)
{
if (board[y][x] == PEG && board[y][x - 1] == PEG && board[y][x - 2] == EMPTY)
return true;
}
else if(direction.equals("up") && y > 1)
{
if (board[y][x] == PEG && board[y - 1][x] == PEG && board[y - 2][x] == EMPTY)
return true;
}
else if(direction.equals("down") && y < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y + 1][x] == PEG && board[y + 2][x] == EMPTY)
return true;
}
return false;
}
public void setValue(int x, int y, int value)
{
board[y][x]=value; //and not board[x][y]=value;
}
//for square nxn board
public int boardSize(){
return board.length;
}
public boolean isWithinBoard(int x, int y){
//check bounds
if (x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE) return false;
//left top corner
if (x < CORNER_SIZE && y < CORNER_SIZE) return false;
//right top corner
if(x >= BOARD_SIZE - CORNER_SIZE && y < CORNER_SIZE) return false;
//left bottom corner
if(x < CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
//right bottom corner
if(x >= BOARD_SIZE - CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
return true;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int[] row : board) {
for(int cell : row){
if(cell<CHAR_REPRESENTATION.length && cell >= 0) {
sb.append(CHAR_REPRESENTATION[cell]);
}else{
sb.append(ERROR);
}
}
sb.append("\n"); //new line
}
return sb.toString();
}
}
Todo:
The code is working but it needs further in-depth testing and debugging.
If something is not clear, don't hesitate to ask.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 6 years ago.
Improve this question
I'm trying to recreate a printer in java,I'm fairly new to programming so I'm using huge if else blocks inside a single function to dictate the logic of the program, I'm noticing this is creating a mass of code inside the same function, I was wondering if there was a more eloquent/efficient way of doing this, printer class below. Logic for the printer isn't too important, but just to show anyway, one is a double sided printer one isn't, and logic is in charge of checking toner levels and making sure pages printed are in line with printer being double sided or not.
package com.company;
public class Printer {
private String name;
private double tonerLevel = 100;
private int ammountOfPaper;
private int numberOfPagesPrinted;
private boolean isDoubleSided;
public Printer(String name, double tonerLevel, int ammountOfPaper, boolean isDoubleSided) {
this.name = name;
if(tonerLevel >= 0 && tonerLevel <= 100) {
this.tonerLevel = tonerLevel;
}
this.ammountOfPaper = ammountOfPaper;
this.isDoubleSided = isDoubleSided;
}
private boolean isOutOfToner(double numberToPrint) {
if((tonerLevel - (numberToPrint / 2) < 0)) {
return true;
}
else {
return false;
}
}
private boolean isOutOfPaper(double numberToPrint) {
if(((ammountOfPaper - numberToPrint) < 0)) {
return true;
}
else {
return false;
}
}
private boolean twoSideNoPaperEven(double numberToPrint) {
if((ammountOfPaper - ((int) numberToPrint / 2)) < 0 ) {
return true;
}
else {
return false;
}
}
private boolean twoSideNoPaperOdd(double numberToPrint) {
if(((ammountOfPaper - ((int) numberToPrint / 2)) - 1) < 0) {
return true;
}
else {
return false;
}
}
public void printPages(double numberToPrint) {
if(isDoubleSided == false) {
if(tonerLevel == 0) {
System.out.println("Out of toner");
}
if(ammountOfPaper == 0) {
System.out.println("Out of Paper");
}
if(isOutOfToner(numberToPrint) && (tonerLevel != 0)) {
double difference = tonerLevel * 2;
numberToPrint = difference;
ammountOfPaper -= numberToPrint;
System.out.println("Will run out of toner after this print, able to print " + (int) numberToPrint +
" pages");
tonerLevel = 0;
}
if(isOutOfPaper(numberToPrint) && (ammountOfPaper != 0)) {
double different = ammountOfPaper - numberToPrint;
numberToPrint = numberToPrint + different;
System.out.println("Will run out of paper after this print, printing " + (int) numberToPrint + " pages");
ammountOfPaper = 0;
}
else if(!isOutOfToner(numberToPrint) && (!isOutOfPaper(numberToPrint))) {
ammountOfPaper -= numberToPrint;
tonerLevel = tonerLevel - (numberToPrint / 2);
showPages(numberToPrint);
}
}
else if(isDoubleSided = true) {
if (numberToPrint % 2 == 0) {
if(tonerLevel == 0) {
System.out.println("Out of Toner");
}
if(ammountOfPaper == 0) {
System.out.println("Out of Paper");
}
if(twoSideNoPaperEven(numberToPrint) && (ammountOfPaper != 0)) {
ammountOfPaper -= numberToPrint / 2;
System.out.println("There is no Paper");
}
else if(!twoSideNoPaperEven(numberToPrint)) {
tonerLevel = tonerLevel - (numberToPrint / 2);
ammountOfPaper -= numberToPrint / 2;
showPages(numberToPrint);
}
} else {
if(tonerLevel == 0) {
System.out.println("Out of Toner");
}
if(ammountOfPaper == 0) {
System.out.println("Out of Paper");
}
if(twoSideNoPaperOdd(numberToPrint) && (ammountOfPaper != 0)) {
System.out.println("There is no paper");
ammountOfPaper = (ammountOfPaper - ((int) numberToPrint / 2)) - 1;
ammountOfPaper = 0;
}
else if(!twoSideNoPaperOdd(numberToPrint)) {
tonerLevel = tonerLevel - (numberToPrint / 2);
ammountOfPaper = (ammountOfPaper - ((int) numberToPrint / 2)) - 1;
showPages(numberToPrint);
}
}
}
}
public void showPages(double numberToPrint) {
System.out.println("Printing " + (int) numberToPrint + " Pages, paper remaining is: " + this.ammountOfPaper
+ " Toner level is: " + this.tonerLevel);
}
public void refillToner() {
tonerLevel = 100;
}
public void refillPaper(int paper) {
if(paper > 50) {
System.out.println("Cannot put in more paper");
}
else {
this.ammountOfPaper += paper;
}
}
public int getAmmountOfPaper() {
return ammountOfPaper;
}
public double getTonerLevel() {
return tonerLevel;
}
public void setTonerLevel(double tonerLevel) {
this.tonerLevel = tonerLevel;
}
public void setAmmountOfPaper(int ammountOfPaper) {
this.ammountOfPaper = ammountOfPaper;
}
Changing the If Statements To as suggested by nicolas:
public void printPages(double numberToPrint) {
if(tonerLevel == 0) {
System.out.println("Out of toner");
return;
}
if(ammountOfPaper == 0) {
System.out.println("Out of Paper");
return;
}
if(isDoubleSided == false) {
Your if-statements are redundant. You can return directly the boolean value. It saves you 12 lines in your code. For example:
private boolean twoSideNoPaperOdd(double numberToPrint) {
return ((ammountOfPaper - ((int) numberToPrint / 2)) - 1) < 0;
}
There are few conditions repeated often with the same result. Again, it shortens the class by 24 lines.
if (tonerLevel == 0) {
System.out.println("Out of toner");
return; // leave the rest of method
}
if (ammountOfPaper == 0) {
System.out.println("Out of Paper");
return
}
I have a simple class:
public class NPP {
// inputs
public int m__water_pressure = 0;
public boolean m__blockage_button = false;
public boolean m__reset_button = false;
public int old_m__pressure_mode = 0;
public boolean old_m__reset_button = false;
public boolean old_m__blockage_button = false;
public int old_m__water_pressure = 0;
// outputs
public int c__pressure_mode = 0;
public boolean c__the_overriden_mode = false;
public int c__the_safety_injection_mode = 0;
public int p__pressure_mode = 0;
public boolean p__the_overriden_mode = false;
public int p__the_safety_injection_mode = 0;
public void method__c__pressure_mode() {
if ( m__water_pressure >= 9 && old_m__water_pressure < 9 && c__pressure_mode == 0 ) {
p__pressure_mode = 1;
} else if ( m__water_pressure >= 10 && old_m__water_pressure < 10 && c__pressure_mode == 1 ) {
p__pressure_mode = 2;
} else if ( m__water_pressure < 9 && old_m__water_pressure >= 9 && c__pressure_mode == 1 ) {
p__pressure_mode = 0;
} else if ( m__water_pressure < 10 && old_m__water_pressure >= 10 && c__pressure_mode == 2 ) {
p__pressure_mode = 1;
}
}
public void method__c__the_overriden_mode() {
if ( m__blockage_button == true && old_m__blockage_button == false && m__reset_button == false && !(c__pressure_mode==2) ) {
p__the_overriden_mode = true;
} else if ( m__reset_button == true && old_m__reset_button == false && !(c__pressure_mode==2) ) {
p__the_overriden_mode = false;
} else if ( c__pressure_mode==2 && !(old_m__pressure_mode==2) ) {
p__the_overriden_mode = false;
} else if ( !(c__pressure_mode==2) && old_m__pressure_mode==2 ) {
p__the_overriden_mode = false;
}
}
public void method__c__the_safety_injection_mode() {
if ( c__pressure_mode == 0 && c__the_overriden_mode == true ) {
p__the_safety_injection_mode = 0;
} else if ( c__pressure_mode == 0 && c__the_overriden_mode == false ) {
p__the_safety_injection_mode = 1;
} else if ( c__pressure_mode == 1 || c__pressure_mode == 2 ) {
p__the_safety_injection_mode = 0;
}
}
}
And i've wrote this junit class:
import static org.junit.Assert.*;
import org.junit.Test;
public class NPPTest {
#Test
public void testMethod__c__pressure_mode() {
NPP npp = new NPP();
npp.m__water_pressure = 3;
npp.old_m__water_pressure = 5;
npp.c__pressure_mode = 2;
npp.method__c__pressure_mode();
assertEquals(1, npp.p__pressure_mode);
}
#Test
public void testMethod__c__the_overriden_mode() {
NPP npp = new NPP();
npp.m__blockage_button = false;
npp.old_m__blockage_button = true;
npp.m__reset_button = false;
npp.method__c__the_overriden_mode();
assertFalse(npp.p__the_overriden_mode);
}
#Test
public void testMethod__c__the_safety_injection_mode() {
NPP npp = new NPP();
npp.c__pressure_mode = 2;
npp.c__the_overriden_mode = false;
npp.method__c__the_safety_injection_mode();
assertEquals(1, npp.p__the_safety_injection_mode);
}
}
I've been asked to write some tests and to cover 100% of code coverage. But what exactly does it mean? How can i achieve this? I've ran Eclemma and i've got only 46%.
100% code coverage means that every line of code is covered by a test.
In other words, your test code should call and go through everything that has been written and make sure it works as expected.
In your case, it means that all the methods must be called and every if-else if case must be tested.
Even though 100% code coverage is very sexy, what matters most is the quality of your test suite.
85% code coverage might be near perfect if all the 15% left is some getters/setters, call to external APIs that is useless to check, glue code that is very very difficult to test and so on. It is up to you to realize what code can and should be tested and what code can be left without knowing that you are leaving holes (and bombs?) in your app.
Well been working for hours today so i might be missing something silly, but, at this point I'm kinda blind with this and looking for an explanation for this behaviour
i made an example of the problem I'm having and the solution i found is not quite a solution.
The Problem: to the following function I pass 1 as shotCount and 9 as Countdown
the result when i debug, i see the first if run, and run the return 2, but then also the else decides to run to and finally return -1
public int getNextShot(int shotCount, int Countdown)
{
if ((shotCount == 1) && (Countdown != 10)) return 2;
else if (shotCount == 0) return 1;
else return -1;
}
BUT if i do this (same parameters) it works:
public int getNextShot(int shotCount, int Countdown)
{
int res = -2;
if ((shotCount == 1) && (Countdown != 10)) res = 2;
else if (shotCount == 0) res = 1;
else res = -1;
return res;
}
Am I missing something here?
Thanks :)
I think you are mistaken.
Sometimes the debugger in Eclipse acts like its jumping to the last line of the method call but then does return the correct value.
For example, I just copied and pasted your code and it ran fine for me. The below code prints 2.
public class AA {
public static void main(String[] args) {
System.out.println(getNextShot(1, 9));
}
public static int getNextShot(int shotCount, int Countdown)
{
if ((shotCount == 1) && (Countdown != 10)) return 2;
else if (shotCount == 0) return 1;
else return -1;
}
}
This code is OK. When I run this:
public static int getNextShot1(int shotCount, int Countdown) {
if ((shotCount == 1) && (Countdown != 10)) {
return 2;
} else if (shotCount == 0) {
return 1;
} else {
return -1;
}
}
public static int getNextShot2(int shotCount, int Countdown) {
int res = -2;
if ((shotCount == 1) && !(Countdown == 10)) {
res = 2;
} else if (shotCount == 0) {
res = 1;
} else {
res = -1;
}
return res;
}
public static void main(String[] args) throws KeyStoreException, ParseException {
System.out.println(getNextShot1(1, 9));
System.out.println(getNextShot2(1, 9));
}
I get
2
2
on console :)
Second function could look like this (final keyword):
public static int getNextShot2(int shotCount, int Countdown) {
final int res;
if ((shotCount == 1) && !(Countdown == 10)) {
res = 2;
} else if (shotCount == 0) {
res = 1;
} else {
res = -1;
}
return res;
}