示例#1
0
        private Result getMin(int curDepth, int agentIdx, ClientGameState curState)
        {
            double min = Double.MaxValue;
            ActionSet bestActions = new ActionSet(curState.Me.units.Count);
            int opponentIdx = (curState.myPlayerIdx + 1) % 2;
            List<ActionSet> legalActions = curState.GetLegalActions(opponentIdx);

            foreach (ActionSet action in legalActions)
            {
                ClientGameState successor = new ClientGameState(curState);
                for (int unitIdx = 0; unitIdx < successor.Opponent.units.Count; unitIdx++)
                {
                    successor.Opponent.units[unitIdx].action = action[unitIdx];
                }
                successor.UpdateGameState();
                int nextAgentIdx = (agentIdx + 1) % 2;

                Result result = this.getNode(curDepth, nextAgentIdx, successor);
                if (result.Score < min)
                {
                    min = result.Score;
                    action.CopyTo(bestActions);
                }
            }

            return new Result(min, bestActions);
        }
        private Result getMax(int curDepth, int agentIdx, ClientGameState curState, double alpha, double beta)
        {
            List<ActionSet> legalActions;
            double max = Double.MinValue;
            ActionSet bestActions = new ActionSet(curState.Me.units.Count);
            if (curDepth < this.searchDepth)
            {
                legalActions = curState.GetLegalActions(curState.myPlayerIdx);
            }
            else
            {
                legalActions = new List<ActionSet>();
                legalActions.Add(bestActions);
            }
            if (legalActions.Count < 1)
            {
                return new Result(-1000, bestActions);
            }

            foreach (ActionSet action in legalActions)
            {
                //Program.abDebug.Write("[" + action.ToString() + "]");
                ClientGameState successor = new ClientGameState(curState);
                for (int unitIdx = 0; unitIdx < successor.Me.units.Count; unitIdx++)
                {
                    successor.Me.units[unitIdx].action = action[unitIdx];
                }
                int nextAgentIdx = (agentIdx + 1) % 2;

                moveStack.Push(action);
                Result result = this.getNode(curDepth, nextAgentIdx, successor, alpha, beta);
                if (curDepth == 0)
                {
                    debugWindow.AddLog(action.ToString() + " : " + result.Score);
                }
                if (result.Score > max)
                {
                    max = result.Score;
                    //Program.abDebug.WriteLine("Max at " + curDepth + " : " + max);
                    action.CopyTo(bestActions);
                    alpha = max;
                    if (curDepth == 0)
                    {
                        for( int idx=0; idx<curState.Me.units.Count; idx++)
                        {
                            Program.MainForm.SetAction(curState.myPlayerIdx, curState.Me.units[idx].id, bestActions[idx]);
                        }
                    }
                }
                moveStack.Pop();
                if (max > beta)
                {
                    //Program.abDebug.WriteLine("Beta Cutoff");
                    this.cutoffs++;
                    break;
                }
            }

            return new Result(max, bestActions);
        }
