Test all possible 'wins' of a norts and crosses/tic tac toe game?

edited January 2016 in How To...

The positions of the pieces ('N' or 'C') are placed in a char array that has a length of 9 (0-8). So using the places in the array the board would look like this:

0 1 2 3 4 5 6 7 8

There are 8 possible wins: (0,1,2), (3,4,5), (6,7,8), (0,3,6), (1,4,7), (2,5,8),(0,4,8) or (2,4,6). So if the same piece is in the three spots in any of the ones listed they win. The only way that I can think of to test all of the possibilities is by using 8 if functions but it seems inelegant. Is there a better way.

if(array[0]==array[1]&&array[1]==array[2])

There has to be a better solution, but I just cant think of it right now. Thanks

Tagged:

Answers

  • I'm not entirely sure how you're making the code, so I'm just guessing.

    If you mean "elegant" as in the length of the code, then this is a bit more "elegant":

    if(NArray == Win1 || NArray == Win2 || etc...
    

    Here's another idea to think about. Look at the wins. They all go up in even increments...

    Again, it's something to think about.

    -- MenteCode

  • First I wouldn't use a char array because it makes it very difficult to use numerical techniques to analize the board.

    In the code below I have used an int array to store the positions. A value of 1 = N, 10 = C and 0 - empty square. The advantage of this is that you can add the three values in a line (repeat for each line) and depending on the sum (S) you get

    3 N wins

    30 C wins

    2 N can win if it is his turn

    20 C can win if it is his turn

    0 empty line

    etc.

    int[] board = {
      10, 1, 1, 0, 10, 0, 1, 0, 10
    };
    int[] line = new int[8];
    
    final int N = 1;
    final int C = 10;
    final int N_WIN = 3 * N;
    final int C_WIN = 3 * C;
    final int NO_WINNER = 0;
    
    
    void setup() {
      size(240, 128);
      background(255);
      fill(0);
      int w = checkForWinner();
      switch (w) {
      case N_WIN:
        text("Noughts have won", 20, 20);
        break;
      case C_WIN:
        text("Crosses have won", 20, 20);
        break;
      case NO_WINNER:
        text("No winner yet ...", 20, 20);
        break;
      }
    }
    
    int checkForWinner() {
      analyseBoard();
      for (int i = 0; i < line.length; i++)
        if (line[i] == N_WIN || line[i] == C_WIN)
          return line[i];
      return NO_WINNER;
    }
    
    void analyseBoard() {
      int p = 0;
      // horizontaal rows
      for (int i = 0; i <= 6; i += 3)
        line[p++] = board[i] + board[i+1] + board[i+2];
      // vertical columns
      for (int i = 0; i < 3; i++)
        line[p++] = board[i] + board[i+3] + board[i+6];
      // top-left to bottom-right diagonal
      line[p++] =  board[0] + board[4] + board[8]; 
      // top-right to bottom-left diagonal
      line[p++] =  board[2] + board[4] + board[6];
    }
    
  • edited October 2013

    First I wouldn't use a char array because it makes it very difficult to use numerical techniques to analyze the board.

    All of Java's (even in C) primitive data-types, except boolean, are real numerical types! @-)
    And they're fully capable of being part of any numerical expression used by operators & functions! :-B
    The only catches for char data-type is that it's unsigned and displayed as characters! 8-X

    But for a tic-tac-toe array, anything more than a byte[] would be a waste of RAM! :(|)

    Anyways, using char w/ Quark's code would be more or less below: ;-P

    final static char N_WIN = 3*'N', C_WIN = 3*'C', NO_WINNER = 0;
    
  • The reason for using int rather than char is to avoid

    (1) causing any confusion re casting

    (2) to make the maths clearer

    (3) to enable easy extension of the simple example provided (e.g. other methods that might be used to create a computer player for instance)

    But for a tic-tac-toe array, anything more than a byte[] would be a waste of RAM!

    In programming there are always balances to be made and I don't think the difference between 9 bytes for a char array and 36 bytes for the in array a waste of RAM if it makes the code clearer.

  • edited October 2013

    (1) causing any confusion re-casting

    If there's no assignment, there's no need of using cast operators! 8-X
    Also, assignment operators like +=, /=, etc., got auto-box casting!!! $-)

    (2) to make the maths clearer

    Using char data-type for calculation is very unorthodox. And can even get cryptic I agree! >-)
    But in this specific case:

    final static char N_WIN = 3*'N', C_WIN = 3*'C';
    

    its reasoning is very easy to figure out IMO! As much as your original version below:

    final static int N = 1, C = 10;
    final static int N_WIN = 3*N, C_WIN = 3*C;
    

    ... other methods that might be used to create a computer player for instance...

    Any methods from a class (or extending it) should be aware of the data-types of the declared fields! :>

    ... a waste of RAM if it makes the code clearer.

    I can't see why a byte[] would be less clearer than an int[]! :-@

  • I picked the numbers so that the value of C is > 3* N consider the line (where the underscore is an free position on the board)

    C _ N the value (S) of this line is 11

    The number of crosses is 11 / C i.e. 1

    The number of noughts is 11 % C i.e. 1

    Now consider _ N N the value (S) of this line is 2

    The number of crosses is 2 / C i.e. 0

    The number of noughts is 2 % C i.e. 2

    and so on

    Very useful when you want to have a simple way to categorize _ a line and then _evaluate the board. This would not be as straightforward if you use the ASCII values of N and C (whatever they happen to be)

    BTW my original code did not use the static modifier. Unless you are going to create your own classes inside the sketch there is no real need for it, to access the variable from another top level class would require sketch_name.C (so forget save-as) and it is just something else for a newbie to get confused about.

Sign In or Register to comment.