Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Linq;
- using System.IO;
- using System.Text;
- using System.Collections;
- using System.Collections.Generic;
- using System.Diagnostics;
- // rank 5
- /**
- * Auto-generated code below aims at helping you parse
- * the standard input according to the problem statement.
- **/
- class CotC
- {
- public static bool shootMines = false; //shoot near enemy
- public static bool clearMines = false; //clear for myself
- public static bool layMines = false; // lay mines
- public static bool logging = true;
- #region props
- public static int width = 23;
- public static int height = 21;
- public static List<Rum> rum = new List<Rum>();
- public static List<Ship> ships = new List<Ship>();
- public static List<Cannonball> balls = new List<Cannonball>();
- public static List<Mine> mines = new List<Mine>();
- public static int round = 0;
- private static int MAP_WIDTH = 23;
- private static int MAP_HEIGHT = 21;
- private static int COOLDOWN_CANNON = 2;
- private static int COOLDOWN_MINE = 5;
- private static int INITIAL_SHIP_HEALTH = 100;
- private static int MAX_SHIP_HEALTH = 100;
- private static int MAX_SHIP_SPEED;
- private static int MIN_SHIPS = 1;
- private static int MAX_SHIPS = 3;
- private static int MIN_RUM_BARRELS = 10;
- private static int MAX_RUM_BARRELS = 26;
- private static int MIN_RUM_BARREL_VALUE = 10;
- private static int MAX_RUM_BARREL_VALUE = 20;
- private static int REWARD_RUM_BARREL_VALUE = 30;
- private static int MINE_VISIBILITY_RANGE = 5;
- private static int FIRE_DISTANCE_MAX = 10;
- private static int LOW_DAMAGE = 25;
- private static int HIGH_DAMAGE = 50;
- private static int MINE_DAMAGE = 25;
- private static int NEAR_MINE_DAMAGE = 10;
- private static bool CANNONS_ENABLED = true;
- private static bool MINES_ENABLED = true;
- #endregion props
- static void Main(string[] args)
- {
- //map = new int[width,height];
- // game loop
- Stopwatch watch = new Stopwatch();
- while (true)
- {
- watch.Start();
- #region setup
- round++;
- int myShipCount = int.Parse(Console.ReadLine()); // the number of remaining ships
- int entityCount = int.Parse(Console.ReadLine()); // the number of entities (e.g. ships, mines or cannonballs)
- rum = new List<Rum>();
- List<Ship> currentShips = new List<Ship>();
- balls = new List<Cannonball>();
- mines = new List<Mine>();
- for (int i = 0; i < entityCount; i++)
- {
- string[] inputs = Console.ReadLine().Split(' ');
- int entityId = int.Parse(inputs[0]);
- string entityType = inputs[1];
- int x = int.Parse(inputs[2]);
- int y = int.Parse(inputs[3]);
- int arg1 = int.Parse(inputs[4]);
- int arg2 = int.Parse(inputs[5]);
- int arg3 = int.Parse(inputs[6]);
- int arg4 = int.Parse(inputs[7]);
- switch (entityType)
- {
- case "BARREL":
- var tempRum = new Rum()
- {
- x = x,
- y = y,
- id = entityId,
- type = entityType,
- rum = arg1,
- };
- rum.Add(tempRum);
- break;
- case "SHIP":
- var oldShip = ships.FirstOrDefault(a => a.id == entityId);
- if (oldShip != null)
- {
- oldShip.x = x;
- oldShip.y = y;
- oldShip.id = entityId;
- oldShip.type = entityType;
- oldShip.orientation = arg1;
- oldShip.speed = arg2;
- oldShip.rum = arg3;
- oldShip.owner = arg4;
- oldShip.cannonCooldown--;
- oldShip.mineCooldown--;
- currentShips.Add(oldShip);
- }
- else
- {
- var tempShip = new Ship()
- {
- x = x,
- y = y,
- id = entityId,
- type = entityType,
- orientation = arg1,
- speed = arg2,
- rum = arg3,
- owner = arg4,
- layMines = layMines,
- };
- currentShips.Add(tempShip);
- }
- break;
- case "CANNONBALL":
- var tempBall = new Cannonball()
- {
- x = x,
- y = y,
- id = entityId,
- type = entityType,
- shipId = arg1,
- turns = arg2,
- };
- balls.Add(tempBall);
- break;
- case "MINE":
- var tempMine = new Mine()
- {
- x = x,
- y = y,
- id = entityId,
- type = entityType,
- };
- mines.Add(tempMine);
- break;
- }
- }//end for
- ships.Clear();
- ships.AddRange(currentShips);
- #endregion setup
- #region MAIN LOGIC
- var myShips = ships.Where(a => a.owner == 1).ToArray();
- //sim first round
- List<Ship> cloneShips = new List<Ship>();
- foreach (var tShip in ships) { cloneShips.Add(tShip.Clone()); };
- var myCloneShips = cloneShips.Where(a => a.owner == 1).ToArray();
- for (int i = 0; i < myCloneShips.Length; i++)
- {
- var ship = myCloneShips[i];
- var goodActions = testActions(ship, cloneShips, rum, mines, balls);
- ship.priorities = goodActions;
- myShips[i].priorities = goodActions;
- ship.PerformAction(Action.WAIT, false);
- ship.TheoryMove(ship.action);
- }
- for (int i = 0; i < myShipCount; i++)
- {
- var ship = myShips[i];
- // Write an action using Console.WriteLine()
- // To debug: Console.Error.WriteLine("Debug messages...");
- Random rand = new Random();
- var enemies = ships.Where(a => a.owner == 0).OrderBy(b => b.DistFront(ship));
- var enemy = enemies.FirstOrDefault();
- var dist = enemy != null ? ship.DistFront(enemy) : 999;
- bool dontFire = false;
- //dontFire = testFire(ship);
- if (ship.rum + ship.priorities.Max(a => a.Value) <= 0)
- {
- log("will die regardless, GO OUT BLAZING");
- dontFire = false;
- }
- else
- {
- var fireScore = ship.priorities[Action.WAIT];
- if (ship.priorities.Max(a => a.Value) > fireScore + 4)
- {
- dontFire = true;
- }
- }
- var mineHit = mines.Where(a => myShips.Min(c => c.Dist(a)) > 4 && enemies.Min(c => c.Dist(a)) <= 4 && !balls.Any(b => b.x == a.x && b.y == a.y)).FirstOrDefault();
- var clearMine = mines.Where(a => myShips.Min(c => c.Dist(a)) > 4 && enemies.Min(c => c.Dist(a)) <= 4 && !balls.Any(b => b.x == a.x && b.y == a.y)).OrderBy(d => ship.DistFront(d)).FirstOrDefault();
- rum = rum.OrderBy(a => ship.DistFront(a)).ToList();
- if (rum.Count() == 0 && ship.rum >= enemies.Max(c => c.rum) && enemies.Min(c => ship.Dist(c)) > 10)
- {
- EndGameStrat(ship);
- }
- else if (ship.cannonCooldown <= 0)
- {
- var closeRum = rum.Where(a => ship.DistFront(a) > enemy.DistFront(a) && ship.DistFront(a) <= 10 && !balls.Any(b => b.Pos().Equals(a.Pos()))).FirstOrDefault();
- if (!dontFire && closeRum != null
- && myShips.Min(a => a.DistFront(closeRum)) > enemies.Min(a => a.DistFront(closeRum)))
- {
- ship.Fire(closeRum);
- rum.Remove(closeRum);
- balls.Add(new Cannonball()
- {
- x = closeRum.x,
- y = closeRum.y,
- id = -1,
- turns = ship.shotDuration(new Coord(closeRum.x, closeRum.y)),
- });
- ship.cannonCooldown = 2;
- }
- else if (!dontFire && ship.Fire(enemy, ships, rum, balls))
- {
- balls.Add(new Cannonball()
- {
- x = ship.target.x,
- y = ship.target.y,
- turns = ship.shotDuration(ship.target),
- });
- ship.cannonCooldown = 2;
- }
- else if (shootMines && !dontFire && mineHit != null)
- {
- ship.Fire(mineHit);
- balls.Add(new Cannonball()
- {
- x = mineHit.x,
- y = mineHit.y,
- turns = ship.shotDuration(new Coord(mineHit.x, mineHit.y)),
- });
- ship.cannonCooldown = 2;
- continue;
- }
- else if (shootMines && !dontFire && clearMine != null)
- {
- ship.Fire(clearMine);
- balls.Add(new Cannonball()
- {
- x = clearMine.x,
- y = clearMine.y,
- turns = ship.shotDuration(new Coord(clearMine.x, clearMine.y)),
- });
- ship.cannonCooldown = 2;
- continue;
- }
- else
- {
- var closeRumNotTargeted = rum.FirstOrDefault(a => ship.DistFront(a) <= enemy.DistFront(a) && !balls.Any(b => b.Pos().equals(a.Pos())));
- if (closeRumNotTargeted != null)
- {
- ship.Move(closeRumNotTargeted);
- rum.Remove(closeRumNotTargeted);
- }
- else
- {
- EndGameStrat(ship);
- }
- }
- }
- else if (rum.Count > 0)
- {
- var target = rum.FirstOrDefault(a => !balls.Any(b => b.x == a.x && b.y == a.y));
- if (target != null && target.rum + ship.rum > 100 && target.Dist(ship) < 2 && !ship.BallsWillHit(balls))
- {
- if (ship.speed > 0)
- {
- ship.Slower();
- }
- else
- {
- ship.Wait();
- }
- }
- else if (target != null)
- {
- ship.Move(target.x, target.y);
- rum.Remove(target);
- }
- else
- {
- EndGameStrat(ship);
- }
- }
- else
- {
- EndGameStrat(ship);
- }
- }//end for
- #endregion MAIN LOGIC
- watch.Stop();
- log(watch.ElapsedMilliseconds + "ms");
- watch.Reset();
- }//end while
- }
- #region print/log
- public static double GetDistance(int x1, int y1, int x2, int y2)
- {
- return Math.Sqrt(Math.Pow(x1 - x2, 2) + Math.Pow(y1 - y2, 2));
- }
- public static bool testFire(Ship ship)
- {
- if (ship.cannonCooldown > 0)
- {
- return true;
- }
- Ship tempShip = ship.Clone();
- if (tempShip.speed == 2)
- {
- tempShip.TheoryMove(Action.FIRE);
- tempShip.TheoryMove(Action.SLOWER);
- }
- else
- {
- tempShip.TheoryMove(Action.FIRE);
- tempShip.TheoryMove(Action.WAIT);
- }
- var front = tempShip.GetFront();
- var back = tempShip.GetBack();
- var middle = tempShip.GetMiddle();
- bool mineHits = mines.Any(a => a.Pos().equals(front) || a.Pos().equals(middle) || a.Pos().equals(back));
- bool cannonHits = balls.Any(a => a.Pos().equals(front) || a.Pos().equals(middle) || a.Pos().equals(back));
- if (mineHits || cannonHits)
- log("dont fire " + (mineHits || cannonHits));
- return mineHits || cannonHits;
- }
- public static Dictionary<Action, int> testActions(Ship ship, List<Ship> shipsOld, List<Rum> rumOld, List<Mine> minesOld, List<Cannonball> ballsOld)
- {
- var results = new Dictionary<Action, int>();
- var actions = new List<Action>() { Action.WAIT, Action.PORT, Action.STARBOARD, Action.SLOWER, Action.FASTER };
- //repeat this for each depth
- foreach (var act in actions)
- {
- bool performSim = true;
- //reset variables per action
- List<Ship> ships = new List<Ship>();
- foreach (var tShip in shipsOld) { ships.Add(tShip.Clone()); };
- List<Rum> rum = new List<Rum>();
- foreach (var tRum in rumOld) { rum.Add(tRum.Clone()); };
- List<Mine> mines = new List<Mine>();
- foreach (var tMine in minesOld) { mines.Add(tMine.Clone()); };
- List<Cannonball> balls = new List<Cannonball>();
- foreach (var tBall in ballsOld) { balls.Add(tBall.Clone()); };
- var score = 0;
- Ship tempShip = ship.Clone();
- //prevent useless commands
- if (ship.speed == 2 && act == Action.FASTER)
- {
- score -= 2;
- }
- if (ship.speed == 0 && act == Action.SLOWER)
- {
- score -= 2;
- }
- if (ship.speed == 0)
- {
- if (act == Action.WAIT)
- score -= 2;
- if (act == Action.FASTER)
- score += 2;
- }
- //front ship collides (in case i cant move)
- if (ships.Any(a => a.id != ship.id && a.GetFront().equals(tempShip.GetFront().neighbor(tempShip.orientation))) ||
- ships.Any(a => a.id != ship.id && a.GetMiddle().equals(tempShip.GetFront().neighbor(tempShip.orientation))) ||
- ships.Any(a => a.id != ship.id && a.GetBack().equals(tempShip.GetFront().neighbor(tempShip.orientation))))
- {
- tempShip.speed = 0;
- if (act == Action.WAIT || act == Action.FASTER) { score -= 5; performSim = false; }
- }
- if (ships.Any(a => a.id != ship.id && a.GetFront().neighbor(a.orientation).equals(tempShip.GetFront().neighbor(tempShip.orientation)))
- && ((ship.speed == 2 && act != Action.SLOWER) || (ship.speed == 1 && act == Action.FASTER)))
- {
- tempShip.speed = 0;
- if (act == Action.WAIT || act == Action.FASTER)
- {
- score -= 5; performSim = false;
- }
- }
- if (!tempShip.GetFront().isInsideMap() && (act == Action.WAIT || act == Action.FASTER || act == Action.SLOWER))
- {
- score -= 15;
- tempShip.speed = 0;
- performSim = false;
- }
- #region mines
- var mine1 = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(ship.orientation)));
- var mine2 = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(ship.orientation).neighbor(ship.orientation)));
- var mine3 = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(ship.orientation).neighbor(ship.orientation).neighbor(ship.orientation)));
- //run into mines prior to turn
- if ((tempShip.speed == 1 && act == Action.FASTER))
- {
- if (mine1 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- if (mine2 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- if (mine3 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- }
- else if ((tempShip.speed == 1 && act != Action.SLOWER && act != Action.FASTER) || (tempShip.speed == 2 && act == Action.SLOWER) || (tempShip.speed == 0 && act == Action.FASTER))
- {
- if (mine1 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- }
- else if (tempShip.speed == 1 && act == Action.SLOWER)
- {
- if (mine1 != null)
- {//wont hit, but dont want to slow down
- score -= 5;
- }
- }
- else if (tempShip.speed == 2 && act != Action.SLOWER)
- {
- if (mine1 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- if (mine2 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- if (mine3 != null)
- {
- score -= 25;
- mines.Remove(mine1);
- }
- }
- else if (tempShip.speed == 2 && act == Action.SLOWER)
- {
- if (mine3 != null)
- {
- score -= 5;
- }
- }
- #endregion mines
- if (performSim)
- {
- tempShip.TheoryMove(act);
- }
- else
- {
- log("skip sim");
- }
- //mines hit
- var hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront()));
- if (hitMine != null)
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetMiddle()));
- if (hitMine != null)
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetBack()));
- if (hitMine != null)
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- //future hit
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(tempShip.orientation)));
- if (hitMine != null && tempShip.speed == 0)
- {//wont hit, but stops movement
- score -= 6;
- }
- //run into mines prior to turn
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(ship.orientation)));
- if (hitMine != null && (tempShip.speed == 2 || (tempShip.speed == 1 && act != Action.SLOWER)))
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- //balls hit
- var tempBallsHit = balls.Where(a => a.Pos().equals(tempShip.GetFront()) && a.turns <= 2);
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- balls = balls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = balls.Where(a => a.Pos().equals(tempShip.GetBack()) && a.turns <= 2);
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- balls = balls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = balls.Where(a => a.Pos().equals(tempShip.GetMiddle()) && a.turns <= 2);
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- balls = balls.Except(tempBallsHit).ToList();
- score -= 50 * numBalls;
- }
- if (tempShip.speed == 0)
- {
- tempBallsHit = balls.Where(a => a.Pos().equals(tempShip.GetMiddle()) && a.turns <= 3);
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- score -= 20 * numBalls;
- }
- }
- else if (tempShip.speed == 2)
- {
- var tempShip2 = tempShip.Clone();
- var tempShip3 = tempShip.Clone();
- tempShip2.TheoryMove(Action.WAIT);
- tempShip3.TheoryMove(Action.SLOWER);
- var tempBalls = balls.Where(a => a.turns > 1 && a.turns <= 4);
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip2.GetFront()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip2.GetBack()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip2.GetMiddle()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 50 * numBalls;
- }
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip3.GetFront()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip3.GetBack()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 25 * numBalls;
- }
- tempBallsHit = tempBalls.Where(a => a.Pos().equals(tempShip3.GetMiddle()));
- if (tempBallsHit.Count() > 0)
- {
- var numBalls = tempBallsHit.Count();
- tempBalls = tempBalls.Except(tempBallsHit).ToList();
- score -= 50 * numBalls;
- }
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(tempShip.orientation)));
- if (hitMine != null)
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(tempShip.orientation).neighbor(tempShip.orientation)));
- if (hitMine != null)
- {
- score -= 25;
- mines.Remove(hitMine);
- }
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(tempShip.orientation).neighbor(tempShip.orientation).neighbor(tempShip.orientation)));
- if (hitMine != null)
- {//wont hit, but avoid slowing down
- score -= 5;
- //mines.Remove(hitMine);
- }
- }
- else if (tempShip.speed == 2)
- {
- hitMine = mines.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront().neighbor(tempShip.orientation)));
- if (hitMine != null)
- {//wont hit, but avoid slowing down
- score -= 5;
- //mines.Remove(hitMine);
- }
- }
- //front ship collides
- if (ships.Any(a => a.id != ship.id && a.GetFront().equals(tempShip.GetFront())))
- {
- score -= 1;
- }
- if (ships.Any(a => a.id != ship.id && a.GetMiddle().equals(tempShip.GetFront())))
- {
- score -= 1;
- }
- if (ships.Any(a => a.id != ship.id && a.GetBack().equals(tempShip.GetFront())))
- {
- score -= 1;
- }
- //back ship collides
- if (ships.Any(a => a.id != ship.id && a.GetFront().equals(tempShip.GetBack())))
- {
- score -= 1;
- }
- if (ships.Any(a => a.id != ship.id && a.GetMiddle().equals(tempShip.GetBack())))
- {
- score -= 1;
- }
- if (ships.Any(a => a.id != ship.id && a.GetBack().equals(tempShip.GetBack())))
- {
- score -= 1;
- }
- //barrels hit
- var rumHit = rum.FirstOrDefault(a => a.Pos().equals(tempShip.GetFront()));
- if (rumHit != null)
- {
- var rumAmount = rumHit.rum;
- var diff = (100 - ship.rum);
- var rumInc = diff >= rumAmount ? rumAmount : diff;
- ship.rum += rumInc;
- score += rumInc * 2;
- rum.Remove(rumHit);
- }
- rumHit = rum.FirstOrDefault(a => a.Pos().equals(tempShip.GetMiddle()));
- if (rumHit != null)
- {
- var rumAmount = rumHit.rum;
- var diff = (100 - ship.rum);
- var rumInc = diff >= rumAmount ? rumAmount : diff;
- ship.rum += rumInc;
- score += rumInc * 2;
- rum.Remove(rumHit);
- }
- rumHit = rum.FirstOrDefault(a => a.Pos().equals(tempShip.GetBack()));
- if (rumHit != null)
- {
- var rumAmount = rumHit.rum;
- var diff = (100 - ship.rum);
- var rumInc = diff >= rumAmount ? rumAmount : diff;
- ship.rum += rumInc;
- score += rumInc * 2;
- rum.Remove(rumHit);
- }
- if (rum.Count() > 0)
- {
- var minDist = rum.Min(a => tempShip.DistFront(a));
- if (minDist < 5)
- {
- score += (10 - minDist);
- }
- }
- if (!tempShip.GetFront().isInsideMap())
- {
- score -= 5;
- }
- else if (!tempShip.GetFront().isInsideEdge())
- {
- if (rum.Count() > 0)
- {
- var minDist = rum.Min(a => tempShip.DistFront(a));
- if (minDist > 3)
- {
- score -= 4;
- }
- }
- else
- {
- score -= 4;
- }
- }
- //run into rum prior to turn
- rumHit = rum.FirstOrDefault(a => a.Pos().equals(tempShip.GetMiddle().neighbor(ship.orientation)));
- if (rumHit != null)
- {
- var rumAmount = rumHit.rum;
- var diff = (100 - ship.rum);
- var rumInc = diff >= rumAmount ? rumAmount : diff;
- ship.rum += rumInc;
- score += rumInc * 2;
- rum.Remove(rumHit);
- }
- results.Add(act, score);
- }
- if (logging)
- {
- foreach (var result in results)
- {
- log(result.Key.ToString() + ": " + result.Value.ToString());
- }
- }
- return results;
- }
- public static int Dist(int x1, int y1, int x2, int y2)
- {
- int xp1 = x1 - (y1 - (y1 & 1)) / 2;
- int zp1 = y1;
- int yp1 = -(xp1 + zp1);
- int xp2 = x2 - (y2 - (y2 & 1)) / 2;
- int zp2 = y2;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public static void log(string str)
- {
- Console.Error.WriteLine(str);
- }
- public static void log(int str)
- {
- Console.Error.WriteLine(str);
- }
- public static void log(double str)
- {
- Console.Error.WriteLine(str);
- }
- public static void print(string str)
- {
- Console.WriteLine(str);
- }
- public static void Move(int x, int y)
- {
- Console.WriteLine("MOVE {0} {1}", x, y);
- }
- public static void Fire(int x, int y)
- {
- Console.WriteLine("FIRE {0} {1}", x, y);
- }
- public static void Mine()
- {
- print("MINE");
- }
- public static void Slower()
- {
- print("SLOWER");
- }
- public static void Faster()
- {
- print("FASTER");
- }
- public static void Wait()
- {
- print("WAIT");
- }
- public static void EndGameStrat(Ship ship)
- {
- log("end game strat");
- var enemies = ships.Where(a => a.owner == 0).OrderBy(b => b.Dist(ship));
- var enemy = enemies.FirstOrDefault();
- var myShips = ships.Where(a => a.owner == 1 && a.id != ship.id && !a.suicide && a.Dist(ship) < 5);
- var myShipsFar = ships.Where(a => a.owner == 1 && a.id != ship.id && !a.suicide).OrderBy(b => b.Dist(ship));
- var myShipsFarSuicide = ships.Where(a => a.owner == 1 && a.id != ship.id).OrderBy(b => b.Dist(ship));
- if (rum.Count() == 0 && myShipsFar.Count() > 0 && enemies.Min(e => e.Dist(ship) > 5))
- {
- if (myShipsFar.Max(a => a.rum) >= ship.rum && ship.rum <= 50 && (enemies.Max(a => a.rum) >= myShipsFar.Max(a => a.rum)))
- {//other ship has more rum
- ship.suicide = true;
- log("suicide");
- }
- }
- if (ship.suicide && myShips.Count() > 0)
- {
- if (ship.rum > myShipsFar.Max(a => a.rum))
- {
- log("no suicide anymore");
- ship.suicide = false;
- }
- else if (ship.speed > 0)
- {
- ship.Slower();
- return;
- }
- else
- {
- if (balls.Any(b => b.Pos().equals(ship.GetMiddle())))
- {//going to die anyway, wait it out
- ship.Wait();
- }
- else
- {
- ship.Fire(ship.x, ship.y);
- }
- return;
- }
- }
- else if (ship.suicide && myShipsFar.Count() > 0)
- {
- var first = myShipsFar.First();
- ship.Move(first);
- return;
- }
- else if (!ship.suicide && myShipsFarSuicide.Count() > 0)
- {
- var first = myShipsFarSuicide.First();
- ship.Move(first);
- return;
- }
- else if (ship.suicide)
- {
- ship.suicide = false;
- }
- if (ship.rum > enemies.Max(c => c.rum) || (Math.Min(myShips.Sum(a => a.rum), (myShips.Count() * 30)) + ship.rum) > enemies.Max(c => c.rum))
- {
- log("will hit: " + ship.BallsWillHit(balls));
- if (enemies.Min(c => ship.Dist(c)) > 10 && !ship.BallsWillHit(balls))
- {
- if (ship.speed > 0)
- {
- ship.PerformAction(Action.SLOWER);
- return;
- }
- else
- {
- ship.PerformAction(Action.WAIT);
- //ship.Wait();
- return;
- }
- }
- else
- {
- var avgX = enemies.Sum(c => c.x) / enemies.Count();
- var avgY = enemies.Sum(c => c.y) / enemies.Count();
- var tX = avgX < 6 ? 18 : avgX > 15 ? 4 : 18;
- var tY = avgY < 6 ? 17 : avgY > 14 ? 4 : 17;
- log("move away from enemy");
- ship.Move(tX, tY);
- }
- }
- else
- {
- ship.Move(enemy);
- }
- }
- #endregion
- }
- #region classes
- class Unit
- {
- public int x;
- public int y;
- public int id;
- public string type;
- public Action action;
- public Coord Pos()
- {
- return new Coord(x, y);
- }
- public double GetDistance(int x1, int y1)
- {
- return Math.Sqrt(Math.Pow(x - x1, 2) + Math.Pow(y - y1, 2));
- }
- public double GetDistance(Unit unit)
- {
- return Math.Sqrt(Math.Pow(x - unit.x, 2) + Math.Pow(y - unit.y, 2));
- }
- public int Dist(Unit unit)
- {
- int xp1 = this.x - (this.y - (this.y & 1)) / 2;
- int zp1 = this.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = unit.x - (unit.y - (unit.y & 1)) / 2;
- int zp2 = unit.y;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int Dist(Coord unit)
- {
- int xp1 = this.x - (this.y - (this.y & 1)) / 2;
- int zp1 = this.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = unit.x - (unit.y - (unit.y & 1)) / 2;
- int zp2 = unit.y;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int Dist(int x2, int y2)
- {
- int xp1 = this.x - (this.y - (this.y & 1)) / 2;
- int zp1 = this.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = x2 - (y2 - (y2 & 1)) / 2;
- int zp2 = y2;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int Dist(Coord point, int x2, int y2)
- {
- int xp1 = point.x - (point.y - (point.y & 1)) / 2;
- int zp1 = point.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = x2 - (y2 - (y2 & 1)) / 2;
- int zp2 = y2;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int Dist(Coord point1, Coord point2)
- {
- int xp1 = point1.x - (point1.y - (point1.y & 1)) / 2;
- int zp1 = point1.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = point2.x - (point2.y - (point2.y & 1)) / 2;
- int zp2 = point2.y;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- }
- class Ship : Unit
- {
- private static int MAP_WIDTH = 23;
- private static int MAP_HEIGHT = 21;
- public int orientation;
- public int speed;
- public int rum;
- public int owner;
- public int xOffset;
- public int yOffset;
- public bool layMines;
- public bool suicide;
- public Dictionary<Action, int> priorities = null;
- public Coord target;
- public int cannonCooldown;
- public int mineCooldown;
- public Ship Clone()
- {
- return new Ship()
- {
- id = this.id,
- x = this.x,
- y = this.y,
- orientation = this.orientation,
- speed = this.speed,
- rum = this.rum,
- owner = this.owner,
- action = this.action,
- mineCooldown = this.mineCooldown,
- cannonCooldown = this.cannonCooldown,
- target = this.target != null ? this.target.Clone() : null,
- layMines = this.layMines,
- };
- }
- public Coord GetFront()
- {
- Coord front = new Coord(x, y).neighbor(orientation);
- return front;
- }
- public Coord GetMiddle()
- {
- Coord middle = new Coord(x, y);
- return middle;
- }
- public Coord GetBack()
- {
- Coord back = new Coord(x, y).neighbor((orientation + 3) % 6);
- return back;
- }
- public bool BallsWillHit(List<Cannonball> balls)
- {
- var result = (balls.Any(a => GetFront().equals(a) || GetMiddle().equals(a) || GetBack().equals(a)));
- return result;
- }
- public Coord GetFront(int turns)
- {
- Coord currentCoord = new Coord(x, y);
- this.yOffset = 0;
- this.xOffset = 0;
- //first turn
- Coord newPosition = currentCoord.neighbor(orientation);
- //extra turns
- for (int i = 1; i < turns; i++)
- {
- newPosition = newPosition.neighbor(orientation);
- }
- return newPosition.neighbor(orientation);
- }
- public Coord GetBack(int turns)
- {
- Coord currentCoord = new Coord(x, y);
- this.yOffset = 0;
- this.xOffset = 0;
- //first turn
- Coord newPosition = currentCoord.neighbor(orientation);
- //extra turns
- for (int i = 1; i < turns; i++)
- {
- newPosition = newPosition.neighbor(orientation);
- }
- return newPosition.neighbor((orientation + 3) % 6);
- }
- public Coord GetMiddle(int turns)
- {
- Coord currentCoord = new Coord(x, y);
- this.yOffset = 0;
- this.xOffset = 0;
- //first turn
- Coord newPosition = currentCoord.neighbor(orientation);
- //extra turns
- for (int i = 1; i < turns; i++)
- {
- newPosition = newPosition.neighbor(orientation);
- }
- return newPosition;
- }
- public Coord GetOffsetFront()
- {
- Coord front = GetFront().neighbor(orientation);
- return front;
- }
- public Coord GetOffsetBack()
- {
- Coord back = GetBack().neighbor((orientation + 3) % 6);
- return back;
- }
- public bool Fire(Rum rum)
- {
- Console.WriteLine("Fire {0} {1}", rum.x, rum.y);
- return true;
- }
- public bool Fire(Mine mine)
- {
- Console.WriteLine("Fire {0} {1}", mine.x, mine.y);
- return true;
- }
- public bool Fire(Coord coord)
- {
- Console.WriteLine("Fire {0} {1}", coord.x, coord.y);
- return true;
- }
- public bool Fire(int X, int Y)
- {
- Console.WriteLine("Fire {0} {1}", X, Y);
- return true;
- }
- public bool Fire()
- {
- if (target == null)
- throw new NullReferenceException("no target set");
- Console.WriteLine("Fire {0} {1}", target.x, target.y);
- return true;
- }
- public bool Fire(Ship unit)
- {
- if (cannonCooldown > 0 || DistFront(unit) > 10)
- {
- return false;
- }
- var tempShip = unit.Clone();
- var tempThisShip = Clone();
- var xTar = unit.x;
- var yTar = unit.y;
- tempThisShip.TheoryMove(Action.WAIT);
- if (tempShip.speed < 2)
- {
- tempShip.TheoryMove(Action.FASTER);
- }
- else
- {
- tempShip.TheoryMove(Action.WAIT);
- }
- int estimateTime = shotDuration(tempShip.GetMiddle());
- if (estimateTime > 1)
- {
- tempThisShip.TheoryMove(Action.WAIT);
- if (tempShip.speed < 2)
- {
- tempShip.TheoryMove(Action.FASTER);
- }
- else
- {
- tempShip.TheoryMove(Action.WAIT);
- }
- estimateTime = shotDuration(tempShip.GetMiddle());
- }
- if (shotDuration(unit.GetMiddle()) != 1 && unit.speed != 0)
- {
- xTar = tempShip.x;
- yTar = tempShip.y;
- }
- if (!unit.GetFront().isInsideMap() || !unit.GetFront().neighbor(unit.orientation).isInsideMap())
- {
- xTar = unit.x;
- yTar = unit.y;
- }
- target = new Coord(xTar, yTar);
- Cannonball tempBall = new Cannonball() { x = xTar, y = yTar, turns = shotDuration(target) };
- List<Cannonball> tempBalls = new List<Cannonball>();
- tempBalls.Add(tempBall);
- if (tempThisShip.BallsWillHit(tempBalls))
- {
- Console.Error.WriteLine("would shoot self");
- return false;
- }
- if (DistFront(target) > 10)
- {
- return false;
- }
- if (shotDuration(target) > 3 && (unit.speed != 0 || tempShip.speed != 0))
- {
- return false;
- }
- return Fire();
- }
- public bool Fire(Ship unit, List<Ship> ships, List<Rum> rum, List<Cannonball> balls)
- {
- if (cannonCooldown > 0 || DistFront(unit) > 4)
- {
- return false;
- }
- int yTarOffset = 0;
- int xTarOffset = 0;
- int eSpeed = unit.speed;
- int dist = DistFront(unit);
- int distToTarget = 0;
- int attempts = 0;
- int maxAttempts = 10;
- Ship tempShip = unit.Clone();
- var closestRum = rum.Where(a => !balls.Any(b => b.x == a.x && b.y == a.y)).OrderBy(c => c.Dist(tempShip)).FirstOrDefault();
- var front = tempShip.GetFront().neighbor(tempShip.orientation);
- if (ships.Any(a => a.GetMiddle().equals(front) || a.GetFront().equals(front) || a.GetBack().equals(front)))
- {//going to be speed 0, fire at center
- Console.Error.WriteLine("block enemy, fire center");
- this.target = tempShip.GetMiddle();
- return Fire();
- }
- return Fire(unit);
- //dont use yet
- if (closestRum == null)
- {
- return Fire(unit);
- }
- var targetRum = new Coord(closestRum.x, closestRum.y);
- bool fired = false;
- while (attempts < maxAttempts)
- {
- attempts++;
- //TODO: THIS
- Console.Error.WriteLine("loop {0}", attempts);
- tempShip.TheoryMove(targetRum, false);
- var frontDist = shotDuration(tempShip.GetFront());
- var middletDist = shotDuration(tempShip.GetMiddle());
- var backDist = shotDuration(tempShip.GetBack());
- if (attempts == frontDist)
- {
- Console.Error.WriteLine("predict front shot");
- this.target = tempShip.GetFront();
- return Fire();
- }
- else if (attempts == middletDist)
- {
- Console.Error.WriteLine("predict middle shot");
- this.target = tempShip.GetMiddle();
- return Fire();
- }
- else if (attempts == backDist)
- {
- Console.Error.WriteLine("predict back shot");
- this.target = tempShip.GetBack();
- return Fire();
- }
- }
- if (!fired)
- {
- return Fire(unit);
- }
- return false;
- }
- public void Avoid(Cannonball ball, List<Cannonball> balls, List<Mine> mines)
- {
- SetOffsets(ball.turns + 1);
- var front = GetOffsetFront();
- var back = GetOffsetBack();
- var middle = new Coord(x + speed * xOffset, y + speed * yOffset);
- if (ball.x == front.x && ball.y == front.y)
- {
- Console.Error.WriteLine("avoid front!");
- Swivel();
- }
- else if (ball.x == back.x && ball.y == back.y && speed < 2)
- {
- Console.Error.WriteLine("avoid back!");
- Swivel();
- //Console.WriteLine("FASTER");
- }
- else if (ball.x == middle.x && ball.y == middle.y && speed < 2)
- {
- Console.Error.WriteLine("avoid middle!");
- if (GetFront().x > 21 || GetFront().x < 1 || GetFront().y < 1 || GetFront().y > 19)
- {
- Swivel();
- }
- else
- {
- Faster();
- }
- }
- else
- {
- //Console.WriteLine("SLOWER");
- Console.Error.WriteLine("avoid something!");
- Swivel();
- }
- }
- public void Swivel(int? option = 0)
- {//1 right, -1 left
- if (option != 0)
- {
- Random rand = new Random();
- var dir = rand.Next(2) == 0 ? "PORT" : "STARBOARD";
- Console.WriteLine(dir);
- }
- else
- {
- var dir = option == 1 ? "STARBOARD" : "PORT";
- Console.WriteLine(dir);
- }
- }
- public void PerformAction(Action act, bool doAction = true)
- {
- if (priorities.ContainsKey(act))
- {
- var currentScore = priorities[act];
- if (priorities.Any(b => b.Value > currentScore))
- {
- var waitScore = priorities.ContainsKey(Action.WAIT) ? priorities[Action.WAIT] : -100;
- var portScore = priorities.ContainsKey(Action.PORT) ? priorities[Action.PORT] : -100;
- var starboardScore = priorities.ContainsKey(Action.STARBOARD) ? priorities[Action.STARBOARD] : -100;
- var fasterScore = priorities.ContainsKey(Action.FASTER) ? priorities[Action.FASTER] : -100;
- var slowerScore = priorities.ContainsKey(Action.SLOWER) ? priorities[Action.SLOWER] : -100;
- var sortedPairList = priorities.OrderByDescending(a => a.Value);
- if (!(sortedPairList.First().Value > 0) && (act == Action.PORT || act == Action.STARBOARD))
- {
- if (slowerScore == 0)
- {
- act = Action.SLOWER;
- Console.Error.WriteLine("Action Override - SLOWER 0");
- }
- else if (fasterScore == 0)
- {
- act = Action.FASTER;
- Console.Error.WriteLine("Action Override - FASTER 0");
- }
- else if (waitScore == 0)
- {
- act = Action.WAIT;
- Console.Error.WriteLine("Action Override - WAIT 0");
- }
- else
- {
- act = sortedPairList.First().Key;
- Console.Error.WriteLine("Action Override - " + sortedPairList.First().Key.ToString() + ": " + sortedPairList.First().Value);
- }
- }
- else
- {
- act = sortedPairList.First().Key;
- Console.Error.WriteLine("Action Override - " + sortedPairList.First().Key.ToString() + ": " + sortedPairList.First().Value);
- }
- }
- }
- if (doAction)
- {
- switch (act)
- {
- case Action.WAIT:
- case Action.MINE:
- case Action.NONE:
- if (layMines && mineCooldown <= 0)
- {
- Mine();
- mineCooldown = 5;
- }
- else
- {
- Wait();
- }
- break;
- case Action.FASTER:
- Faster();
- break;
- case Action.SLOWER:
- Slower();
- break;
- case Action.PORT:
- Port();
- break;
- case Action.STARBOARD:
- Starboard();
- break;
- }
- }
- }
- public void Move(Ship unit)
- {
- //TODO
- var tempShip = unit.Clone();
- tempShip.TheoryMove(Action.WAIT);
- var front = tempShip.GetFront().neighbor(tempShip.orientation);
- if (!front.isInsideMap())
- front = tempShip.GetMiddle();
- MoveTo(front.x, front.y);
- PerformAction(action);
- }
- public void Move(Rum unit)
- {
- //TODO
- MoveTo(unit.x, unit.y);
- PerformAction(action);
- }
- public void Move(int x1, int y1)
- {
- //TODO
- x1 = Math.Min(x1, 22);
- x1 = Math.Max(x1, 0);
- y1 = Math.Min(y1, 20);
- y1 = Math.Max(y1, 0);
- MoveTo(x1, y1);
- PerformAction(action);
- }
- public void Slower()
- {
- print("SLOWER");
- }
- public void Faster()
- {
- print("FASTER");
- }
- public void Port()
- {
- print("PORT");
- }
- public void Starboard()
- {
- print("STARBOARD");
- }
- public void Wait()
- {
- print("WAIT");
- }
- public void Mine()
- {
- print("MINE");
- }
- public void print(string str)
- {
- Console.WriteLine(str);
- }
- public int GetFX()
- {
- SetOffsets();
- return x + xOffset;
- }
- public int GetFY()
- {
- SetOffsets();
- return y + yOffset;
- }
- //TODO: THIS
- public void TheoryMove(int x, int y, bool custom = true)
- {
- MoveTo(x, y, custom);
- //adjust speed
- switch (action)
- {
- case Action.SLOWER:
- if (speed > 0)
- speed--;
- break;
- case Action.FASTER:
- if (speed < 2)
- speed++;
- break;
- }
- //move
- switch (speed)
- {
- case 2:
- var futurePos = GetFront().neighbor(orientation);
- if (futurePos.isInsideMap())
- {
- x = futurePos.x;
- y = futurePos.y;
- }
- else if (GetFront().isInsideMap())
- {
- futurePos = GetFront();
- x = futurePos.x;
- y = futurePos.y;
- }
- else
- {
- speed = 0;
- }
- break;
- case 1:
- var front = GetFront();
- if (front.isInsideMap())
- {
- x = front.x;
- y = front.y;
- }
- else
- {
- speed = 0;
- }
- break;
- case 0:
- break;
- }
- //rorate
- switch (action)
- {
- case Action.PORT:
- orientation++;
- if (orientation > 5)
- orientation = 0;
- break;
- case Action.STARBOARD:
- orientation--;
- if (orientation < 0)
- orientation = 5;
- break;
- }
- }
- public void TheoryMove(Action action)
- {
- //adjust speed
- switch (action)
- {
- case Action.SLOWER:
- if (speed > 0)
- speed--;
- break;
- case Action.FASTER:
- if (speed < 2)
- speed++;
- break;
- }
- //move
- //Console.Error.WriteLine("before: {0}, {1}", x, y);
- switch (speed)
- {
- case 2:
- var futurePos = GetFront().neighbor(orientation);
- if (futurePos.isInsideMap())
- {
- x = futurePos.x;
- y = futurePos.y;
- }
- else if (GetFront().isInsideMap())
- {
- futurePos = GetFront();
- x = futurePos.x;
- y = futurePos.y;
- }
- else
- {
- speed = 0;
- }
- break;
- case 1:
- var front = GetFront();
- if (front.isInsideMap())
- {
- x = front.x;
- y = front.y;
- }
- else
- {
- speed = 0;
- }
- break;
- case 0:
- break;
- }
- //Console.Error.WriteLine("after: {0}, {1}", x, y);
- //rorate
- switch (action)
- {
- case Action.PORT:
- orientation++;
- if (orientation > 5)
- orientation = 0;
- break;
- case Action.STARBOARD:
- orientation--;
- if (orientation < 0)
- orientation = 5;
- break;
- }
- }
- public void TheoryMove(Coord coord, bool custom = true)
- {
- TheoryMove(coord.x, coord.y, custom);
- }
- public void SetOffsets(int turns)
- {
- Coord currentCoord = new Coord(x, y);
- this.yOffset = 0;
- this.xOffset = 0;
- //first turn
- Coord newPosition = currentCoord.neighbor(orientation);
- //extra turns
- for (int i = 1; i < turns; i++)
- {
- newPosition = newPosition.neighbor(orientation);
- }
- this.xOffset = newPosition.x - currentCoord.x;
- this.yOffset = newPosition.y - currentCoord.y;
- }
- public void SetOffsets()
- {
- Coord currentCoord = new Coord(x, y);
- this.yOffset = 0;
- this.xOffset = 0;
- Coord newPosition = currentCoord.neighbor(orientation);
- this.xOffset = newPosition.x - currentCoord.x;
- this.yOffset = newPosition.y - currentCoord.y;
- }
- public int DistFront(Unit unit)
- {
- var front = GetFront();
- int xp1 = front.x - (front.y - (front.y & 1)) / 2;
- int zp1 = front.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = unit.x - (unit.y - (unit.y & 1)) / 2;
- int zp2 = unit.y;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int DistFront(Coord unit)
- {
- var front = GetFront();
- int xp1 = front.x - (front.y - (front.y & 1)) / 2;
- int zp1 = front.y;
- int yp1 = -(xp1 + zp1);
- int xp2 = unit.x - (unit.y - (unit.y & 1)) / 2;
- int zp2 = unit.y;
- int yp2 = -(xp2 + zp2);
- return (Math.Abs(xp1 - xp2) + Math.Abs(yp1 - yp2) + Math.Abs(zp1 - zp2)) / 2;
- }
- public int shotDuration(Coord coord)
- {
- return 1 + (int)Math.Round(DistFront(coord) / 3.0);
- }
- public void MoveTo(int X, int Y, bool custom = true)
- {
- Coord currentPosition = new Coord(this.x, this.y);
- Coord targetPosition = new Coord(X, Y);
- if (currentPosition.equals(targetPosition))
- {
- this.action = Action.FASTER;
- return;
- }
- double targetAngle, angleStraight, anglePort, angleStarboard, centerAngle, anglePortCenter, angleStarboardCenter;
- switch (speed)
- {
- case 2:
- case 1:
- if (!custom && speed == 2)
- {
- this.action = Action.SLOWER;
- break;
- }
- // Suppose we've moved first
- currentPosition = currentPosition.neighbor(orientation);
- if (!currentPosition.isInsideMap())
- {
- this.action = Action.SLOWER;
- break;
- }
- // Target reached at next turn
- if (currentPosition.equals(targetPosition))
- {
- this.action = Action.FASTER;
- break;
- }
- // For each neighbor cell, find the closest to target
- targetAngle = currentPosition.angle(targetPosition);
- angleStraight = Math.Min(Math.Abs(orientation - targetAngle), 6 - Math.Abs(orientation - targetAngle));
- anglePort = Math.Min(Math.Abs((orientation + 1) - targetAngle), Math.Abs((orientation - 5) - targetAngle));
- angleStarboard = Math.Min(Math.Abs((orientation + 5) - targetAngle), Math.Abs((orientation - 1) - targetAngle));
- centerAngle = currentPosition.angle(new Coord(MAP_WIDTH / 2, MAP_HEIGHT / 2));
- anglePortCenter = Math.Min(Math.Abs((orientation + 1) - centerAngle), Math.Abs((orientation - 5) - centerAngle));
- angleStarboardCenter = Math.Min(Math.Abs((orientation + 5) - centerAngle), Math.Abs((orientation - 1) - centerAngle));
- // Next to target with bad angle, slow down then rotate (avoid to turn around the target!)
- if (currentPosition.distanceTo(targetPosition) == 1 && angleStraight > 1.5)
- {
- this.action = Action.SLOWER;
- break;
- }
- int? distanceMin = null;
- // Test forward
- Coord nextPosition = currentPosition.neighbor(orientation);
- if (nextPosition.isInsideMap())
- {
- distanceMin = nextPosition.distanceTo(targetPosition);
- this.action = Action.WAIT;
- int distance = nextPosition.distanceTo(targetPosition);
- if (custom && distance > 5)
- {
- this.action = Action.FASTER;
- }
- }
- // Test port
- nextPosition = currentPosition.neighbor((orientation + 1) % 6);
- if (nextPosition.isInsideMap())
- {
- int distance = nextPosition.distanceTo(targetPosition);
- if (distanceMin == null || distance < distanceMin || distance == distanceMin && anglePort < angleStraight - 0.5)
- {
- distanceMin = distance;
- if (distance <= 5 && speed == 2 && custom)
- {
- this.action = Action.SLOWER;
- }
- else
- {
- this.action = Action.PORT;
- }
- }
- }
- // Test starboard
- nextPosition = currentPosition.neighbor((orientation + 5) % 6);
- if (nextPosition.isInsideMap())
- {
- int distance = nextPosition.distanceTo(targetPosition);
- if (distanceMin == null || distance < distanceMin
- || (distance == distanceMin && angleStarboard < anglePort - 0.5 && this.action == Action.PORT)
- || (distance == distanceMin && angleStarboard < angleStraight - 0.5 && this.action == Action.NONE)
- || (distance == distanceMin && this.action == Action.PORT && angleStarboard == anglePort
- && angleStarboardCenter < anglePortCenter)
- || (distance == distanceMin && this.action == Action.PORT && angleStarboard == anglePort
- && angleStarboardCenter == anglePortCenter && (orientation == 1 || orientation == 4)))
- {
- distanceMin = distance;
- if (distance <= 5 && speed == 2 && custom)
- {
- this.action = Action.SLOWER;
- }
- else
- {
- this.action = Action.STARBOARD;
- }
- }
- }
- break;
- case 0:
- // Rotate ship towards target
- targetAngle = currentPosition.angle(targetPosition);
- angleStraight = Math.Min(Math.Abs(orientation - targetAngle), 6 - Math.Abs(orientation - targetAngle));
- anglePort = Math.Min(Math.Abs((orientation + 1) - targetAngle), Math.Abs((orientation - 5) - targetAngle));
- angleStarboard = Math.Min(Math.Abs((orientation + 5) - targetAngle), Math.Abs((orientation - 1) - targetAngle));
- centerAngle = currentPosition.angle(new Coord(MAP_WIDTH / 2, MAP_HEIGHT / 2));
- anglePortCenter = Math.Min(Math.Abs((orientation + 1) - centerAngle), Math.Abs((orientation - 5) - centerAngle));
- angleStarboardCenter = Math.Min(Math.Abs((orientation + 5) - centerAngle), Math.Abs((orientation - 1) - centerAngle));
- Coord forwardPosition = currentPosition.neighbor(orientation);
- this.action = Action.FASTER;
- if (anglePort <= angleStarboard)
- {
- this.action = Action.PORT;
- }
- if (angleStarboard < anglePort || angleStarboard == anglePort && angleStarboardCenter < anglePortCenter
- || angleStarboard == anglePort && angleStarboardCenter == anglePortCenter && (orientation == 1 || orientation == 4))
- {
- this.action = Action.STARBOARD;
- }
- if (forwardPosition.isInsideMap() && angleStraight <= anglePort && angleStraight <= angleStarboard)
- {
- this.action = Action.FASTER;
- }
- break;
- }
- }
- }
- class Rum : Unit
- {
- public int rum;
- public bool taken;
- public Rum Clone()
- {
- return new Rum()
- {
- id = this.id,
- x = this.x,
- y = this.y,
- rum = this.rum,
- type = this.type,
- };
- }
- }
- class Cannonball : Unit
- {
- public int shipId;
- public int turns;
- public Cannonball() { }
- public Cannonball(int X, int Y, int Turns)
- {
- x = X;
- y = Y;
- turns = Turns;
- }
- public Cannonball Clone()
- {
- return new Cannonball()
- {
- x = this.x,
- y = this.y,
- id = this.id,
- type = this.type,
- shipId = this.shipId,
- turns = this.turns,
- };
- }
- public bool WillHit(Ship ship)
- {
- //ship.SetOffsets(turns * ship.speed);
- var front = ship.GetFront(turns);
- var back = ship.GetBack(turns);
- var middle = ship.GetMiddle(turns);
- if (Pos().equals(front))
- {
- return true;
- }
- if (Pos().equals(back))
- {
- return true;
- }
- if (Pos().equals(middle))
- {
- return true;
- }
- return false;
- }
- }
- class Mine : Unit
- {
- public bool hit;
- public Mine Clone()
- {
- return new Mine()
- {
- id = this.id,
- x = this.x,
- y = this.y,
- type = this.type,
- };
- }
- public bool WillHit(Ship ship)
- {
- //var advTurns = ship.speed == 2 ? 1 : 2;
- var front = ship.GetFront(ship.speed + 1);
- var back = ship.GetBack(ship.speed + 1);
- var middle = ship.GetMiddle(ship.speed + 1);
- if (Pos().equals(front))
- {
- return true;
- }
- if (Pos().equals(back))
- {
- return true;
- }
- if (Pos().equals(middle))
- {
- return true;
- }
- return false;
- }
- }
- public enum Action
- {
- FASTER, SLOWER, PORT, STARBOARD, FIRE, MINE, NONE, WAIT
- }
- public class Coord
- {
- private int MAP_WIDTH = 23;
- private int MAP_HEIGHT = 21;
- public int[,] DIRECTIONS_EVEN = new int[,] { { 1, 0 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, 1 } };
- public int[,] DIRECTIONS_ODD = new int[,] { { 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, 0 }, { 0, 1 }, { 1, 1 } };
- public int x;
- public int y;
- public Coord(int x, int y)
- {
- this.x = x;
- this.y = y;
- }
- public Coord Clone()
- {
- return new Coord(x, y);
- }
- public Coord(Coord other)
- {
- this.x = other.x;
- this.y = other.y;
- }
- public double angle(Coord targetPosition)
- {
- double dy = (targetPosition.y - this.y) * Math.Sqrt(3) / 2;
- double dx = targetPosition.x - this.x + ((this.y - targetPosition.y) & 1) * 0.5;
- double angle = -Math.Atan2(dy, dx) * 3 / Math.PI;
- if (angle < 0)
- {
- angle += 6;
- }
- else if (angle >= 6)
- {
- angle -= 6;
- }
- return angle;
- }
- public CubeCoordinate toCubeCoordinate()
- {
- int xp = x - (y - (y & 1)) / 2;
- int zp = y;
- int yp = -(xp + zp);
- return new CubeCoordinate(xp, yp, zp);
- }
- public Coord neighbor(int orientation)
- {
- int newY, newX;
- if (this.y % 2 == 1)
- {
- newY = this.y + DIRECTIONS_ODD[orientation, 1];
- newX = this.x + DIRECTIONS_ODD[orientation, 0];
- }
- else
- {
- newY = this.y + DIRECTIONS_EVEN[orientation, 1];
- newX = this.x + DIRECTIONS_EVEN[orientation, 0];
- }
- return new Coord(newX, newY);
- }
- public bool isInsideEdge()
- {
- return x >= 3 && x < MAP_WIDTH - 3 && y >= 3 && y < MAP_HEIGHT - 3;
- }
- public bool isInsideMap()
- {
- return x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT;
- }
- public int distanceTo(Coord dst)
- {
- return this.toCubeCoordinate().distanceTo(dst.toCubeCoordinate());
- }
- public bool equals(Object obj)
- {
- if (obj == null || this.GetType() != obj.GetType())
- {
- return false;
- }
- Coord other = (Coord)obj;
- return y == other.y && x == other.x;
- }
- public bool equals(Coord other)
- {
- return y == other.y && x == other.x;
- }
- public bool equals(int X, int Y)
- {
- return y == Y && x == X;
- }
- public override string ToString()
- {
- return string.Format("{0} {1}", x, y);
- }
- }
- public class CubeCoordinate
- {
- int[,] directions = new int[,] { { 1, -1, 0 }, { +1, 0, -1 }, { 0, +1, -1 }, { -1, +1, 0 }, { -1, 0, +1 }, { 0, -1, +1 } };
- int x, y, z;
- public CubeCoordinate(int x, int y, int z)
- {
- this.x = x;
- this.y = y;
- this.z = z;
- }
- public CubeCoordinate Clone()
- {
- return new CubeCoordinate(x, y, z);
- }
- public Coord toOffsetCoordinate()
- {
- int newX = x + (z - (z & 1)) / 2;
- int newY = z;
- return new Coord(newX, newY);
- }
- public CubeCoordinate neighbor(int orientation)
- {
- int nx = this.x + directions[orientation, 0];
- int ny = this.y + directions[orientation, 1];
- int nz = this.z + directions[orientation, 2];
- return new CubeCoordinate(nx, ny, nz);
- }
- public int distanceTo(CubeCoordinate dst)
- {
- return (Math.Abs(x - dst.x) + Math.Abs(y - dst.y) + Math.Abs(z - dst.z)) / 2;
- }
- public override string ToString()
- {
- return string.Format("{0} {1} {2}", x, y, z);
- }
- }
- #endregion
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement