5
\$\begingroup\$

You can set any size of the field, you can set how much you need to put in a row to win. I think I got a pretty flexible program. What do you think about the code? I would like to know if I made mistakes in program design.

skeleton:

public class Main {
    private static String[] turn;
    private static int hmInARowToWin;
    private static Scanner sc = new Scanner(System.in);
    private static pole[][] area;
    public static void main(String[] args) {

        System.out.println("Hi, lets play tik tak toe!");
        while(true) {
            System.out.println("Pick x.length and y.length of area(print"+'"'+"x y"+'"'+"): ");
            turn = sc.nextLine().split(" "); 
            if(turn.length!=2) {
                System.out.println("print: "+'"'+"x y"+'"'+"!");
            }
            else if(!isNumeric(turn[0])||!isNumeric(turn[1])) {
                System.out.println("x and y should be numbers!");
            }
            else if(Integer.parseInt(turn[0])<=0||Integer.parseInt(turn[1])<=0) {
                System.out.println("x and y should be >0!");
            }
            else {
                area = new pole[Integer.parseInt(turn[0])][Integer.parseInt(turn[1])];
                break;
            }
        }
        fillAreaNOTHING();
        String hmInARowToWinString;
        while(true) {
            System.out.println("hm in a row?");
            hmInARowToWinString = sc.nextLine();
            if(!isNumeric(hmInARowToWinString)) {
                System.out.println("it should be a number!");
            }
            else if(Integer.parseInt(hmInARowToWinString)<3) {
                System.out.println("it should be >2");
            }
            else if(Integer.parseInt(hmInARowToWinString)>Math.max(area.length,area[0].length)) {
                System.out.println("u can not win");
            }
            else {
                hmInARowToWin=Integer.parseInt(hmInARowToWinString);
                break;
            }
        }
        player winner;
        while(true) {
            printArea();
            thisPlayerTurn(player.FIRST);
            if(checkforWin(player.FIRST)) {
                winner = player.FIRST;
                break;
            }
            printArea();
            thisPlayerTurn(player.SECOND);
            if(checkforWin(player.SECOND)) {
                winner = player.SECOND;
                break;
            }
        }
        printArea();
        System.out.println("u won, "+winner.name);


    }
    private static void thisPlayerTurn(player p) {
        System.out.println(p.name+" player, yours turn!(print: "+'"'+"x y"+'"'+")");
        while(true) {
            turn = sc.nextLine().split(" "); 
            if(turn.length!=2) {
                System.out.println("print: "+'"'+"x y"+'"'+"!");
            }
            else if(!isNumeric(turn[0])||!isNumeric(turn[1])) {
                System.out.println("x and y should be numbers!");
            }
            else if(!isXandYIn()) {
                System.out.println("x and y should be in area! P.S.: area.lengthY="+area.length+", area.lengthX="+area[0].length);
            }
            else if(area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])]!=pole.NOTHING){
                System.out.println("this place is already taken! Take another.");
            }
            else {
                if(p==player.FIRST) {
                    area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])] = pole.X;
                }
                else { //second
                    area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])] = pole.O;
                }
                break;
            }
        }
    }
    private static boolean checkforWin(player p) {
        pole toCheck;
        if(p==player.FIRST) {
            toCheck = pole.X;
        }
        else { //second
            toCheck = pole.O;
        }
        for(int y=0;y<area.length;y++) {
            for(int x=0;x<area[0].length;x++) {
                if(area[y][x]!=toCheck) {continue;}
                if(checkHorizontal(x,y,toCheck)||checkVertical(x,y,toCheck)||checkRightUpDiagonal(x,y,toCheck)||checkLeftUpDiagonal(x,y,toCheck)) {
                    return true;
                }
            }
        }
        return false;
    }
    private static boolean checkLeftUpDiagonal(int x, int y,pole toPick);
    private static boolean checkRightUpDiagonal(int x, int y,pole toPick);
    private static boolean checkVertical(int x, int y,pole toPick);
    private static boolean checkHorizontal(int x, int y,pole toPick);
    private static boolean isXandYIn() {}
    public static boolean isNumeric(String strNum);
    public static void printArea();
    static void fillAreaNOTHING();
    private static String repeat(int times,String string);
    enum pole{
        X,O,NOTHING
    }
    enum player{
        FIRST("first"),SECOND("second");
        String name;
        player(String name){
            this.name = name;
        }

    }

}

