static void Main(string[] args) { //Standard input string[] inputs; int numSites = int.Parse(Console.ReadLine()); for (int i = 0; i < numSites; i++) { inputs = Console.ReadLine().Split(' '); int siteId = int.Parse(inputs[0]); int x = int.Parse(inputs[1]); int y = int.Parse(inputs[2]); int radius = int.Parse(inputs[3]); listBarrack.Add(new Barrack(siteId, x, y, radius, -1)); } // game loop while (true) { //Joueur inputs = Console.ReadLine().Split(' '); int gold = int.Parse(inputs[0]); int touchedSite = int.Parse(inputs[1]); // -1 if none moi.gold = gold; moi.touchedSite = touchedSite; for (int i = 0; i < numSites; i++) { inputs = Console.ReadLine().Split(' '); int siteId = int.Parse(inputs[0]); int remainingGold = int.Parse(inputs[1]); // used in future leagues int maxProductionRate = int.Parse(inputs[2]); // used in future leagues int structureType = int.Parse(inputs[3]); // -1 = No structure, 2 = Barracks int owner = int.Parse(inputs[4]); // -1 = No structure, 0 = Friendly, 1 = Enemy int param1 = int.Parse(inputs[5]); int param2 = int.Parse(inputs[6]); Barrack barrack = getBarrackFromId(siteId); if (barrack == null) { Console.Error.WriteLine("WARN: Barrack not found " + siteId); } else { BarrackType type = BarrackType.BUILD_SITE; if (structureType == 2 && param2 == 0) { type = BarrackType.CASERNE; } else if (structureType == 2 && param2 == 1) { type = BarrackType.ARCHERY; } else if (structureType == 1) { type = BarrackType.TOWER; barrack.pv = param1; barrack.actionRadius = param2; } else if (structureType == 0) { type = BarrackType.MINE; barrack.productionRate = param1; barrack.maxProductionRate = maxProductionRate; barrack.remainingGold = remainingGold; } barrack.setType(type); barrack.ownerId = owner; barrack.cyclesRemaining = param1; } } //Units int numUnits = int.Parse(Console.ReadLine()); listUnit.Clear(); listUnit.Capacity = numUnits - 2; // - 2 queens for (int i = 0; i < numUnits; i++) { inputs = Console.ReadLine().Split(' '); int x = int.Parse(inputs[0]); int y = int.Parse(inputs[1]); int owner = int.Parse(inputs[2]); int unitType = int.Parse(inputs[3]); // -1 = QUEEN, 0 = KNIGHT, 1 = ARCHER int health = int.Parse(inputs[4]); if (unitType == -1) //Qween { Joueur joueur = getJoueurFromId(owner); if (joueur.queen == null) { joueur.queen = new Unit(x, y, health, UnitType.QUEEN, owner); listUnit.Add(joueur.queen); } else { joueur.queen.x = x; joueur.queen.y = y; joueur.queen.pv = health; } } else { UnitType type = UnitType.UNKNOWN; if (unitType == 0) { type = UnitType.KNIGHT; } else if (unitType == 1) { type = UnitType.ARCHER; } listUnit.Add(new Unit(x, y, health, type, owner)); } } //Output variables Barrack selectedBarrack = null; BarrackType selectedType = BarrackType.CASERNE; bool shouldBuild = false; List <int> listTrainingId = new List <int> { }; listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x)).ToList(); int towerTargetCount = 0; int mineTargetCount = 0; int caserneTargetCount = 0; int armyTargetSize = 1; int giantTargetCount = 0; int protectionPointX = 0; int protectionPointY = 0; List <Action> priorityList = new List <Action> { }; bool underAttack = false; int attackDistance = 2000; int meanAdvFirstUnitsX = 0; int meanAdvFirstUnitsY = 0; int meanAdvFirstUnitsCount = 0; listUnit = listUnit.OrderBy(x => moi.queen.distanceTo(x)).ToList(); int c = 0; foreach (Unit unit in listUnit) { if (unit.ownerId != moi.id && unit.pv > 6 ) { if (c < 3) { meanAdvFirstUnitsX += unit.x; meanAdvFirstUnitsY += unit.y; meanAdvFirstUnitsCount++; c++; } else { break; } } } if (meanAdvFirstUnitsCount > 1) { meanAdvFirstUnitsX /= meanAdvFirstUnitsCount; meanAdvFirstUnitsY /= meanAdvFirstUnitsCount; attackDistance = (int)moi.queen.distanceTo(meanAdvFirstUnitsX, meanAdvFirstUnitsY); if (attackDistance < 150) { underAttack = true; Console.Error.WriteLine("Under attack"); } } Console.Error.WriteLine("Touching " + moi.touchedSite); int currentTowerCount = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.TOWER).Count(); int currentMineCount = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.MINE).Count(); int currentCaserneCount = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.CASERNE).Count(); for (int i = 0; i <= 5; i++) { if (i == 0) { towerTargetCount = 0; mineTargetCount = 3; caserneTargetCount = 0; armyTargetSize = 1; priorityList = new List <Action> { Action.REPAIR_MINE, Action.BUILD_MINE, Action.BUILD_CASERNE, Action.REPAIR_TOWER, Action.BUILD_TOWER, Action.SELF_PROTECT, Action.SELF_PROTECT_TOWER }; if (moi.queen.pv <= 40) { priorityList = new List <Action> { Action.BUILD_CASERNE, Action.REPAIR_MINE, Action.BUILD_MINE, Action.REPAIR_TOWER, Action.BUILD_TOWER, Action.SELF_PROTECT, Action.SELF_PROTECT_TOWER }; } } else if (i == 1) //add 1 tower fast { towerTargetCount = 1; mineTargetCount = 3; caserneTargetCount = 1; armyTargetSize = 1; priorityList = new List <Action> { Action.BUILD_CASERNE, Action.REPAIR_MINE, Action.BUILD_MINE, Action.REPAIR_TOWER, Action.BUILD_TOWER, Action.SELF_PROTECT, Action.SELF_PROTECT_TOWER }; } else if (i == 2) { towerTargetCount = 3; mineTargetCount = 3; caserneTargetCount = 2; armyTargetSize = 2; priorityList = new List <Action> { Action.BUILD_TOWER, Action.REPAIR_TOWER, Action.REPAIR_MINE, Action.BUILD_MINE, Action.SELF_PROTECT, Action.BUILD_CASERNE, Action.SELF_PROTECT_TOWER }; } /*else if(i == 3){ * towerTargetCount = 3; * mineTargetCount = 3; * caserneTargetCount = 2; * armyTargetSize = 2; * priorityList = new List<Action>{ * Action.REPAIR_TOWER, * Action.BUILD_TOWER, * Action.SELF_PROTECT, * Action.REPAIR_MINE, * Action.BUILD_CASERNE, * Action.BUILD_MINE, * Action.SELF_PROTECT_TOWER * }; * }*/ else if (i == 4) { towerTargetCount = 4; mineTargetCount = 3; caserneTargetCount = 3; armyTargetSize = 2; priorityList = new List <Action> { Action.REPAIR_TOWER, Action.BUILD_TOWER, Action.SELF_PROTECT, Action.REPAIR_MINE, Action.BUILD_CASERNE, Action.BUILD_MINE, Action.SELF_PROTECT_TOWER }; } else if (i == 5) { towerTargetCount = 5; mineTargetCount = 3; caserneTargetCount = 2; armyTargetSize = 2; priorityList = new List <Action> { Action.REPAIR_TOWER, Action.SELF_PROTECT, Action.REPAIR_MINE, Action.BUILD_TOWER, Action.BUILD_CASERNE, Action.BUILD_MINE, Action.SELF_PROTECT_TOWER }; } if (towerTargetCount > currentTowerCount || mineTargetCount > currentMineCount || caserneTargetCount > currentCaserneCount) { currentScale = i; break; } currentScale = i; } if (underAttack /*|| moi.queen.pv < 15*/) { if (towerTargetCount < 4) { towerTargetCount = 4; } priorityList = new List <Action> { Action.REPAIR_TOWER, Action.BUILD_TOWER, Action.SELF_PROTECT, Action.BUILD_CASERNE, Action.REPAIR_MINE, Action.BUILD_MINE, Action.SELF_PROTECT_TOWER }; if (moi.touchedSite != -1 && getBarrackFromId(moi.touchedSite).type != BarrackType.TOWER) { priorityList = new List <Action> { Action.BUILD_TOWER, Action.REPAIR_TOWER, Action.SELF_PROTECT, Action.BUILD_CASERNE, Action.REPAIR_MINE, Action.BUILD_MINE, Action.SELF_PROTECT_TOWER }; } } Console.Error.WriteLine("Scale " + currentScale); Console.Error.WriteLine("Tower " + currentTowerCount + "/" + towerTargetCount); Console.Error.WriteLine("Mine " + currentMineCount + "/" + mineTargetCount); Console.Error.WriteLine("Caserne " + currentCaserneCount + "/" + caserneTargetCount); Console.Error.WriteLine("Adv at " + attackDistance); foreach (Action action in priorityList) { switch (action) { case Action.SELF_PROTECT: if (shouldBuild == false && selectedBarrack == null && moi.queen.pv < 45 && protectionPointX == 0 && protectionPointY == 0) { bool ennemyClose = false; foreach (Unit unit in listUnit) { if (unit.ownerId != moi.id && unit.distanceTo(moi.queen) < 300 ) { ennemyClose = true; break; } } if (ennemyClose) { List <Barrack> moiTowerList = listBarrack.Where(x => x.ownerId == moi.id && x.type == BarrackType.TOWER).ToList(); if (moiTowerList.Count > 1) { //Get moi tower center int towerCenterX = 0; int towerCenterY = 0; foreach (Barrack tower in moiTowerList) { towerCenterX += tower.x; towerCenterY += tower.y; } towerCenterX /= moiTowerList.Count; towerCenterY /= moiTowerList.Count; protectionPointX = towerCenterX; protectionPointY = towerCenterY; //Get adv unit center int advUnitCenterX = 0; int advUnitCenterY = 0; int advUnitCount = 0; foreach (Unit unit in listUnit) { if (unit.ownerId == adv.id && unit.type != UnitType.QUEEN) { advUnitCenterX += unit.x; advUnitCenterY += unit.y; advUnitCount++; } } advUnitCenterX /= advUnitCount; advUnitCenterY /= advUnitCount; //move back keeping in the towers range bool postitionValid = true; for (double i = 0; i <= 1 && postitionValid; i += 0.02) { int x1 = towerCenterX + (int)(i * (double)(towerCenterX - advUnitCenterX)); int y1 = towerCenterY + (int)(i * (double)(towerCenterY - advUnitCenterY)); int inRadiusCount = 0; foreach (Barrack tower in moiTowerList) { if (tower.distanceTo(x1, y1) < tower.actionRadius) { inRadiusCount++; } } postitionValid = inRadiusCount >= 3; if (postitionValid) { protectionPointX = x1; protectionPointY = y1; } } Console.Error.WriteLine("Protect " + (protectionPointX - moi.queen.x) + " " + (protectionPointY - moi.queen.y)); } } } break; case Action.SELF_PROTECT_TOWER: if (shouldBuild == false && selectedBarrack == null && moi.queen.pv < 60 && protectionPointX == 0 && protectionPointY == 0) { bool towerClose = false; foreach (Barrack barrack in listBarrack) { if (barrack.ownerId != moi.id && barrack.type == BarrackType.TOWER && barrack.distanceTo(moi.queen) <= barrack.actionRadius + 60 ) { bool protectedByUnit = false; foreach (Unit unit in listUnit) { if (unit.ownerId == moi.id && barrack.distanceTo(unit) <= barrack.actionRadius) { protectedByUnit = true; break; } } if (!protectedByUnit) { Console.Error.WriteLine("TC:" + barrack.id + " " + barrack.distanceTo(moi.queen) + " < " + barrack.actionRadius); towerClose = true; break; } } } if (towerClose) { List <Barrack> moiTowerList = listBarrack.Where(x => x.ownerId == moi.id && x.type == BarrackType.TOWER).ToList(); foreach (Barrack tower in moiTowerList) { protectionPointX += tower.x; protectionPointY += tower.y; } if (moiTowerList.Count > 0) { protectionPointX /= moiTowerList.Count; protectionPointY /= moiTowerList.Count; Console.Error.WriteLine("Protect Tower "); } } } break; case Action.DESTROY: //Destroy adv towers Console.Error.WriteLine("Destroy adv "); listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x)).ToList(); if (shouldBuild == false) { foreach (Barrack barrack in listBarrack) { if (selectedBarrack == null && barrack.isBuildable(moi, listBarrack, false)) { selectedBarrack = barrack; selectedType = BarrackType.TOWER; shouldBuild = true; Console.Error.WriteLine("DT " + barrack.id); break; } } } break; case Action.BUILD_TOWER: //Keep n towers built, prefer building on moi side listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x) - 0.5 * x.distanceTo(1920 / 2, moi.queen.y)).ToList(); int moiTowerBuilt = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.TOWER).Count(); if (shouldBuild == false && moiTowerBuilt < towerTargetCount) { foreach (Barrack barrack in listBarrack) { bool allowOwn = false; if (selectedBarrack != null) { allowOwn = moi.queen.pv < 20 && selectedBarrack.ownerId == moi.id && selectedBarrack.type != BarrackType.TOWER; } if (selectedBarrack == null && barrack.isBuildable(moi, listBarrack, allowOwn)) { selectedBarrack = barrack; selectedType = BarrackType.TOWER; shouldBuild = true; break; } } } break; case Action.BUILD_MINE: //Keep n mine built listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x) - 100 * (x.maxProductionRate > 0?x.maxProductionRate:1)).ToList(); int moiMineBuilt = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.MINE).Count(); if (shouldBuild == false && moiMineBuilt < mineTargetCount) { foreach (Barrack barrack in listBarrack) { bool allowOwn = towerTargetCount < currentTowerCount && currentTowerCount > 2 && barrack.type == BarrackType.TOWER; if (selectedBarrack == null && barrack.isBuildable(moi, listBarrack, allowOwn) && //allow to destroy own towers (barrack.remainingGold > 50 || barrack.remainingGold == -1) ) { bool advClose = false; foreach (Unit unit in listUnit) { if (unit.ownerId != moi.id && unit.distanceTo(barrack) < barrack.radius + 30 ) { advClose = true; break; } } bool reachable = true; if (attackDistance < barrack.distanceTo(moi.queen)) { reachable = false; } if (!advClose && reachable) { selectedBarrack = barrack; selectedType = BarrackType.MINE; shouldBuild = true; Console.Error.WriteLine("BM ID " + barrack.id + " G" + barrack.remainingGold + " R" + barrack.maxProductionRate + " " + barrackTypeToString(barrack.type)); Console.Error.WriteLine("Own:" + allowOwn + " Build:" + barrack.isBuildable(moi, listBarrack, allowOwn)); break; } } } } break; case Action.REPAIR_MINE: //Repair mines List <Barrack> moiMineList = listBarrack.Where(x => x.ownerId == moi.id && x.type == BarrackType.MINE).ToList(); moiMineList = moiMineList.OrderBy(x => x.productionRate).ToList(); if (shouldBuild == false) { foreach (Barrack barrack in moiMineList) { if (barrack.productionRate < barrack.maxProductionRate) { Console.Error.WriteLine("RM " + barrack.productionRate + " " + barrack.maxProductionRate); selectedBarrack = barrack; selectedType = BarrackType.MINE; shouldBuild = true; break; } } } break; case Action.BUILD_CASERNE: //Keep n caserne built, prefer building in the middle listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x) + 0.5 * x.distanceTo(1920 / 2, moi.queen.y)).ToList(); int moiCaserneBuilt = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.CASERNE).Count(); if (shouldBuild == false && moiCaserneBuilt < caserneTargetCount) { foreach (Barrack barrack in listBarrack) { if (selectedBarrack == null && barrack.isBuildable(moi, listBarrack)) { selectedBarrack = barrack; selectedType = BarrackType.CASERNE; shouldBuild = true; break; } } } break; case Action.REPAIR_TOWER: //Repair towers listBarrack = listBarrack.OrderBy(x => moi.queen.distanceTo(x)).ToList(); List <Barrack> towerList = listBarrack.Where(x => x.ownerId == moi.id && x.type == BarrackType.TOWER).ToList(); towerList = towerList.OrderBy(x => moi.queen.distanceTo(x)).ToList(); if (shouldBuild == false && currentTowerCount <= towerTargetCount) { foreach (Barrack barrack in towerList) { int minPoints = 200; if (moi.touchedSite == barrack.id) { minPoints = 700; } if (barrack.pv < minPoints) { Console.Error.WriteLine("RT " + barrack.pv); selectedBarrack = barrack; selectedType = BarrackType.TOWER; shouldBuild = true; break; } } } break; default: break; } } //Wait gold for n knight army int moiCaserneCount = listBarrack.FindAll(o => o.ownerId == moi.id && o.type == BarrackType.CASERNE).Count(); if (moiCaserneCount < armyTargetSize) { armyTargetSize = moiCaserneCount; } if (moi.gold >= armyTargetSize * Unit.getUnitCost(UnitType.KNIGHT)) { listBarrack = listBarrack.OrderBy(x => adv.queen.distanceTo(x)).ToList(); foreach (Barrack barrack in listBarrack) { if (barrack.ownerId == moi.id && barrack.cyclesRemaining == 0 && barrack.type == BarrackType.CASERNE) { if (moi.gold >= barrack.unitCost) { listTrainingId.Add(barrack.id); moi.gold -= barrack.unitCost; Console.Error.WriteLine("train army"); } } } } //Send knight if queen is close if (moi.gold >= Unit.getUnitCost(UnitType.KNIGHT)) { listBarrack = listBarrack.OrderBy(x => adv.queen.distanceTo(x)).ToList(); foreach (Barrack barrack in listBarrack) { if (barrack.ownerId == moi.id && barrack.cyclesRemaining == 0 && barrack.type == BarrackType.CASERNE) { if (moi.gold >= barrack.unitCost && barrack.distanceTo(adv.queen) < 550) { listTrainingId.Add(barrack.id); moi.gold -= barrack.unitCost; Console.Error.WriteLine("adv queen close"); } } } } //Write the output // First line: A valid queen action // Second line: A set of training instructions //Build if (protectionPointX != 0 && protectionPointY != 0) { Console.Error.WriteLine(">Protect"); if (moi.touchedSite != -1 && (getBarrackFromId(moi.touchedSite).type == BarrackType.BUILD_SITE || (getBarrackFromId(moi.touchedSite).ownerId == adv.id && getBarrackFromId(moi.touchedSite).type != BarrackType.TOWER) ) ) { Console.WriteLine("BUILD " + moi.touchedSite + " " + barrackTypeToString(BarrackType.TOWER)); } else { Console.WriteLine("MOVE " + protectionPointX + " " + protectionPointY); } } else if (shouldBuild && moi.touchedSite != -1 && selectedBarrack.id == moi.touchedSite) { Console.Error.WriteLine(">Build"); Console.WriteLine("BUILD " + selectedBarrack.id + " " + barrackTypeToString(selectedType)); } else if (selectedBarrack != null) { Console.Error.WriteLine(">Move " + selectedBarrack.id); if (moi.touchedSite != -1 && (getBarrackFromId(moi.touchedSite).type == BarrackType.BUILD_SITE || (getBarrackFromId(moi.touchedSite).ownerId == adv.id && getBarrackFromId(moi.touchedSite).type != BarrackType.TOWER) ) ) { Console.WriteLine("BUILD " + moi.touchedSite + " " + barrackTypeToString(BarrackType.TOWER)); } else { Console.WriteLine("MOVE " + selectedBarrack.x + " " + selectedBarrack.y); } } else { Console.Error.WriteLine(">Wait"); int advUnitCount = listUnit.FindAll(o => o.ownerId != moi.id && o.type != UnitType.QUEEN).Count();; if (moi.touchedSite != -1 && getBarrackFromId(moi.touchedSite).type == BarrackType.BUILD_SITE) { Console.WriteLine("BUILD " + moi.touchedSite + " " + barrackTypeToString(BarrackType.TOWER)); } else if (advUnitCount > 4) { //hide beetween towers List <Barrack> moiTowerList = listBarrack.Where(x => x.ownerId == moi.id && x.type == BarrackType.TOWER).ToList(); protectionPointX = 0; protectionPointY = 0; foreach (Barrack tower in moiTowerList) { protectionPointX += tower.x; protectionPointY += tower.y; } if (moiTowerList.Count > 0) { protectionPointX /= moiTowerList.Count; protectionPointY /= moiTowerList.Count; Console.Error.WriteLine("Protect waiting"); Console.WriteLine("MOVE " + protectionPointX + " " + protectionPointY); } } else { Console.WriteLine("WAIT"); } } //Training string trainingList = ""; foreach (int id in listTrainingId) { trainingList += " " + id; } Console.WriteLine("TRAIN" + trainingList); } }