Skip to content
This repository has been archived by the owner on Aug 21, 2023. It is now read-only.

Commit

Permalink
Battle Attacker AI First Finished
Browse files Browse the repository at this point in the history
  • Loading branch information
Mo-enen committed Aug 11, 2021
1 parent 753d5a8 commit aad1ec4
Show file tree
Hide file tree
Showing 15 changed files with 847 additions and 135 deletions.
75 changes: 73 additions & 2 deletions Assets/Battle Soup AI/Core/Data.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,77 @@ public Int2 (int x, int y) {
this.x = x;
this.y = y;
}
public static Int2 operator + (Int2 a, Int2 b) {
a.x += b.x;
a.y += b.y;
return a;
}
public static Int2 operator - (Int2 a, Int2 b) {
a.x -= b.x;
a.y -= b.y;
return a;
}
public static Int2 operator * (Int2 a, Int2 b) {
a.x *= b.x;
a.y *= b.y;
return a;
}
public static Int2 operator / (Int2 a, Int2 b) {
a.x /= b.x;
a.y /= b.y;
return a;
}
public static Int2 operator * (Int2 a, int b) {
a.x *= b;
a.y *= b;
return a;
}
public static Int2 operator / (Int2 a, int b) {
a.x /= b;
a.y /= b;
return a;
}
public override string ToString () => $"({x},{y})";
}


public struct Float2 {
public float x;
public float y;
public Float2 (float x, float y) {
this.x = x;
this.y = y;
}
public static Float2 operator + (Float2 a, Float2 b) {
a.x += b.x;
a.y += b.y;
return a;
}
public static Float2 operator - (Float2 a, Float2 b) {
a.x -= b.x;
a.y -= b.y;
return a;
}
public static Float2 operator * (Float2 a, Float2 b) {
a.x *= b.x;
a.y *= b.y;
return a;
}
public static Float2 operator / (Float2 a, Float2 b) {
a.x /= b.x;
a.y /= b.y;
return a;
}
public static Float2 operator * (Float2 a, float b) {
a.x *= b;
a.y *= b;
return a;
}
public static Float2 operator / (Float2 a, float b) {
a.x /= b;
a.y /= b;
return a;
}
}


Expand Down Expand Up @@ -250,7 +321,7 @@ public bool Symmetry {


// API
public (Int2 min, Int2 max) GetBounds (ShipPosition pos) {
public (Int2 min, Int2 max) GetBounds (bool flip) {
int minX = int.MaxValue;
int minY = int.MaxValue;
int maxX = int.MinValue;
Expand All @@ -261,7 +332,7 @@ public bool Symmetry {
maxX = System.Math.Max(maxX, v.x);
maxY = System.Math.Max(maxY, v.y);
}
return pos.Flip ?
return flip ?
(new Int2(minY, minX), new Int2(maxY, maxX)) :
(new Int2(minX, minY), new Int2(maxX, maxY));
}
Expand Down
130 changes: 68 additions & 62 deletions Assets/Battle Soup AI/Core/SoupStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public int AliveShipCount {
public int[] Cooldowns;
public bool[] ShipsAlive;
public ShipPosition?[] KnownPositions;
public List<SonarPosition> Sonars;

}


Expand Down Expand Up @@ -82,7 +84,7 @@ public abstract class SoupStrategy {
// Data
private int[,] RIP_ValuesCache = null;
private int[,,] RIP_ValuesCacheAlt = null;
private static System.Random Random = new System.Random();
protected static System.Random Random = new System.Random();


#endregion
Expand Down Expand Up @@ -163,7 +165,7 @@ public static bool PositionShips_Random (int mapSize, Ship[] ships, Int2[] stone
// Func
bool PositionAvailable (Ship _ship, ShipPosition _pos) {
// Border Check
var (min, max) = _ship.GetBounds(_pos);
var (min, max) = _ship.GetBounds(_pos.Flip);
if (_pos.Pivot.x < -min.x || _pos.Pivot.x > mapSize - max.x - 1 ||
_pos.Pivot.y < -min.y || _pos.Pivot.y > mapSize - max.y - 1
) {
Expand Down Expand Up @@ -520,66 +522,6 @@ int Exposure (Ship _ship, ShipPosition _sPos) {
}


public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, out Int2 pos) => GetTileMVP(values, tiles, filter, Tile.None, out pos);
public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, Tile neighbourFilter, out Int2 pos) => GetTileMVP(values, tiles, filter, neighbourFilter, null, out pos);
public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, Tile neighbourFilter, List<Attack> attacks, out Int2 pos) {
int size = tiles.GetLength(0);
int valueIndex = values.GetLength(0) - 1;
bool hasAttacks = attacks != null && attacks.Count > 0;
float maxValue = 0;
bool success = false;
bool neighbour = neighbourFilter != Tile.None;
pos = default;
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
var tile = tiles[i, j];
if (!filter.HasFlag(tile)) { continue; }
float value = GetValue(i, j);
if (value > maxValue || (value == maxValue && Random.NextDouble() > 0.66666f)) {
maxValue = value;
pos.x = i;
pos.y = j;
success = true;
}
}
}
return success;
// Func
float GetValue (int _i, int _j) {
float result = values[valueIndex, _i, _j];
if (neighbour) {
if (!hasAttacks) {
// Default Cross
if (_i - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i - 1, _j])) {
result += values[valueIndex, _i - 1, _j];
}
if (_j - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i, _j - 1])) {
result += values[valueIndex, _i, _j - 1];
}
if (_i + 1 < size && neighbourFilter.HasFlag(tiles[_i + 1, _j])) {
result += values[valueIndex, _i + 1, _j];
}
if (_j + 1 < size && neighbourFilter.HasFlag(tiles[_i, _j + 1])) {
result += values[valueIndex, _i, _j + 1];
}
} else {
// Attacks
foreach (var att in attacks) {
if (att.Trigger == AttackTrigger.PassiveRandom || att.Trigger == AttackTrigger.Random) { continue; }
int _x = _i + att.X;
int _y = _j + att.Y;
if (_x < 0 || _x >= size || _y < 0 || _y >= size) { continue; }
var _tile = tiles[_x, _y];
if (!att.AvailableTarget.HasFlag(_tile) || !neighbourFilter.HasFlag(_tile)) { continue; }
result += values[valueIndex, _x, _y];
}
}
}
return result;
}
}


public int GetShipWithMinimalPotentialPosCount (BattleInfo info, List<ShipPosition>[] hiddenPositions, List<ShipPosition>[] exposedPositions) => GetShipWithMinimalPotentialPosCount(info, hiddenPositions, exposedPositions, out _);


Expand Down Expand Up @@ -728,6 +670,70 @@ public int CountNeighborTile (Tile[,] tiles, int x, int y, Tile filter) {
}


public bool AveragePosition (Tile[,] tiles, Tile filter, out Float2 pos) {
Float2? resultPos = null;
int size = tiles.GetLength(0);
float count = 0f;
pos = default;
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
var tile = tiles[i, j];
if (!filter.HasFlag(tile)) { continue; }
if (!resultPos.HasValue) {
resultPos = new Float2(i, j);
} else {
resultPos += new Float2(i, j);
}
count++;
}
}
if (resultPos.HasValue && count > 0) {
resultPos /= count;
pos = resultPos.Value;
return true;
} else {
return false;
}
}


public bool NearestPosition (Tile[,] tiles, int x, int y, Tile filter, out Int2 pos, out float sqrtDistance) {
pos = default;
sqrtDistance = float.MaxValue;
int size = tiles.GetLength(0);
bool success = false;
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
var tile = tiles[i, j];
if (!filter.HasFlag(tile)) { continue; }
float a = System.Math.Abs(x - i);
float b = System.Math.Abs(y - j);
float sqrtDis = a * a + b * b;
if (sqrtDis < sqrtDistance) {
sqrtDistance = sqrtDis;
pos.x = i;
pos.y = j;
success = true;
}
}
}
return success;
}


public bool ContainsTile (Tile[,] tiles, Tile filter) {
int size = tiles.GetLength(0);
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
if (filter.HasFlag(tiles[i, j])) {
return true;
}
}
}
return false;
}