full code:

public class Main {
    private static String[] turn;
    private static int hmInARowToWin;
    private static Scanner sc = new Scanner(System.in);
    private static pole[][] area;
    public static void main(String[] args) {

        System.out.println("Hi, lets play tik tak toe!");
        while(true) {
            System.out.println("Pick x.length and y.length of area(print"+'"'+"x y"+'"'+"): ");
            turn = sc.nextLine().split(" "); 
            if(turn.length!=2) {
                System.out.println("print: "+'"'+"x y"+'"'+"!");
            }
            else if(!isNumeric(turn[0])||!isNumeric(turn[1])) {
                System.out.println("x and y should be numbers!");
            }
            else if(Integer.parseInt(turn[0])<=0||Integer.parseInt(turn[1])<=0) {
                System.out.println("x and y should be >0!");
            }
            else {
                area = new pole[Integer.parseInt(turn[0])][Integer.parseInt(turn[1])];
                break;
            }
        }
        fillAreaNOTHING();
        String hmInARowToWinString;
        while(true) {
            System.out.println("hm in a row?");
            hmInARowToWinString = sc.nextLine();
            if(!isNumeric(hmInARowToWinString)) {
                System.out.println("it should be a number!");
            }
            else if(Integer.parseInt(hmInARowToWinString)<3) {
                System.out.println("it should be >2");
            }
            else if(Integer.parseInt(hmInARowToWinString)>Math.max(area.length,area[0].length)) {
                System.out.println("u can not win");
            }
            else {
                hmInARowToWin=Integer.parseInt(hmInARowToWinString);
                break;
            }
        }
        player winner;
        while(true) {
            printArea();
            thisPlayerTurn(player.FIRST);
            if(checkforWin(player.FIRST)) {
                winner = player.FIRST;
                break;
            }
            printArea();
            thisPlayerTurn(player.SECOND);
            if(checkforWin(player.SECOND)) {
                winner = player.SECOND;
                break;
            }
        }
        printArea();
        System.out.println("u won, "+winner.name);


    }
    private static void thisPlayerTurn(player p) {
        System.out.println(p.name+" player, yours turn!(print: "+'"'+"x y"+'"'+")");
        while(true) {
            turn = sc.nextLine().split(" "); 
            if(turn.length!=2) {
                System.out.println("print: "+'"'+"x y"+'"'+"!");
            }
            else if(!isNumeric(turn[0])||!isNumeric(turn[1])) {
                System.out.println("x and y should be numbers!");
            }
            else if(!isXandYIn()) {
                System.out.println("x and y should be in area! P.S.: area.lengthY="+area.length+", area.lengthX="+area[0].length);
            }
            else if(area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])]!=pole.NOTHING){
                System.out.println("this place is already taken! Take another.");
            }
            else {
                if(p==player.FIRST) {
                    area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])] = pole.X;
                }
                else { //second
                    area[Integer.parseInt(turn[1])][Integer.parseInt(turn[0])] = pole.O;
                }
                break;
            }
        }
    }
    private static boolean checkforWin(player p) {
        pole toCheck;
        if(p==player.FIRST) {
            toCheck = pole.X;
        }
        else { //second
            toCheck = pole.O;
        }
        for(int y=0;y<area.length;y++) {
            for(int x=0;x<area[0].length;x++) {
                if(area[y][x]!=toCheck) {continue;}
                if(checkHorizontal(x,y,toCheck)||checkVertical(x,y,toCheck)||checkRightUpDiagonal(x,y,toCheck)||checkLeftUpDiagonal(x,y,toCheck)) {
                    return true;
                }
            }
        }
        return false;
    }
    private static boolean checkLeftUpDiagonal(int x, int y,pole toPick) {
        /*
         i mean:
         X
          X
           X 
         */
        ;
        int leftUpDirection=0,rightDownDirection=0;
        boolean areWeLookingOnTempX;
        if(x>y) {
            areWeLookingOnTempX=false;
        }
        else {
            areWeLookingOnTempX=true;
        }
        for(int tempX = x-1,tempY = y-1;areWeLookingOnTempX ? tempX>=0 : tempY>=0;tempX--,tempY--) {
            if(area[tempY][tempX]==toPick) {
                leftUpDirection++;
            }
            else {
                break;
            }
        }
        if(area[0].length-x>area.length-y) {
            areWeLookingOnTempX=false;
        }
        else {
            areWeLookingOnTempX=true;
        }
        for(int tempX = x+1,tempY = y+1;areWeLookingOnTempX ? tempX<area[0].length : tempY<area.length;tempX++,tempY++) {
            if(area[tempY][tempX]==toPick) {
                rightDownDirection++;
            }
            else {
                break;
            }
        }

        return 1+leftUpDirection+rightDownDirection==hmInARowToWin;
    }
    private static boolean checkRightUpDiagonal(int x, int y,pole toPick) {
        /*
         i mean:
           X
          X
         X 
         */
        int rightUpDirection=0,leftDownDirection=0;
        boolean areWeLookingOnTempX;
        if(area[0].length-x>y+1) {
            areWeLookingOnTempX=false;
        }
        else {
            areWeLookingOnTempX=true;
        }
        for(int tempX = x+1,tempY = y-1;areWeLookingOnTempX ? tempX<area[0].length:tempY>=0;tempX++,tempY--) {
            if(area[tempY][tempX]==toPick) {
                rightUpDirection++;
            }
            else {
                break;
            }
        }
        if(x+1>area.length-y) {
            areWeLookingOnTempX=false;
        }
        else {
            areWeLookingOnTempX=true;
        }
        for(int tempX = x-1,tempY = y+1;areWeLookingOnTempX ? tempX>=0:tempY<area.length;tempX--,tempY++) {
            if(area[tempY][tempX]==toPick) {
                leftDownDirection++;
            }
            else {
                break;
            }
        }
        return 1+rightUpDirection+leftDownDirection==hmInARowToWin;
    }
    private static boolean checkVertical(int x, int y,pole toPick) {
        /*
         i mean:
          X
          X
          X
         */
        int upDirection=0,downDirection=0;
        for(int i=y-1;i>=0;i--) {
            if(area[i][x]==toPick) {
                upDirection++;
            }
            else {
                break;
            }
        }
        for(int i=y+1;i<area.length;i++) {
            if(area[i][x]==toPick) {
                downDirection++;
            }
            else {
                break;
            }
        }
        return 1+upDirection+downDirection==hmInARowToWin;
    }
    private static boolean checkHorizontal(int x, int y,pole toPick) {
        /*
         i mean:

         X X X

         */
        int rightDirection=0,leftDirection=0;
        for(int i=x-1;i>=0;i--) {
            if(area[y][i]==toPick) {
                leftDirection++;
            }
            else {
                break;
            }
        }
        for(int i=x+1;i<area[0].length;i++) {
            if(area[y][i]==toPick) {
                rightDirection++;
            }
            else {
                break;
            }
        }
        return 1+rightDirection+leftDirection==hmInARowToWin;
    }
    private static boolean isXandYIn() {
        int turnX = Integer.parseInt(turn[0]);
        int turnY = Integer.parseInt(turn[1]);
        if(turnX<0||area[0].length<=turnX) {
            return false;
        }
        if(turnY<0||area.length<=turnY) {
            return false;
        }
        return true;
    }
    public static boolean isNumeric(String strNum) {
        try {
            Integer.parseInt(strNum);
        } catch (NumberFormatException | NullPointerException nfe) {
            return false;
        }
        return true;
    }
    public static void printArea() {
        if(area != null) {
            for(int i=0;i<area.length;i++) {
                if(i!=0) {
                    System.out.println(repeat(area[0].length-1,"----")+"---");
                }
                for(int b=0;b<area[0].length;b++) {
                    if(b!=0) {
                        System.out.print("|");      
                    }
                    System.out.print(" ");
                    if(area[i][b]==pole.X) {
                        System.out.print("X");
                    }
                    else if(area[i][b]==pole.O) {
                        System.out.print("0");
                    }
                    else {
                        System.out.print(" ");
                    }
                    System.out.print(" ");
                }
                System.out.println();
            }
        }

    }
    static void fillAreaNOTHING() {
        for(int i=0;i<area.length;i++) {
            for(int b=0;b<area[0].length;b++) {
                area[i][b] = pole.NOTHING;
            }
        }
    }
    private static String repeat(int times,String string) {
        String newStr="";
        for(int i=0;i<times;i++) {
            newStr+=string;
        }
        return newStr;
    }
    enum pole{
        X,O,NOTHING
    }
    enum player{
        FIRST("first"),SECOND("second");
        String name;
        player(String name){
            this.name = name;
        }

    }

}
\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code review! I have rolled back your last two edits. Please do not update the code in your question to incorporate feedback from answers, doing so goes against the Question + Answer style of Code Review. This is not a forum where you should keep the most updated version in your question. Please see what you may and may not do after receiving answers. \$\endgroup\$
    – Heslacher
    Commented Nov 1, 2019 at 6:11

