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); }
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); }
public ActionSet GetAction(ClientGameState myState) { Stopwatch searchDuration = new Stopwatch(); this.nodesSearched = 0; searchDuration.Start(); Result best = this.getNode(-1, 0, myState); searchDuration.Stop(); this.debugWindow.AddLog("Depth " + this.searchDepth + " searched " + this.nodesSearched + " nodes in " + searchDuration.ElapsedMilliseconds + "ms"); return best.Actions; }
public ActionSet GetAction(ClientGameState myState) { this.nodesSearched = 0; this.cutoffs = 0; this.moveStack.Clear(); this.searchDuration.Restart(); double alpha = double.MinValue; double beta = double.MaxValue; Result best = this.getNode(-1, 0, myState, alpha, beta); searchDuration.Stop(); this.debugWindow.AddLog("Depth " + this.searchDepth + " searched " + this.nodesSearched + " nodes(" + this.cutoffs + " cutoffs) in " + searchDuration.ElapsedMilliseconds + "ms"); return best.Actions; }
public ClientGameState(ClientGameState source) : base(source) { this.myPlayerIdx = source.myPlayerIdx; }
public void UpdateState(ClientGameState newState) { this.state = newState; canvas.Invalidate(); }
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; }
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); }
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; }
private void player2Worker_DoWork(object sender, DoWorkEventArgs e) { Random rnd = new Random(); State[,] layout = Program.MainForm.Login("Player 2"); GameState initialState = Program.MainForm.GetStatus(1); IAgent agent = new AlphaBetaAgent(p2Debug); ClientGameState myState = new ClientGameState(layout, initialState, 1); myState.currentTick = -1; #if DEBUG p2Debug.UpdateState(myState); Application.DoEvents(); #endif while (player2Worker.CancellationPending == false) { GameState curState = Program.MainForm.GetStatus(1); if (curState.events.blockEvents.Count > 0) { p2Debug.AddLog("Player 2 received " + curState.events.blockEvents.Count + " unseen block events"); myState.ProcessEvents(curState.events); } if (curState.currentTick > myState.currentTick) { myState = new ClientGameState(myState.blocks, curState, 1); myState.ProcessEvents(curState.events); #if DEBUG p2Debug.UpdateState(myState); Application.DoEvents(); #endif RandomAgent(rnd, myState, p2Debug); } Thread.Sleep(100); } }
private void player1Worker_DoWork(object sender, DoWorkEventArgs e) { Random rnd = new Random(); State[,] layout = Program.MainForm.Login("Player 1"); GameState initialState = Program.MainForm.GetStatus(0); IAgent agent = new AlphaBetaAgent(p1Debug); ClientGameState myState = new ClientGameState(layout, initialState, 0); myState.currentTick = -1; #if DEBUG p1Debug.UpdateState(myState); Application.DoEvents(); #endif while (player1Worker.CancellationPending == false) { GameState curState = Program.MainForm.GetStatus(0); if (curState.events.blockEvents.Count > 0) { p1Debug.AddLog("Player 1 received " + curState.events.blockEvents.Count + " unseen block events"); myState.ProcessEvents(curState.events); } if (curState.currentTick > myState.currentTick) { myState = new ClientGameState(myState.blocks, curState, 0); myState.ProcessEvents(curState.events); #if DEBUG p1Debug.UpdateState(myState); Application.DoEvents(); #endif ActionSet actions = agent.GetAction(myState); for (int idx = 0; idx < myState.Me.units.Count; idx++) { p1Debug.AddLog("Unit " + idx + " : Action=" + actions[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.players[myState.myPlayerIdx].units[idx].id, actions[idx]); } } Thread.Sleep(100); } }
private static void RandomAgent(Random rnd, ClientGameState myState, AIDebugWindow debugWin) { List<ActionSet> legalActions = myState.GetLegalActions(myState.myPlayerIdx); if (legalActions.Count < 1) { return; } int pickActions = rnd.Next(legalActions.Count); ActionSet picked = legalActions[pickActions]; for (int idx = 0; idx < myState.players[myState.myPlayerIdx].units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + picked[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.players[myState.myPlayerIdx].units[idx].id, picked[idx]); } }
private static void GoalAgent(Random rnd, ClientGameState myState, AIDebugWindow debugWin) { int avoidedLosing = 0; List<ActionSet> legalActions = myState.GetLegalActions(myState.myPlayerIdx); if (legalActions.Count < 1) { return; } List<ActionSet> validActions = new List<ActionSet>(); foreach(ActionSet action in legalActions) { ClientGameState afterState = new ClientGameState(myState); for (int unitIdx = 0; unitIdx < afterState.Me.units.Count; unitIdx++) { afterState.Me.units[unitIdx].action = action[unitIdx]; } for (int unitIdx = 0; unitIdx < afterState.Opponent.units.Count; unitIdx++) { afterState.Opponent.units[unitIdx].action = Action.NONE; } afterState.UpdateGameState(); if (afterState.Lost == false) { validActions.Add(action); } else { avoidedLosing++; } } if (validActions.Count < 1) { return; } int closestTankIdx = -1; Size closestTankDist = new Size(myState.BoardWidth, myState.BoardHeight); Player me = myState.Me; Player enemy = myState.Opponent; for (int idx = 0; idx < me.units.Count; idx++) { Unit tank = me.units[idx]; Size distToEnemyBase = Utils.DistanceBetween(tank, enemy.playerBase); if (distToEnemyBase.Width + distToEnemyBase.Height < closestTankDist.Width + closestTankDist.Height) { closestTankDist = distToEnemyBase; closestTankIdx = idx; } } Unit closestTank = me.units[closestTankIdx]; Action desiredAction = Action.NONE; if (closestTankDist.Height == 0) { //Vertically aligned with enemy base, so check if we are facing the right direction if (closestTankDist.Width < 0 && closestTank.direction != Direction.RIGHT) { desiredAction = Action.RIGHT; } else if (closestTankDist.Width > 0 && closestTank.direction != Direction.LEFT) { desiredAction = Action.LEFT; } else { // We are aligned and facing the right direction, so start shooting desiredAction = Action.FIRE; } } else if (closestTankDist.Width == 0) { //Horizontally aligned with enemy base, so check if we are facing the right direction if (closestTankDist.Height < 0 && closestTank.direction != Direction.DOWN) { desiredAction = Action.DOWN; } else if (closestTankDist.Height > 0 && closestTank.direction != Direction.UP) { desiredAction = Action.UP; } else { // We are aligned and facing the right direction, so start shooting desiredAction = Action.FIRE; } } else { // We still need to get in position... let's see if we can if (Math.Abs(closestTankDist.Width) <= Math.Abs(closestTankDist.Height)) { if (closestTankDist.Width < 0) { desiredAction = Action.RIGHT; } else { desiredAction = Action.LEFT; } } else { if (closestTankDist.Height < 0) { desiredAction = Action.DOWN; } else { desiredAction = Action.UP; } } } foreach (ActionSet actionSet in validActions) { if (actionSet[closestTankIdx] == desiredAction) { for (int idx = 0; idx < myState.Me.units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + actionSet[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.Me.units[idx].id, actionSet[idx]); } return; } } switch(desiredAction) { case Action.RIGHT: if ((closestTank.direction == Direction.RIGHT) && (myState.blocks[closestTank.x + 3, closestTank.y] == State.FULL)) desiredAction = Action.FIRE; break; case Action.LEFT: if ((closestTank.direction == Direction.LEFT) && (myState.blocks[closestTank.x - 3, closestTank.y] == State.FULL)) desiredAction = Action.FIRE; break; case Action.UP: if ((closestTank.direction == Direction.UP) && (myState.blocks[closestTank.x, closestTank.y - 3] == State.FULL)) desiredAction = Action.FIRE; break; case Action.DOWN: if ((closestTank.direction == Direction.DOWN) && (myState.blocks[closestTank.x, closestTank.y + 3] == State.FULL)) desiredAction = Action.FIRE; break; } foreach (ActionSet actionSet in validActions) { if (actionSet[closestTankIdx] == desiredAction) { for (int idx = 0; idx < myState.Me.units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + actionSet[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.Me.units[idx].id, actionSet[idx]); } return; } } int pickActions = rnd.Next(validActions.Count); ActionSet picked = validActions[pickActions]; for (int idx = 0; idx < myState.Me.units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + picked[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.players[myState.myPlayerIdx].units[idx].id, picked[idx]); } }
private static void BruteForceAgent(Random rnd, ClientGameState myState, AIDebugWindow debugWin) { int closestTankIdx = -1; Size closestTankDist = new Size(myState.BoardWidth,myState.BoardHeight); List<ActionSet> legalActions = myState.GetLegalActions(myState.myPlayerIdx); if (legalActions.Count < 1) { return; } Player me = myState.Me; Player enemy = myState.Opponent; for (int idx = 0; idx < me.units.Count; idx++) { Unit tank = me.units[idx]; Size distToEnemyBase = Utils.DistanceBetween(tank, enemy.playerBase); if (distToEnemyBase.Width + distToEnemyBase.Height < closestTankDist.Width + closestTankDist.Height) { closestTankDist = distToEnemyBase; closestTankIdx = idx; } } Unit closestTank = me.units[closestTankIdx]; Action desiredAction = Action.NONE; if (closestTankDist.Height == 0) { //Vertically aligned with enemy base, so check if we are facing the right direction if (closestTankDist.Width < 0 && closestTank.direction != Direction.RIGHT) { desiredAction = Action.RIGHT; } else if (closestTankDist.Width > 0 && closestTank.direction != Direction.LEFT) { desiredAction = Action.LEFT; } else { // We are aligned and facing the right direction, so start shooting desiredAction = Action.FIRE; } } else if (closestTankDist.Width == 0) { //Horizontally aligned with enemy base, so check if we are facing the right direction if (closestTankDist.Height < 0 && closestTank.direction != Direction.DOWN) { desiredAction = Action.DOWN; } else if (closestTankDist.Height > 0 && closestTank.direction != Direction.UP) { desiredAction = Action.UP; } else { // We are aligned and facing the right direction, so start shooting desiredAction = Action.FIRE; } } else { // We still need to get in position... let's see if we can if (Math.Abs(closestTankDist.Width) <= Math.Abs(closestTankDist.Height)) { if (closestTankDist.Width < 0) { desiredAction = Action.RIGHT; } else { desiredAction = Action.LEFT; } } else { if (closestTankDist.Height < 0) { desiredAction = Action.DOWN; } else { desiredAction = Action.UP; } } } foreach (ActionSet actionSet in legalActions) { if (actionSet[closestTankIdx] == desiredAction) { for (int idx = 0; idx < myState.players[myState.myPlayerIdx].units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + actionSet[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.players[myState.myPlayerIdx].units[idx].id, actionSet[idx]); } return; } } int pickActions = rnd.Next(legalActions.Count); ActionSet picked = legalActions[pickActions]; for (int idx = 0; idx < myState.players[myState.myPlayerIdx].units.Count; idx++) { debugWin.AddLog("Unit " + idx + " : Action=" + picked[idx]); Program.MainForm.SetAction(myState.myPlayerIdx, myState.players[myState.myPlayerIdx].units[idx].id, picked[idx]); } }