#endregion


Expand Down
92 changes: 92 additions & 0 deletions Assets/Battle Soup AI/Core/SoupStrategy_Advanced.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ namespace BattleSoupAI {
public abstract class SoupStrategy_Advanced : SoupStrategy {


// SUB
public enum MVPConfig {
Hidden = 0,
Exposed = 1,
Both = 2,
}


// Data
protected int OwnAliveShipCount = 0;
protected int OpponentAliveShipCount = 0;
Expand Down Expand Up @@ -241,5 +249,89 @@ public bool TryAttackShip (BattleInfo info, int targetIndex, Tile filter, out In
}


public bool GetTileMVP (Tile[,] tiles, Tile filter, MVPConfig config, out Int2 pos) => GetTileMVP(tiles, filter, Tile.None, config, out pos);
public bool GetTileMVP (Tile[,] tiles, Tile filter, Tile neighbourFilter, MVPConfig config, out Int2 pos) => GetTileMVP(tiles, filter, neighbourFilter, null, config, out pos, out _);
public bool GetTileMVP (Tile[,] tiles, Tile filter, Tile neighbourFilter, List<Attack> attacks, MVPConfig config, out Int2 pos, out AbilityDirection direcion) {
var hdValues = HiddenValues;
var exValues = ExposedValues;
int size = tiles.GetLength(0);
int valueIndex = hdValues.GetLength(0) - 1;
bool hasAttacks = attacks != null && attacks.Count > 0;
float maxValue = 0;
bool success = false;
bool neighbour = neighbourFilter != Tile.None;
pos = default;
direcion = default;
for (int j = 0; j < size; j++) {
for (int i = 0; i < size; i++) {
var tile = tiles[i, j];
if (!filter.HasFlag(tile)) { continue; }
float value = GetValue(i, j, out var _direcion);
if (value > maxValue || (value == maxValue && Random.NextDouble() > 0.66666f)) {
maxValue = value;
pos.x = i;
pos.y = j;
success = true;
direcion = _direcion;
}
}
}
return success;
// Func
float GetConfigValue (int _i, int _j) {
float result = 0f;
if (config == MVPConfig.Hidden || config == MVPConfig.Both) {
result += hdValues[valueIndex, _i, _j];
}
if (config == MVPConfig.Exposed || config == MVPConfig.Both) {
result += exValues[valueIndex, _i, _j];
}
return result;
}
float GetValue (int _i, int _j, out AbilityDirection _dir) {
_dir = default;
float result = GetConfigValue(_i, _j);
if (neighbour) {
if (!hasAttacks) {
// Default Cross
if (_i - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i - 1, _j])) {
result += GetConfigValue(_i - 1, _j);
}
if (_j - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i, _j - 1])) {
result += GetConfigValue(_i, _j - 1);
}
if (_i + 1 < size && neighbourFilter.HasFlag(tiles[_i + 1, _j])) {
result += GetConfigValue(_i + 1, _j);
}
if (_j + 1 < size && neighbourFilter.HasFlag(tiles[_i, _j + 1])) {
result += GetConfigValue(_i, _j + 1);
}
} else {
// Attacks
float attResult = 0f;
for (int i = 0; i < 4; i++) {
float currentResult = 0;
var dir = (AbilityDirection)i;
foreach (var att in attacks) {
if (att.Trigger == AttackTrigger.PassiveRandom || att.Trigger == AttackTrigger.Random) { continue; }
var (_x, _y) = att.GetPosition(_i, _j, dir);
if (_x < 0 || _x >= size || _y < 0 || _y >= size) { continue; }
var _tile = tiles[_x, _y];
if (!att.AvailableTarget.HasFlag(_tile) || !neighbourFilter.HasFlag(_tile)) { continue; }
currentResult += GetConfigValue(_x, _y);
}
if (currentResult > attResult) {
attResult = currentResult;
_dir = dir;
}
}
result += attResult;
}
}
return result;
}
}


}
}
Loading

0 comments on commit aad1ec4

Please sign in to comment.