1 Answer 1

7
\$\begingroup\$

Nice job using ENUMS 👍

I'm going to try to do the Code Review top-down.

Don't shorten variable names

The compiler doesn't care how long names are. I'm guessing the 'hm' in hmInARowToWin stands for 'howMany'. So it should be changed to howManyInARowToIn or amountInARowToWin.

Use 'final' keyword when possible

Your scanner object is never going to change. So you could delcare it as final. You should then change the name to SC or SCANNER.

Enums should begin with an upper-case letter and be UpperCamelCase

This is just a naming standard. Java has common naming practices you should be following.

So player should be Player, pole should be Pole.

Avoid magic Strings / magic numbers

Lots to be said on this topic, tbh you can google 'magic strings' or 'avoid magic numbers' for more information but it boils down to maintainability. It's easier to make changes if the static String are declared as a class variable:

private static final String WELCOME_MESSAGE = "Hi, lets play tik tak toe!";

It's also easier to spot typos if you only have one place to look (Developers are known for typos and generally magic Strings are things the users will see, which are very important to be correct).

Use backslash as an escape character

Change from: "Pick x.length and y.length of area(print"+'"'+"x y"+'"'+"): "

to: "Pick x.length and y.length of area(print\"x y\"): "

Use plenty of methods to breakup your code into pieces

This is a skill that takes some practice. Again a lot could be said here, but basically you want each of your methods to be doing only 1 thing.

Getting input from the user & doing something with it should be put into a method.

Validating the input should be a method

Use white space between conditions to increase readability

Change: (Integer.parseInt(turn[0])<=0||Integer.parseInt(turn[1])<=0)

To: (Integer.parseInt(turn[0]) <= 0 || Integer.parseInt(turn[1]) <= 0)

Same goes for additions, make sure a whitespace comes before & after the +.

Use camel case for method names & ensure method names make sense

fillAreaNOTHING should be renamed to fillAreaNothing. Then it should be renamed to fillAreaWithNothing, the javadoc would explain nothing is the class variable and/or use `{@link Pole#NOTHING} in the java doc.

Use class variables strategically. Variables should be within the smallest scope possible

Putting all variables at class level because it's slightly easier creates spaghetti 🍝 code and makes it really hard to follow. It also makes it harder / impossible to write methods that only do 1 thing.

Your fillAreaWithNothing method should take area as a parameter.

Create Classes. Java is an Object Oriented language after all

Your main method should be calling some kind of TicTacToe class. You'll also want to keep the non-related stuff out of that class, such as checking if a String is a number or not.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.