Search Unity

[Othello] It's me again and it's about game rules this time...

Discussion in 'Getting Started' started by luyao795, Mar 22, 2016.

  1. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Thanks to those valuable comments from community, right now I have a board that I can place white and black pieces (discs) in turn!
    boardWithGrid.png
    Now I think it's time to implement the game rule. (If it's still not the time, please let me know.) However, as much as I understand how game works, I'm still confused by how you could actually implement it. To me, it seems that there are so many conditions to check (whether the disc is in corner, whether it's on edge, whether there are enemy discs on all eight directions, whether there are friendly discs on all eight directions, whether there are empty slots between discs, etc.). Is there a way I can check in a listed way (like, check A first, then if meet some condition, check B and check C and so on and so forth)?

    Also, I'm confused about script management right now. All those features I have achieved (place discs in turn and make sure discs will only be place on center of grid) are in a script that is linked to my board. What I'm confused is that whether I need a script for my piece (which is a prefab). If so, I don't really know what I should include in piece's script. Also, since discs are required to flip by using animation instead of substitution between black and white, I need to apply animations (which I already have) onto discs when they flip. Does that mean that I need to construct an Animator inside piece's script?
    Also, where should the implementation of game rules go? Should I create an empty GameObject and link the game rule script to it or I should just simply implement game rules inside board's script?

    Looking forward to all your opinions and suggestions and thanks for your contribution.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    You've missed the key bit I was really trying (but apparently failing) to stress in my first reply.

    You must have a lightweight GameState class that is not in any way related to Unity objects. This is absolutely critical. It must represent the state of the board, and be able to answer questions like whether a certain move is legal, and what are all the legal moves. And it must not be a MonoBehavior, nor make any reference to any MonoBehaviour, or any other Unity object. It should pretty much be a wrapper for a 2D array of char (with 'X' and 'O' for the pieces and maybe '.' for an empty space).

    This is where you will put the rules for whether a move is legal. Not in any of the scripts you have now.

    And remember to build this with test-driven development... It may seem at first that this will take longer than just writing the code, but believe me, it doesn't. It is much faster than the alternative. And writing these tests will drive home the first reason to have your GameState object separate from the Unity scene graph. (The second reason will become apparent when you get to the AI.)

    As for how to implement it, it's not that bad. There are just eight directions to check. And you can make a generic check routine which takes a starting point and a direction, and checks whether there is a valid flip-set (i.e. a set of opposite-colored pieces, followed by a same-colored piece) in that direction. You will of course unit test the snot out of this check routine. And then you can implement your "is this legal" move by simply calling the check routine for each of the eight directions, returning true if any of them return true.
     
  3. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    I'm currently using a 2D int array to represent the boardState (aka GameState) where 0 represents empty, 1 represents white and 2 represents black. To pair with that, I also have a 2D GameObject array to store the instantiate of each piece. So it looks like this:

    boardState = new int[,] {
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 1, 2, 0, 0, 0 },
    { 0, 0, 0, 2, 1, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 }
    };
    boardPieces = new GameObject[,] {
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    { null, null, null, null, null, null, null, null },
    };
    GameObject init;
    init = Instantiate (piece, new Vector3 (3f, 1f, 4f), Quaternion.identity) as GameObject;
    boardPieces[3, 4] = init;
    init = Instantiate (piece, new Vector3 (4f, 1f, 3f), Quaternion.identity) as GameObject;
    boardPieces[4, 3] = init;
    init = Instantiate (piece, new Vector3 (3f, 1f, 3f), Quaternion.Euler(0f, 0f, 180f)) as GameObject;
    boardPieces[3, 3] = init;
    init = Instantiate (piece, new Vector3 (4f, 1f, 4f), Quaternion.Euler(0f, 0f, 180f)) as GameObject;
    boardPieces[4, 4] = init;

    Those are currently in my Board.cs

    Just want to make sure that I understand you correctly, are you trying to say that I should move boardState to a independent C# script? So it would be something like

    public class GameState {

    public int[,] boardState = new int[,] {
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 1, 2, 0, 0, 0 },
    { 0, 0, 0, 2, 1, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 0, 0, 0, 0 }
    };

    }

    If so, where should I set up the game rules? In the same script as GameState? In Board? Or in some other scripts?

    Thanks for your explanation, looking forward to your reply and feel free to correct me if anything I said was wrong or inaccurate. :)
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Yes, that's exactly what I'm saying. You will need to manipulate these GameState objects completely separate from any MonoBehaviour. So, they need to be their own little class. (An int array is fine if that's what you like, but even then you should use byte rather than int; when you start doing AI you are going to have a LOT of these in memory at once!)

    And yes, the GameState script should also embody the game rules. NOT Board. Shove as much as possible into the GameState, where you can test it and do AI stuff with it without having to manipulate Unity objects.
     
  5. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    OK, thank you very much for the explanation! Sigh, the disadvantage for not being a native English speaker... :(

    One more question, does this mean that I should do all game rules and GameState in that separate C# script, and then instantiate pieces onto board in Board (I'm thinking this way since I did the Raycast in Board)? Thank you for your patience!
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Yes, I think you have the right idea.
     
  7. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    I'd also record who's turn it is in your game state object.
     
    JoeStrout likes this.
  8. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    I did that in my Board script along with SetPiece() function so that I can make sure pieces would be placed in turn.
     
  9. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    But Board is a MonoBehaviour, isn't it? @BoredMormon is right — this is part of the game state, and you will need it in the game state class. Trust us, we've done this before. :)
     
  10. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    So I can just use a public bool to record whose turn it is in GameState?
     
  11. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Or actually, can I use a public int to record this (I use 1 to represent human player and 2 for AI which hasn't been implemented yet)?
     
  12. maquis

    maquis

    Joined:
    Feb 7, 2016
    Posts:
    61
    I would make the first iteration of the game as a 2-player game.... not an AI!

    I would use getters and setters instead of public variables to interact with the gamestate class, personally. Its just cleaner that way.
     
  13. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Currently since I haven't implemented AI yet, it has to be a 2-player game.

    But for the submission, we have to make the game 1-player vs AI only. And the requirement said that AI has to have at least 10 levels of difficulty.

    Thanks for your opinion, I will look into that.
     
  14. maquis

    maquis

    Joined:
    Feb 7, 2016
    Posts:
    61
    Huh. 10 levels of difficulty. I dont know that im good enough at othello to play at 10 difficulty levels... I guess you will know the game inside and out by the end, though...
     
  15. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    You could, but I would also consider making the board state immutable. You are going to need a ton of these for the AI to work, and making them immutable reduces the chances for bugs.

    Here is a diagram of how your AI is going to work

    Reversi.png

    To be convincing you are going to have to work with at least three or four generations. If you got all 60 in you could make an unbeatable AI (with sufficient memory). Changing AI difficulty is trivial, you would simply up the number of generations considered for each level. Difficulty level 0 randomly picks a move. Level one examines one generation. Level ten examines ten generations (up your simulation one generation at a time, its pretty easy to run of of memory or set something up that takes several hours to process).

    So you see you are going to need a lot of game states sitting around. That's why JoeStrout keeps coming back to making the board state a light weight class.

    Here is the basic outline I would expect for the board state. (@JoeStrout did I miss anything here? Been a while since I did this sort of thing).

    Code (CSharp):
    1. public class BoardState {
    2.  
    3.     // Data that records the actual state
    4.     public bool isWhitesTurn {get; private set;}
    5.     private byte [,] piecePosition = new byte[8,8];
    6.  
    7.     // A method to get the rating of this position for the AI to evaluate
    8.     public int GetScore (){}
    9.  
    10.     // A way to create new states based on the current state
    11.     public BoardState (BoardState previousPosition, int xMove, int yMove){}
    12.     public BoardState[] GetNextStates(){}
    13. }
     
    JoeStrout likes this.
  16. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Hi, I just finished implementing and applying GameState and game rules. Now I have a problem here.
    Right now I can detect the whether a grid is valid to set piece, both for black and white. And I'm able to set a piece at a grid if it is valid. But after setting the piece, those pieces on the right directions that should flip didn't flip. I'm not sure where I did wrong, this is what I did for flipping a piece (which is basically substitution).
    Here is my code for flipping a piece:
    Code (CSharp):
    1.  
    2. // flip the piece at position (x, z) on board
    3.     void FlipPiece(int x, int z)
    4.     {
    5.         if (gameController.boardState [x, z] == 1) {
    6.             gameController.boardState [x, z] = 2;
    7.             // display the flip white to black animation
    8.             // so far we will just use substitution method
    9.             Vector3 pos = boardPieces[x, z].transform.position;
    10.             //Quaternion rot = boardPieces [x, z].transform.rotation * Quaternion.Euler (new Vector3 (0f, 0f, 180f));
    11.             Destroy(boardPieces[x, z]);
    12.             boardPieces [x, z] = Instantiate (piece, pos, Quaternion.Euler (new Vector3 (0f, 0f, 180f))) as GameObject;
    13.  
    14.             whiteCount--;
    15.             blackCount++;
    16.         }
    17.         if (gameController.boardState [x, z] == 2) {
    18.             gameController.boardState [x, z] = 1;
    19.             // display the flip black to white animation
    20.             // so far we will just use substitution method
    21.             Vector3 pos = boardPieces[x, z].transform.position;
    22.             //Quaternion rot = boardPieces [x, z].transform.rotation * Quaternion.Euler (new Vector3 (0f, 0f, 180f));
    23.             Destroy(boardPieces[x, z]);
    24.             boardPieces [x, z] = Instantiate (piece, pos, Quaternion.identity) as GameObject;
    25.  
    26.             blackCount--;
    27.             whiteCount++;
    28.         }
    29.     }
    30.  
    Pieces are two sided, one is black, the other is white. Whenever I'm trying to flip a piece, I just destroy the old one and instantiate a new one. If it's white, there is no rotation. If it's black, then it rotates 180 degrees about z axis.
    Is there anything wrong with my FlipPiece?
     
  17. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Why are you destroying and creating pieces, instead of just rotating the existing 2-sided object?
     
    Kiwasi likes this.
  18. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Oh, so I just apply rotation on whateverPieceNeedsFlip.transform.rotation?
    Wow, I'm an idiot.
     
    Kiwasi likes this.
  19. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Hmm, I tried this:
    Code (CSharp):
    1. boardPieces[x, z].transform.rotation *= Quaternion.Euler(new Vector3(0f, 0f, 180f));
    But pieces still won't change color after I play a valid move. :(
     
  20. tedthebug

    tedthebug

    Joined:
    May 6, 2015
    Posts:
    2,570
    Do your pieces actually have a different colour on each side or are they all white or all black?

    If they each have different colours on each side then perhaps you aren't rotating them around the right axis.

    If they are only single coloured pieces then instead of destroying & instantiating new ones you could just change the texture.
     
  21. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    That's rotating around Z. It turns your piece upside down; it doesn't flip it front-to-back.
     
  22. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Good idea — or, for that matter, you could change the sprite color.

    (EDIT: But I believe he said he had to have a flip animation.)
     
  23. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    They are indeed white on one side and black on the other side.
     
  24. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Since I want to make sure that the core feature of the game is working, I'm not planning applying animation now, at least not before AI is working.
    When I instantiate pieces, if I use Quaternion.identity then when I click the piece is white, and when I use Quaternion.Euler(new Vector3(0f, 0f, 180f)) then when I click the piece is black. That's why I rotate the piece around Z axis.
    Am I thinking it the wrong way?
     
  25. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Here is my FlipLine function that I actually call when a move is valid:
    Code (CSharp):
    1.  
    2.     // flip qualified pieces on the line that is defined by starting point (x, z) and direction dir
    3.     void FlipLine(int x, int z, Vector2 dir)
    4.     {
    5.         int changeX = (int)dir.x;
    6.         int changeZ = (int)dir.y;
    7.         int state = gameController.boardState [x, z]; // color of the starting point
    8.         // store position of the piece we are checking
    9.         int posX = x + changeX;
    10.         int posZ = z + changeZ;
    11.         // as long as the piece we are checking has a different color than the color of the starting point
    12.         // flip the piece and adjust the number of pieces for both black and white
    13.         while (gameController.boardState [posX, posZ] != state) {
    14.             FlipPiece (posX, posZ);
    15.             if (gameController.colorTurn == 1) {
    16.                 whiteCount++;
    17.                 blackCount--;
    18.             }
    19.             if (gameController.colorTurn == 2) {
    20.                 blackCount++;
    21.                 whiteCount--;
    22.             }
    23.             // keep checking along the line with dir until the color is matching the color of starting point
    24.             posX += changeX;
    25.             posZ += changeZ;
    26.         }
    27.  
    28.     }
    Perhaps the problem is within this function? Though I can't see where it may be wrong...
     
  26. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I don't see it either. Write a little script to test FlipPiece in isolation. Try different rotation axes (and amounts!) until you get a clear idea what's going on.
     
  27. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    It turns out that I wrote the code in wrong order in execution. It's so weird now since I have the very same logic for black as for white but now the flip works fine for white but doesn't work for black. Hmm...
     
  28. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    And somehow for the very same code when color is white it is called twice but when color is black it is only called once.
    I'm so confused right now...
     
  29. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    I literally cannot figure out where I may possibly do wrong... Here is my code for placing a piece and fliping qualified opponent pieces:
    Code (CSharp):
    1.  
    2. if (gameController.colorTurn == 1) {
    3.             if (Input.GetButtonDown ("Fire1")) {
    4.                 RaycastHit hit;
    5.                 Ray ray = camera.ScreenPointToRay (Input.mousePosition);
    6.                 if (coll.Raycast (ray, out hit, 100.0f)) {
    7.                     float coordx = hit.point.x;
    8.                     float coordz = hit.point.z;
    9.                     int wholex = (int)coordx;
    10.                     int wholez = (int)coordz;
    11.                     float decimalx = coordx - wholex;
    12.                     float decimalz = coordz - wholez;
    13.                     List<Vector2> flipDir = new List<Vector2> ();
    14.                     GameObject clone;
    15.                     // white player
    16.                     if (coordx < 7.5f && coordx > -0.5f && coordz < 7.5f && coordz > -0.5f) {
    17.                         if (decimalx > 0.5f && decimalz > 0.5f) {
    18.                             if (gameController.IsValidMove (1, wholex + 1, wholez + 1)) {
    19.                                 flipDir = FindDir (1, wholex + 1, wholez + 1);
    20.                                 for (int i = 0; i < flipDir.Count; i++) {
    21.                                     FlipLine (wholex + 1, wholez + 1, flipDir.ElementAt (i));
    22.                                 }
    23.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex + 1), 1f, (float)(wholez + 1)), Quaternion.identity) as GameObject;
    24.                                 boardPieces [wholex + 1, wholez + 1] = clone;
    25.                                 whiteCount++;
    26.                                 emptyLeft--;
    27.                                 //flipDir.Clear ();
    28.                                 gameController.boardState [wholex + 1, wholez + 1] = 1;
    29.                                 gameController.colorTurn = 2;
    30.                             }
    31.                         }
    32.                         if (decimalx < 0.5f && decimalz > 0.5f) {
    33.                             if (gameController.IsValidMove (1, wholex, wholez + 1)) {
    34.                                 flipDir = FindDir (1, wholex, wholez + 1);
    35.                                 for (int i = 0; i < flipDir.Count; i++) {
    36.                                     FlipLine (wholex, wholez + 1, flipDir.ElementAt (i));
    37.                                 }
    38.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex), 1f, (float)(wholez + 1)), Quaternion.identity) as GameObject;
    39.                                 boardPieces [wholex, wholez + 1] = clone;
    40.                                 whiteCount++;
    41.                                 emptyLeft--;
    42.                                 //flipDir.Clear ();
    43.                                 gameController.boardState [wholex, wholez + 1] = 1;
    44.                                 gameController.colorTurn = 2;
    45.                             }
    46.                         }
    47.                         if (decimalx > 0.5f && decimalz < 0.5f) {
    48.                             if (gameController.IsValidMove (1, wholex + 1, wholez)) {
    49.                                 flipDir = FindDir (1, wholex + 1, wholez);
    50.                                 for (int i = 0; i < flipDir.Count; i++) {
    51.                                     FlipLine (wholex + 1, wholez, flipDir.ElementAt (i));
    52.                                 }
    53.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex + 1), 1f, (float)(wholez)), Quaternion.identity) as GameObject;
    54.                                 boardPieces [wholex + 1, wholez] = clone;
    55.                                 whiteCount++;
    56.                                 emptyLeft--;
    57.                                 //flipDir.Clear ();
    58.                                 gameController.boardState [wholex + 1, wholez] = 1;
    59.                                 gameController.colorTurn = 2;
    60.                             }
    61.                         }
    62.                         if (decimalx < 0.5f && decimalz < 0.5f) {
    63.                             if (gameController.IsValidMove (1, wholex, wholez)) {
    64.                                 flipDir = FindDir (1, wholex, wholez);
    65.                                 for (int i = 0; i < flipDir.Count; i++) {
    66.                                     FlipLine (wholex, wholez, flipDir.ElementAt (i));
    67.                                 }
    68.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex), 1f, (float)(wholez)), Quaternion.identity) as GameObject;
    69.                                 boardPieces [wholex, wholez] = clone;
    70.                                 whiteCount++;
    71.                                 emptyLeft--;
    72.                                 //flipDir.Clear ();
    73.                                 gameController.boardState [wholex, wholez] = 1;
    74.                                 gameController.colorTurn = 2;
    75.                             }
    76.                         }
    77.                     }
    78.                 }
    79.             }
    80.         } else if (gameController.colorTurn == 2) {
    81.             if (Input.GetButtonDown ("Fire1")) {
    82.                 RaycastHit hit;
    83.                 Ray ray = camera.ScreenPointToRay (Input.mousePosition);
    84.                 if (coll.Raycast (ray, out hit, 100.0f)) {
    85.                     float coordx = hit.point.x;
    86.                     float coordz = hit.point.z;
    87.                     int wholex = (int)coordx;
    88.                     int wholez = (int)coordz;
    89.                     float decimalx = coordx - wholex;
    90.                     float decimalz = coordz - wholez;
    91.                     List<Vector2> flipDir = new List<Vector2> ();
    92.                     GameObject clone;
    93.                     // black player
    94.                     if (coordx < 7.5f && coordx > -0.5f && coordz < 7.5f && coordz > -0.5f) {
    95.                         if (decimalx > 0.5f && decimalz > 0.5f) {
    96.                             if (gameController.IsValidMove (2, wholex + 1, wholez + 1)) {
    97.                                 flipDir = FindDir (2, wholex + 1, wholez + 1);
    98.                                 for (int i = 0; i < flipDir.Count; i++) {
    99.                                     FlipLine (wholex + 1, wholez + 1, flipDir.ElementAt (i));
    100.                                 }
    101.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex + 1), 1f, (float)(wholez + 1)), Quaternion.Euler (0.0f, 0.0f, 180f)) as GameObject;
    102.                                 boardPieces [wholex + 1, wholez + 1] = clone;
    103.                                 blackCount++;
    104.                                 emptyLeft--;
    105.                                 //flipDir.Clear ();
    106.                                 gameController.boardState [wholex + 1, wholez + 1] = 2;
    107.                                 gameController.colorTurn = 1;
    108.                             }
    109.                         }
    110.                         if (decimalx < 0.5f && decimalz > 0.5f) {
    111.                             if (gameController.IsValidMove (2, wholex, wholez + 1)) {
    112.                                 flipDir = FindDir (2, wholex, wholez + 1);
    113.                                 for (int i = 0; i < flipDir.Count; i++) {
    114.                                     FlipLine (wholex, wholez + 1, flipDir.ElementAt (i));
    115.                                 }
    116.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex), 1f, (float)(wholez + 1)), Quaternion.Euler (0.0f, 0.0f, 180f)) as GameObject;
    117.                                 boardPieces [wholex, wholez + 1] = clone;
    118.                                 blackCount++;
    119.                                 emptyLeft--;
    120.                                 //flipDir.Clear ();
    121.                                 gameController.boardState [wholex, wholez + 1] = 2;
    122.                                 gameController.colorTurn = 1;
    123.                             }
    124.                         }
    125.                         if (decimalx > 0.5f && decimalz < 0.5f) {
    126.                             if (gameController.IsValidMove (2, wholex + 1, wholez)) {
    127.                                 flipDir = FindDir (2, wholex + 1, wholez);
    128.                                 for (int i = 0; i < flipDir.Count; i++) {
    129.                                     FlipLine (wholex + 1, wholez, flipDir.ElementAt (i));
    130.                                 }
    131.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex + 1), 1f, (float)(wholez)), Quaternion.Euler (0.0f, 0.0f, 180f)) as GameObject;
    132.                                 boardPieces [wholex + 1, wholez] = clone;
    133.                                 blackCount++;
    134.                                 emptyLeft--;
    135.                                 //flipDir.Clear ();
    136.                                 gameController.boardState [wholex + 1, wholez] = 2;
    137.                                 gameController.colorTurn = 1;
    138.                             }
    139.                         }
    140.                         if (decimalx < 0.5f && decimalz < 0.5f) {
    141.                             if (gameController.IsValidMove (2, wholex, wholez)) {
    142.                                 flipDir = FindDir (2, wholex, wholez);
    143.                                 for (int i = 0; i < flipDir.Count; i++) {
    144.                                     FlipLine (wholex, wholez, flipDir.ElementAt (i));
    145.                                 }
    146.                                 clone = Instantiate (piece, new Vector3 ((float)(wholex), 1f, (float)(wholez)), Quaternion.Euler (0.0f, 0.0f, 180f)) as GameObject;
    147.                                 boardPieces [wholex, wholez] = clone;
    148.                                 blackCount++;
    149.                                 emptyLeft--;
    150.                                 //flipDir.Clear ();
    151.                                 gameController.boardState [wholex, wholez] = 2;
    152.                                 gameController.colorTurn = 1;
    153.                             }
    154.                         }
    155.                     }
    156.                 }
    157.             }
    158.         } else
    159.             return;
    I just did the exactly same thing for both players. It works fine for white player but for black player I can detect whether the move is valid, if it's valid I can place a black piece there, but those white pieces that should flip didn't flip...

    Urgent help needed. Thanks a lot. :(
     
  30. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I've already told you what to do: test the flipping code in isolation! You've still got it tied up with a bunch of other junk that processes input, checks for legal moves, etc.

    Whenever you have a problem in a system, your first step should always be to break the system apart into pieces, and test them separately. The problem most likely isn't what and where you think it is, or you would have solved it already.

    (Your second step should be to kick yourself for not developing it that way in the first place — write and test each piece separately before you start bolting them together — especially if you were advised to do exactly that early in the process.)

    Also, if you're really stuck, get a fellow student to sit down and go over it with you. Chances are you'll find the problem just in the course of trying to explain to her how it's supposed to work. And if not, maybe she'll spot it for you.
     
    Kiwasi likes this.
  31. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    OK, I'll do the second step first and then go back to first step.
     
    JoeStrout likes this.
  32. maquis

    maquis

    Joined:
    Feb 7, 2016
    Posts:
    61
    Or a rubber ducky... Or a pet... Or a stuffed animal. Explain the logic you are using in depth and what each line of code is doing, and how you decided to do it that way... :)
     
    Kiwasi likes this.
  33. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    To reiterate: You really do need to break this up. Input does not belong in the same script as checking for valid moves. Checking for valid moves does not belong in the flipping script. Isolating things makes it easier to test and debug.

    You should also look to make your code player agnostic. The logic for blacks move is identical to the logic for whites move.
     
  34. luyao795

    luyao795

    Joined:
    Mar 17, 2016
    Posts:
    33
    Thanks for your suggestion. I have already fixed that bug.