示例#3
0
        public void CopyTo(ActionSet target)
        {
            for (int idx = 0; idx < this.actions.Length; idx++)
            {
                if (idx >= target.actions.Length) break;

                target.actions[idx] = this.actions[idx];
            }
        }
        public List<ActionSet> GetLegalActions(int playerIdx)
        {
            List<ActionSet> result = new List<ActionSet>();

            Player player = this.players[playerIdx];
            if (player.units.Count < 1)
            {
                return result;
            }

            bool test;
            ActionSet actionSet;
            foreach (Action act1 in Enum.GetValues(typeof(Action)))
            {
                actionSet = new ActionSet(act1, Action.NONE);
                test = this.isPseudoLegal(playerIdx, actionSet);
                if (test == false)
                {
                    continue;
                }
                result.Add(actionSet);

                if (player.units.Count > 1)
                {
                    foreach (Action act2 in Enum.GetValues(typeof(Action)))
                    {
                        if (act2 == Action.NONE)
                        {
                            continue;
                        }

                        actionSet = new ActionSet(act1, act2);
                        test = this.isPseudoLegal(playerIdx, actionSet);
                        if (test == false)
                        {
                            continue;
                        }

                        result.Add(actionSet);
                    }
                }
            }

            //result.Reverse();
            return result;
        }
        private void applyPlayerMovement(int playerIdx, ActionSet actions)
        {
            int newX, newY;
            bool blocked = false;

            //bool test = isPseudoLegal(playerIdx, actions);
            for (int unitIdx = 0; unitIdx < this.players[playerIdx].units.Count; unitIdx++)
            {
                Unit tank = this.players[playerIdx].units[unitIdx];
                blocked = false;

                switch (actions[unitIdx])
                {
                    case Action.NONE:
                    case Action.FIRE:
                        break;
                    case Action.LEFT:
                        newX = tank.x - 1;
                        newY = tank.y;

                        if (newX < 2) throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move LEFT(Left Border Reached)");
                        for (int uy = newY - 2; uy <= newY + 2; uy++)
                        {
                            if (this.blocks[newX - 2, uy] != State.EMPTY)
                            {
                                if (tank.direction == Direction.LEFT)
                                {
                                    throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move LEFT(Wall Hit and Already facing Left)");
                                }
                                blocked = true;
                            }
                        }
                        if (anyUnitAt(newX, newY, tank) != null) blocked = true;

                        if (!blocked) this.players[playerIdx].units[unitIdx].x--;
                        this.players[playerIdx].units[unitIdx].direction = Direction.LEFT;
                        break;
                    case Action.RIGHT:
                        newX = tank.x + 1;
                        newY = tank.y;

                        if (newX >= this.BoardWidth - 2) throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move RIGHT(Right Border Reached)");
                        for (int uy = newY - 2; uy <= newY + 2; uy++)
                        {
                            if (this.blocks[newX + 2, uy] != State.EMPTY)
                            {
                                if (tank.direction == Direction.RIGHT)
                                {
                                    throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move RIGHT(Wall Hit and Already facing Right)");
                                }
                                blocked = true;
                            }
                        }
                        if (anyUnitAt(newX, newY, tank) != null) blocked = true;

                        if (!blocked) this.players[playerIdx].units[unitIdx].x++;
                        this.players[playerIdx].units[unitIdx].direction = Direction.RIGHT;
                        break;
                    case Action.UP:
                        newX = tank.x;
                        newY = tank.y - 1;

                        if (newY < 2) throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move UP(Top Border Reached)");
                        for (int ux = newX - 2; ux <= newX + 2; ux++)
                        {
                            if (this.blocks[ux, newY - 2] != State.EMPTY)
                            {
                                if (tank.direction == Direction.UP)
                                {
                                    throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move UP(Wall Hit and Already facing Up)");
                                }
                                blocked = true;
                            }
                        }
                        if (anyUnitAt(newX, newY, tank) != null) blocked = true;

                        if (!blocked) this.players[playerIdx].units[unitIdx].y--;
                        this.players[playerIdx].units[unitIdx].direction = Direction.UP;
                        break;
                    case Action.DOWN:
                        newX = tank.x;
                        newY = tank.y + 1;

                        if (newY >= this.BoardHeight - 2) throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move DOWN(Bottom Border Reached)");
                        for (int ux = newX - 2; ux <= newX + 2; ux++)
                        {
                            if (this.blocks[ux, newY + 2] != State.EMPTY)
                            {
                                if (tank.direction == Direction.DOWN)
                                {
                                    throw new InvalidOperationException("Player " + playerIdx + " Tank " + unitIdx + " : Illegal Move DOWN(Wall Hit and Already facing Down)");
                                }
                                blocked = true;
                            }
                        }
                        if (anyUnitAt(newX, newY, tank) != null) blocked = true;

                        if (!blocked) this.players[playerIdx].units[unitIdx].y++;
                        this.players[playerIdx].units[unitIdx].direction = Direction.DOWN;
                        break;
                }
            }
        }
        private void applyPlayerFire(int playerIdx, ActionSet actions)
        {
            for (int unitIdx = 0; unitIdx < this.players[playerIdx].units.Count; unitIdx++)
            {
                Unit sourceTank = this.players[playerIdx].units[unitIdx];

                switch (actions[unitIdx])
                {
                    case Action.FIRE:
                        switch (sourceTank.direction)
                        {
                            case Direction.UP:
                                this.players[playerIdx].bullets.Add(new Bullet(sourceTank.x, sourceTank.y - 3, Direction.UP));
                                break;
                            case Direction.DOWN:
                                this.players[playerIdx].bullets.Add(new Bullet(sourceTank.x, sourceTank.y + 3, Direction.DOWN));
                                break;
                            case Direction.LEFT:
                                this.players[playerIdx].bullets.Add(new Bullet(sourceTank.x - 3, sourceTank.y, Direction.LEFT));
                                break;
                            case Direction.RIGHT:
                                this.players[playerIdx].bullets.Add(new Bullet(sourceTank.x + 3, sourceTank.y, Direction.RIGHT));
                                break;
                        }
                        break;
                }
            }
        }
        public void UpdateGameState()
        {
            this.moveBullets(0);
            this.checkCollisions(false);
            this.moveBullets(1);
            this.checkCollisions(false);

            this.moveBullets(0);
            this.checkCollisions(true);
            this.moveBullets(1);
            this.checkCollisions(true);

            for (int playerIdx = 0; playerIdx < 2; playerIdx++)
            {
                ActionSet actions = new ActionSet(this.players[playerIdx].units.Count);
                for (int unitIdx = 0; unitIdx < this.players[playerIdx].units.Count; unitIdx++)
                {
                    actions[unitIdx] = this.players[playerIdx].units[unitIdx].action;
                }

                this.applyPlayerMovement(playerIdx, actions);
            }

            this.checkCollisions(false);

            for (int playerIdx = 0; playerIdx < 2; playerIdx++)
            {
                ActionSet actions = new ActionSet(this.players[playerIdx].units.Count);
                for (int unitIdx = 0; unitIdx < this.players[playerIdx].units.Count; unitIdx++)
                {
                    actions[unitIdx] = this.players[playerIdx].units[unitIdx].action;
                }

                this.applyPlayerFire(playerIdx, actions);
            }

            this.checkCollisions(false);
        }
        public bool isPseudoLegal(int playerIdx, ActionSet actions)
        {
            int newX, newY;

            for (int unitIdx = 0; unitIdx < this.players[playerIdx].units.Count; unitIdx++)
            {
                Unit tank = this.players[playerIdx].units[unitIdx];

                switch (actions[unitIdx])
                {
                    case Action.NONE:
                    case Action.FIRE:
                        break;
                    case Action.LEFT:
                        newX = tank.x - 1;
                        newY = tank.y;

                        if (newX < 2) return false;
                        for (int uy = newY - 2; uy <= newY + 2; uy++)
                        {
                            if ((this.blocks[newX - 2, uy] != State.EMPTY) && (tank.direction == Direction.LEFT)) return false;
                        }
                        break;
                    case Action.RIGHT:
                        newX = tank.x + 1;
                        newY = tank.y;

                        if (newX >= this.BoardWidth - 2) return false;
                        for (int uy = newY - 2; uy <= newY + 2; uy++)
                        {
                            if ((this.blocks[newX + 2, uy] != State.EMPTY) && (tank.direction == Direction.RIGHT)) return false;
                        }
                        break;
                    case Action.UP:
                        newX = tank.x;
                        newY = tank.y - 1;

                        if (newY < 2) return false;
                        for (int ux = newX - 2; ux <= newX + 2; ux++)
                        {
                            if ((this.blocks[ux, newY - 2] != State.EMPTY) && (tank.direction == Direction.UP)) return false;
                        }
                        break;
                    case Action.DOWN:
                        newX = tank.x;
                        newY = tank.y + 1;

                        if (newY >= this.BoardHeight - 2) return false;
                        for (int ux = newX - 2; ux <= newX + 2; ux++)
                        {
                            if ((this.blocks[ux, newY + 2] != State.EMPTY) && (tank.direction == Direction.DOWN)) return false;
                        }
                        break;
                    default:
                        return false;
                }
            }

            return true;
        }
