示例#1
0
        //Some explanation here:
        public static List <Point> StonesFromGameState(int[] gs, BoardSetup board)
        {
            List <Point> stones = new List <Point>();

            for (int i = 0; i < gs.Length; i = i + 4)
            {
                Point p = board.GetPoint(new Vector2(gs[i + 1], gs[i + 2]));
                p.stone.turnNumberPlayed = gs[i];
                p.stone.color            = IntToStoneColor(gs[i + 3]);
                stones.Add(p);
            }
            return(stones);
        }
示例#2
0
        public void PlaceStone(Vector2 position, StoneColor color)
        {
            if (gsi.gameOver)
            {
                // Debug.Log("sorry, can't make a move, the game is over!");
                if (TurnResponseEvent != null)
                {
                    TurnResponseEvent.Raise(false);
                }
                if (TurnResponseCodeEvent != null)
                {
                    TurnResponseCodeEvent.Raise(2);
                }
            }

            if (color != gsi.currentTurn)
            {
                //  Debug.Log("Not your turn to play!");
                if (TurnResponseEvent != null)
                {
                    TurnResponseEvent.Raise(false);
                }
                if (TurnResponseCodeEvent != null)
                {
                    TurnResponseCodeEvent.Raise(3);
                }
                return;
            }
            Point point = boardSetup.GetPoint(position);

            if (point != null)
            {
                if (point.stone.color != StoneColor.none)
                {
                    // Debug.Log("Can't Place stone here!");
                    if (TurnResponseEvent != null)
                    {
                        TurnResponseEvent.Raise(false);
                    }
                    if (TurnResponseCodeEvent != null)
                    {
                        TurnResponseCodeEvent.Raise(4);
                    }
                    return;
                }
                else
                {
                    stonesCapturedThisTurn = 0;
                    //Suicide and snapback checks
                    Chain g = null;
                    //I deleted the suicide check for immediate neighbors, because chain liberties should check that anywayyyy?

                    //this is a soft "add" while we do out checks, and we will need to undo them on failures.
                    point.stone.color            = color;
                    point.stone.turnNumberPlayed = gsi.turnNumber;

                    //Oop i have to do ALL OF THIS like three times for a snapback? uh oh//edit this didnt change anything but should have tho, so i'm leaving it.
                    //I think it fixes a bug that i hadnt found yet, with previously defined chains boofing the addNieghborsToChain function, which checks for null chains and add those only so it isnt infinitly recursive
                    //we might be able to check this not with the stone.chain property but if the list in the addneighbros list already contains the stone or not, and get rid of this foreach
                    if (chains != null)//We initialize in a coroutine, so it's possible to try to play in the first few frames and boof everything up.
                    {
                        chains.Clear();

                        for (int i = 0; i < allStones.Count; i++)
                        {
                            allStones[i].stone.chain = null;
                        }
                    }

                    //need to check if the chain we place our stone in, without direct suicide, would become a suicide. That's still invalid.
                    Chain c = new Chain();
                    chains.Add(c);
                    point.stone.chain = c;
                    point.stone.chain.stones.Add(point);
                    c.color = point.stone.color;
                    AddNeighborsToChain(point, c);//This is recursive.

                    //snapback checks
                    bool snapback = false;

                    c.DefineLiberties();//get all open ajacent spots to the chain.
                    if (c.liberties.Count == 0)
                    {
                        //Invalid?

                        //Check if any enemies surrounding the point WOULD be captured.

                        //Begin the process of clearing all of our chains.
                        chains.Clear();
                        for (int i = 0; i < allStones.Count; i++)
                        {
                            allStones[i].stone.chain = null;
                        }
                        //We will have to do this clearing again. it's not optimized code.

                        //First we get the enemies surrounding the point.
                        List <Point> enemyNeighbors = GetEnemyNeighbors(point, color);
                        for (int i = 0; i < enemyNeighbors.Count; i++)
                        {
                            //e is the enemy surrounding the stone we just placed.

                            //First we get the surrounding chain.
                            g = new Chain();

                            if (enemyNeighbors[i].stone.chain == null)
                            {
                                enemyNeighbors[i].stone.chain = g;
                                g.stones.Add(enemyNeighbors[i]);
                                g.color = enemyNeighbors[i].stone.color;
                                AddNeighborsToChain(enemyNeighbors[i], g);//This is recursive.
                            }
                            //So we check if the surrounding enemy neighbor chain has no more liberties now.
                            if (g.stones.Count != 0)
                            {
                                g.DefineLiberties();
                            }

                            if (g.liberties.Count == 0 && g.stones.Count > 0)
                            {
                                //okay, so we CAN place this point.... MAYBE

                                // Debug.Log("Snapback?");
                                snapback = true;

                                //KO rule
                                // One may not capture just one stone if that stone was played on the previous move and that move also captured just one stone.
                                if (snapback && g.stones.Count == 1)
                                {
                                    //ko rule always happens during snapback (???)
                                    if (history.gameHistory[gsi.turnNumber - 1].stonesCapturedThisTurn == 1)
                                    {
                                        if (g.stones[0].stone.turnNumberPlayed == gsi.turnNumber - 1)
                                        {
                                            //undo our placement
                                            point.stone.color            = StoneColor.none;//undo our placement
                                            point.stone.chain            = null;
                                            point.stone.turnNumberPlayed = -1;
                                            if (TurnResponseEvent != null)
                                            {
                                                TurnResponseEvent.Raise(false);
                                            }
                                            if (TurnResponseCodeEvent != null)
                                            {
                                                TurnResponseCodeEvent.Raise(6);
                                            }
                                            return;
                                        }
                                    }
                                }


                                Capture(g); //capture this on before we run the chain iteration but after ko rule because otherwise when we do it later it wont know which chain to capture, and probably capture both?
                                //We can do the rest from below, let it do the rest of the chains (i mean, does it need to?) and calculate points and all that.
                                break;      //if we break ... is it possible to snapback two chains at once?
                            }
                        }

                        ///
///
                        if (!snapback)
                        {
                            ///
                            point.stone.color = StoneColor.none;//undo our placement
                            point.stone.chain = null;
                            // Debug.Log("Cant place stone here, chain suicide!");
                            if (TurnResponseEvent != null)
                            {
                                TurnResponseEvent.Raise(false);
                            }
                            if (TurnResponseCodeEvent != null)
                            {
                                TurnResponseCodeEvent.Raise(5);
                            }
                            return;
                        }
                    }
                    //So we have to build a one of chain from this location?

                    //OR do we just do it, check that something beefed, and then do a history state revert? That feels clumsy.
                    //EXCEPT we might have to do a history state storing and comparing thing ANYWAY because of ko rule.

                    //end suicide and snapbacks.


                    //which feels more ... systematicc



                    //place stone
                    allStones.Add(point);
                    //end placing stone

                    DefineChains();//Defining chains starts the ball rolling on our capture logic too.


                    UpdateTerritoryCounts();//Does a number of recursive things, including going off and tallying the points.


                    history.AddToHistory(gsi.turnNumber, point.stone, stonesCapturedThisTurn, GameStateFromStonesList(allStones), boardSetup);
                    stonesCapturedThisTurn = 0;
                    //Increment the turn counter, switch the player turns.
                    gsi.turnNumber++;
                    gsi.currentTurn = OtherColor(gsi.currentTurn);
                    //Call Stone event to visually place a stone.

                    NewStonePlayedEvent.Raise(point.stone);
                    if (TurnResponseEvent != null)
                    {
                        TurnResponseEvent.Raise(true);
                    }
                    if (TurnResponseCodeEvent != null)
                    {
                        TurnResponseCodeEvent.Raise(1);
                    }
                }
            }
            else
            {
                // Debug.Log("Invalid Position, no point at: "+ position);
                if (TurnResponseEvent != null)
                {
                    TurnResponseEvent.Raise(false);
                }
                if (TurnResponseCodeEvent != null)
                {
                    TurnResponseCodeEvent.Raise(7);
                }
                return;
            }
        }