// find possible attack and return it MGPumAttackCommand findAttack(MGPumField field, MGPumUnit unit, MGPumGameState state) { // can we find this out in a better way? queued = new bool[8, 8]; tilesToVisit = new SortedSet <Vector2Int>(new AStarComparer(field.coords)); predecessors = new Dictionary <Vector2Int, Vector2Int>(); //distance = new Dictionary<Vector2Int, int>(); tilesToVisit.Add(unit.field.coords); queued[unit.field.coords.x, unit.field.coords.y] = true; int recursion = 0; int maxRecursion = 500; while (tilesToVisit.Count > 0) { recursion++; if (recursion > maxRecursion) { break; } Vector2Int position = tilesToVisit.Min; tilesToVisit.Remove(position); if (!state.fields.inBounds(position)) { continue; } //touchedTiles.Add(position); if (position == field.coords) { List <Vector2Int> path = new List <Vector2Int>(); path.Add(position); //reconstruct path in reverse while (predecessors.ContainsKey(path[0])) { path.Insert(0, predecessors[path[0]]); } MGPumAttackChainMatcher matcher = unit.getAttackMatcher(); MGPumFieldChain chain = new MGPumFieldChain(unit.ownerID, matcher); for (int i = 0; i < path.Count; i++) { chain.add(state.getField(path[i])); } if (chain.isValidChain()) { MGPumAttackCommand ac = new MGPumAttackCommand(this.playerID, chain, unit); return(ac); } continue; } foreach (Vector2Int direction in getDirections()) { Vector2Int neighbor = position + direction; if (!state.fields.inBounds(neighbor)) { continue; } if (!queued[neighbor.x, neighbor.y]) { queued[neighbor.x, neighbor.y] = true; tilesToVisit.Add(neighbor); predecessors.Add(neighbor, position); //distance.Add(neighbor, ) } } } return(null); }
// method to score a move command private int scoreMove(MGPumMoveCommand move) { int score = 0; MGPumGameState copiedState = state.deepCopy(); MGPumAIPlayerDummyController dummy1 = new MGPumAIPlayerDummyController(playerID); MGPumAIPlayerDummyController dummy2 = new MGPumAIPlayerDummyController(1 - playerID); MGPumGameController copiedController = new MGPumGameController(dummy1, dummy2, copiedState); copiedController.acceptCommand(move); MGPumUnit copiedUnit = null; if (copiedController.state.getUnitForField(move.chain.getLast()) != null) { copiedUnit = copiedController.state.getUnitForField(move.chain.getLast()); } else { // this should never happen, but just in case we give it a really bad score return(-1000); } // get fields for different vision ranges List <MGPumField> possibleEnemyFields = getPossibleEnemyFields(copiedUnit, copiedState, 0); List <MGPumField> possibleEnemyFieldsExtraRange = getPossibleEnemyFields(copiedUnit, copiedState, 2); List <MGPumField> possibleEnemyFieldsExtraRangeKing = getPossibleEnemyFields(copiedUnit, copiedState, 1); List <MGPumField> allyFields = getAllyFields(copiedUnit, copiedState); foreach (MGPumField allyField in allyFields) { // if Bummz is nearby, reduce score if (state.getUnitForField(allyField).unitID == "PUM007") { score -= 5; } } //Debug.Log("Move: " + move); //Debug.Log("Possible Enemy Fields Count: " + possibleEnemyFields.Count); // if buffy or haley find a move to reach a lot of allies, score will be increased if (state.getUnitForField(move.chain.getFirst()).unitID == "PUM013" || state.getUnitForField(move.chain.getFirst()).unitID == "PUM014") { score += (allyFields.Count * 3); } // if unit is bummz, get away from teammates and go towards enemies if (state.getUnitForField(move.chain.getFirst()).unitID == "PUM007") { score += (possibleEnemyFieldsExtraRange.Count * 5); score -= (allyFields.Count * 2); } else if (state.getUnitForField(move.chain.getFirst()).unitID == "PUM004") { // Wolli should tank, sending him towards enemies rewards points score += (possibleEnemyFieldsExtraRange.Count * 3); } else if (state.getUnitForField(move.chain.getFirst()).unitID == "PUM008") { // the more wounded our king is, the higher the penalty for stepping near enemies score -= (possibleEnemyFieldsExtraRangeKing.Count * (state.getUnitForField(move.chain.getFirst()).damage + 1)); } else { // the more enemies in attack range of the unit, the higher the penalty score -= (possibleEnemyFields.Count * 3); } // method in case no prior weighting has been given if (score == 0) { Debug.Log("Score ist 0"); List <MGPumField> allEnemyFields = getPossibleEnemyFields(copiedUnit, copiedState, 7); foreach (MGPumField enemyField in allEnemyFields) { // move towards enemies if (Vector2Int.Distance(move.chain.getFirst().coords, enemyField.coords) > Vector2Int.Distance(move.chain.getLast().coords, enemyField.coords)) { score += 1; break; } } } //Debug.Log("Score sollte hier negativ sein: " + score); List <MGPumAttackCommand> attackCommands = new List <MGPumAttackCommand>(); int bestAttackScore = 0; MGPumAttackCommand bestAttackCommand = null; foreach (MGPumField enemyField in possibleEnemyFields) { MGPumAttackCommand attackCommand = findAttack(enemyField, copiedUnit, copiedState); //Debug.Log(attackCommand); if (attackCommand != null) { attackCommands.Add(attackCommand); } } if (attackCommands.Count > 0) { foreach (MGPumAttackCommand ac in attackCommands) { int attackScore = scoreAttack(ac); if (attackScore >= bestAttackScore) { bestAttackScore = attackScore; bestAttackCommand = ac; } } } // final score is based on movement score and attack score score += bestAttackScore; //Debug.Log("Best Move Score: " + bestAttackScore); //Debug.Log("Best Move: "+ bestAttackCommand); return(score); }
// return a list of fields where allied units are standing List <MGPumField> getAllyFields(MGPumUnit unit, MGPumGameState state) { List <MGPumField> possibleFields = new List <MGPumField>(); Vector2Int position = unit.field.coords; MGPumField field = new MGPumField(unit.coords.x, unit.coords.y); MGPumUnit foundUnit = null; for (int horizontal = 0; horizontal <= unit.currentSpeed; horizontal++) { for (int vertical = 0; vertical <= unit.currentSpeed; vertical++) { if (state.getField(position + Vector2Int.up * vertical + Vector2Int.left * horizontal) != null) { field = state.getField(position + Vector2Int.up * vertical + Vector2Int.left * horizontal); foundUnit = state.getUnitForField(field); if (foundUnit != null) { if (!possibleFields.Contains(field) && field.coords != position && state.fields.inBounds(field.coords) && foundUnit.ownerID == unit.ownerID) { possibleFields.Add(field); } } } if (state.getField(position + Vector2Int.up * vertical + Vector2Int.right * horizontal) != null) { field = state.getField(position + Vector2Int.up * vertical + Vector2Int.right * horizontal); foundUnit = state.getUnitForField(field); if (foundUnit != null) { if (!possibleFields.Contains(field) && field.coords != position && state.fields.inBounds(field.coords) && foundUnit.ownerID == unit.ownerID) { possibleFields.Add(field); } } } if (state.getField(position + Vector2Int.down * vertical + Vector2Int.left * horizontal) != null) { field = state.getField(position + Vector2Int.down * vertical + Vector2Int.left * horizontal); foundUnit = state.getUnitForField(field); if (foundUnit != null) { if (!possibleFields.Contains(field) && field.coords != position && state.fields.inBounds(field.coords) && foundUnit.ownerID == unit.ownerID) { possibleFields.Add(field); } } } if (state.getField(position + Vector2Int.down * vertical + Vector2Int.right * horizontal) != null) { field = state.getField(position + Vector2Int.down * vertical + Vector2Int.right * horizontal); foundUnit = state.getUnitForField(field); if (foundUnit != null) { if (!possibleFields.Contains(field) && field.coords != position && state.fields.inBounds(field.coords) && foundUnit.ownerID == unit.ownerID) { possibleFields.Add(field); } } } } } return(possibleFields); }