示例#9
0
        private Result getNode(int curDepth, int agentIdx, ClientGameState curState)
        {
            Player me = curState.Me;
            Player opponent = curState.Opponent;

            this.nodesSearched++;
            if (agentIdx == 0) {
                curDepth++;
                if (nodesSearched % 1000 == 0)
                {
                    this.debugWindow.AddLog("Searched " + this.nodesSearched + " nodes...");
                }
            } else {
                me = curState.Opponent;
                opponent = curState.Me;
            }

            if ((curDepth == this.searchDepth) || (curState.Won == true) || (curState.Lost == true))
            {
                double score = curState.Evaluate();
                ActionSet actions = new ActionSet(me.units.Count);
                for (int idx = 0; idx < me.units.Count; idx++)
                {
                    actions[idx] = Action.NONE;
                }

                return new Result(score, actions);
            }

            Result result;
            if (agentIdx == 0)
            {
                result = this.getMax(curDepth, agentIdx, curState);
            }
            else
            {
                result = this.getMin(curDepth, agentIdx, curState);
            }

            return result;
        }
示例#10
0
 public Result(double score, ActionSet actions)
 {
     this.Score = score;
     this.Actions = actions;
 }
示例#11
0
        private Result getNode(int curDepth, int agentIdx, ClientGameState curState, double alpha, double beta)
        {
            Player me = curState.Me;
            Player opponent = curState.Opponent;

            this.nodesSearched++;
            if (agentIdx == 0) {
                curDepth++;
                if (nodesSearched % 1000 == 0)
                {
                    this.debugWindow.AddLog("Searched " + this.nodesSearched + " nodes...");
                }
            } else {
                me = curState.Opponent;
                opponent = curState.Me;
            }

            if (me.bullets.Count < 1 || curDepth > 15)
            {
            #if DEBUG
                if ((curDepth >= this.searchDepth) || (curState.Won == true) || (curState.Lost == true))
            #else
            if ((curDepth == this.searchDepth) || (curState.Won == true) || (curState.Lost == true) || (searchDuration.ElapsedMilliseconds > 2800))
            #endif
                {
                    double score = curState.Evaluate();
                    //Program.abDebug.WriteLine(String.Join(",", moveStack) + " - " + curDepth.ToString() + ":" + score.ToString());
                    ActionSet actions = new ActionSet(me.units.Count);
                    for (int idx = 0; idx < me.units.Count; idx++)
                    {
                        actions[idx] = Action.NONE;
                    }

                    return new Result(score, actions);
                }
            }

            Result result;
            if (agentIdx == 0)
            {
                result = this.getMax(curDepth, agentIdx, curState, alpha, beta);
            }
            else
            {
                result = this.getMin(curDepth, agentIdx, curState, alpha, beta);
            }

            return result;
        }
示例#12
0
        private Result getMin(int curDepth, int agentIdx, ClientGameState curState, double alpha, double beta)
        {
            List<ActionSet> legalActions;
            double min = Double.MaxValue;
            ActionSet bestActions = new ActionSet(curState.Opponent.units.Count);
            int opponentIdx = (curState.myPlayerIdx + 1) % 2;
            if (curDepth < this.searchDepth)
            {
                legalActions = curState.GetLegalActions(opponentIdx);
            }
            else
            {
                legalActions = new List<ActionSet>();
                legalActions.Add(bestActions);
            }
            if (legalActions.Count < 1)
            {
                return new Result(1000, bestActions);
            }

            foreach (ActionSet action in legalActions)
            {
                //Program.abDebug.Write("[" + action.ToString() + "]");
                ClientGameState successor = new ClientGameState(curState);
                for (int unitIdx = 0; unitIdx < successor.Opponent.units.Count; unitIdx++)
                {
                    successor.Opponent.units[unitIdx].action = action[unitIdx];
                }
                successor.UpdateGameState();
                int nextAgentIdx = (agentIdx + 1) % 2;
                moveStack.Push(action);
                Result result = this.getNode(curDepth, nextAgentIdx, successor, alpha, beta);
                if (result.Score < min)
                {
                    min = result.Score;
                    //Program.abDebug.WriteLine("Min at " + curDepth + " : " + min);
                    action.CopyTo(bestActions);
                    beta = min;
                }
                moveStack.Pop();
                if (min < alpha)
                {
                    //Program.abDebug.WriteLine("Alpha Cutoff");
                    this.cutoffs++;
                    break;
                }
            }

            return new Result(min, bestActions);
        }