Skip to content

Instantly share code, notes, and snippets.

@Arnauld
Created December 19, 2014 10:23
Show Gist options
  • Save Arnauld/0a04ee2a80f323eafcfe to your computer and use it in GitHub Desktop.
Save Arnauld/0a04ee2a80f323eafcfe to your computer and use it in GitHub Desktop.
Platinum-rift [JAVA]
import java.io.ByteArrayOutputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.*;
/**
*
*/
class Player {
private static boolean DEBUG = true;
public static void main(String args[]) {
new Player().start();
}
//
private Scanner in;
private final PrintStream out;
private final PrintStream debug;
private final ByteArrayOutputStream bout = new ByteArrayOutputStream();
//
public final Random random = new Random();
//
private int round = 0;
private int playerCount;
private int myId;
private int zoneCount;
private Zone[] zones;
//
private int availablePlatinum;
private List<Region> regions;
//
private List<Move> moves = new ArrayList<Move>();
private List<Purchase> purchases = new ArrayList<Purchase>();
public Player() {
this(System.in, System.out, System.err);
}
public Player(InputStream in, PrintStream out, PrintStream debug) {
changeInput(in);
this.out = out;
this.debug = debug;
}
//-----------------------------------------------------
// __ _ ___ ___ ___ ___ ___ ___ _ __
// _____ / _` |/ __/ __/ _ \/ __/ __|/ _ \| '__|
// |_____| (_| | (_| (_| __/\__ \__ \ (_) | |
// \__,_|\___\___\___||___/___/\___/|_|
//
//-----------------------------------------------------
public int round() {
return round;
}
public void changeRound(int round) {
this.round = round;
}
public void changeInput(InputStream in) {
if (DEBUG)
in = new FilterInputStream(in) {
@Override
public int read() throws IOException {
int read = super.read();
if (read != -1)
bout.write(read);
return read;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
int read = super.read(b, off, len);
if (read > 0) {
bout.write(b, off, read);
}
return read;
}
};
this.in = new Scanner(in);
}
public int zoneCount() {
return zoneCount;
}
public int playerCount() {
return playerCount;
}
public int getMyId() {
return myId;
}
public Zone[] getZones() {
return zones;
}
public List<Move> getMoves() {
return moves;
}
public List<Purchase> getPurchases() {
return purchases;
}
public int getAvailablePlatinum() {
return availablePlatinum;
}
public Zone zone(int zoneId) {
return zones[zoneId];
}
private Map<Integer, Zone> newZoneByIdMap() {
Map<Integer, Zone> zoneById = new HashMap<Integer, Zone>();
for (Zone zone : zones) {
zoneById.put(zone.zoneId, zone);
}
return zoneById;
}
public List<Region> getRegions() {
return regions;
}
//---------------------------------------------------------------
// _
// __ _ __ _ _ __ ___ ___ | | ___ ___ _ __
// _____ / _` |/ _` | '_ ` _ \ / _ \ | |/ _ \ / _ \| '_ \
// |_____| (_| | (_| | | | | | | __/ | | (_) | (_) | |_) |
// \__, |\__,_|_| |_| |_|\___| |_|\___/ \___/| .__/
// |___/ |_|
//---------------------------------------------------------------
public void start() {
initializeFromInput();
// game loop
while (true) {
round++;
updateStatusFromInput();
processIA();
}
}
public void processIA() {
moves.clear();
purchases.clear();
think();
for (Zone zone : zones) {
packOrders(zone);
}
display(out, moves);
display(out, purchases);
}
//-------------------------------------------------------------------------
// _
// (_) __ _
// _____| |/ _` |
// |_____| | (_| |
// |_|\__,_|
//-------------------------------------------------------------------------
private void think() {
if (round == 1) {
initialSpawn();
} else {
takeOrders();
//expand();
}
}
private void takeOrders() {
List<Order> orders = new ArrayList<Order>();
Context ctx = newContext();
for (Zone zone : zones) {
zone.clearAssignmentsAndStats(zones, myId);
if (zone.region.isOwned(myId))
continue;
if (zone.isSpawnPossible(myId))
orders.add(new Spawn(zone, myId));
if (zone.myPods(myId) > 0) {
if (zone.notOwnedBy(myId)) {
orders.add(new Fight(zone));
orders.add(new Flee(zone));
} else {
orders.add(new Support(zone));
}
} else if (zone.notOwnedBy(myId)) {
orders.add(new Conquer(zone, zone.maxOtherPods(myId)));
}
}
// sort in reverse order
// so that removing the last element is less consuming
Collections.sort(orders, orderPriorityReverseComparator(ctx));
List<Order> selected = new ArrayList<Order>();
for (int i = orders.size() - 1; i >= 0; i--) {
Order order = orders.remove(i);
if (order.evaluate(ctx)) {
selected.add(order);
// readjust priority based on previous decision...
Collections.sort(orders, orderPriorityReverseComparator(ctx));
}
}
for (Order order : selected) {
order.execute(ctx);
}
}
public Context newContext() {
return new Context(myId, zones, random, availablePlatinum / 20, round);
}
private void initialSpawn() {
Collections.sort(regions, regionPlatinumSourceComparator);
int remainingBuy = availablePlatinum / 20;
Iterator<Integer> buyings = distribute(remainingBuy).iterator();
Context ctx = new Context(myId, zones, random, remainingBuy, round);
int nbMaxInitialSpawnPerRegion = 3;
for (Region r : regions) {
int nb = nbMaxInitialSpawnPerRegion;
Collections.sort(r.zones, zonePlatinumSourceComparator(ctx));
for (Zone z : r.zones) {
if (buyings.hasNext()) {
z.purchasedNb = buyings.next();
} else {
return;
}
nb--;
if (nb == 0)
break;
}
}
}
public static List<Integer> distribute(int remainingBuy) {
List<Integer> xs = new ArrayList<Integer>();
if (remainingBuy > 3) {
xs.add(3);
remainingBuy = remainingBuy - 3;
}
int nb = remainingBuy / 3;
int n = nb;
while (n > 0) {
xs.add(2);
n--;
}
n = remainingBuy - 2 * nb;
while (n > 0) {
xs.add(1);
n--;
}
return xs;
}
private void packOrders(Zone z) {
if (z.purchasedNb > 0)
purchases.add(new Purchase(z.purchasedNb, z.zoneId));
int lastZId = -1;
Move move = null;
for (Integer zId : z.assignedToThis) {
if (move == null || zId != lastZId) {
lastZId = zId;
move = new Move(zId, z.zoneId);
moves.add(move);
}
move.nb++;
}
}
//---------------------------------
// _
// (_) ___
// _____| |/ _ \
// |_____| | (_) |
// |_|\___/
//---------------------------------
public void updateStatusFromInput() {
availablePlatinum = in.nextInt();
in.nextLine();
for (int i = 0; i < zoneCount(); i++) {
int zId = in.nextInt(); // this zone's ID
zones[zId].update(
in.nextInt(), // the player who owns this zone (-1 otherwise)
in.nextInt(), // player 0's PODs on this zone
in.nextInt(), // player 1's PODs on this zone
in.nextInt(), // player 2's PODs on this zone (always 0 for a two player game)
in.nextInt()); // player 3's PODs on this zone (always 0 for a two or three player game)
in.nextLine();
}
for (Region r : regions) {
r.invalidate();
}
// -- no more input there...
if (DEBUG) {
String string = bout.toString();
debug.println("::processIA::" + round);
debug.println(string);
bout.reset();
}
}
public void initializeFromInput() {
playerCount = in.nextInt();
myId = in.nextInt();
zoneCount = in.nextInt(); // the amount of zones on the map
int linkCount = in.nextInt();
in.nextLine();
zones = new Zone[zoneCount];
for (int i = 0; i < zoneCount; i++) {
int zoneId = in.nextInt(); // this zone's ID (between 0 and zoneCount-1)
int platinumSource = in.nextInt(); // the amount of Platinum this zone can provide per game turn
in.nextLine();
Zone zone = new Zone(zoneId, platinumSource);
zones[zoneId] = zone;
}
for (int i = 0; i < linkCount; i++) {
int zone1 = in.nextInt();
int zone2 = in.nextInt();
zones[zone1].linkedTo(zone2);
zones[zone2].linkedTo(zone1);
in.nextLine();
}
regions = new ArrayList<Region>();
Map<Integer, Zone> zoneById = newZoneByIdMap();
while (!zoneById.isEmpty()) {
Region region = new Region(regions.size());
region.traverse(zoneById);
regions.add(region);
}
}
//-------------------------------------------------------------------------
// __ _
// /__\ ___ __ _(_) ___ _ __
// / \/// _ \/ _` | |/ _ \| '_ \
// / _ \ __/ (_| | | (_) | | | |
// \/ \_/\___|\__, |_|\___/|_| |_|
// |___/
//-------------------------------------------------------------------------
public static class Region {
private final Integer regionId;
private List<Zone> zones = new ArrayList<Zone>();
private Boolean owned;
private int numberOfPlatinumSources;
public Region(int regionId) {
this.regionId = regionId;
}
public int platinumSources() {
return numberOfPlatinumSources;
}
public int zoneCount() {
return zones.size();
}
public boolean isOwned(int myId) {
if (owned == null) {
owned = true;
for (Zone zone : zones) {
if (zone.ownerId != myId) {
owned = false;
break;
}
}
}
return owned;
}
public void traverse(Map<Integer, Zone> zoneById) {
Zone zone = zoneById.values().iterator().next();
List<Zone> toVisit = new ArrayList<Zone>();
toVisit.add(zone);
while (!toVisit.isEmpty()) {
Zone z = removeLast(toVisit);
for (Integer zId : z.linkedTo) {
Zone linked = zoneById.remove(zId);
if (linked != null)
toVisit.add(linked);
}
z.region = this;
declareZone(z);
}
}
private boolean declareZone(Zone z) {
numberOfPlatinumSources += z.numberOfPlatinumSources;
return zones.add(z);
}
private Zone removeLast(List<Zone> list) {
return list.remove(list.size() - 1);
}
public void invalidate() {
owned = null;
}
public int[] numberOfZoneOwnedByOthers(int myId) {
int nbMine = 0, nbOthers = 0;
for (Zone zone : zones) {
if (zone.ownerId == -1)
continue;
if (zone.ownerId == myId)
nbMine++;
else
nbOthers++;
}
return new int[]{nbMine, nbOthers};
}
}
//-------------------------------------------------------------------------
// _
// /\/\ (_)___ ___
// / \| / __|/ __|
// / /\/\ \ \__ \ (__
// \/ \/_|___/\___|
//-------------------------------------------------------------------------
private static Comparator<? super Order> orderPriorityReverseComparator(final Context ctx) {
return new Comparator<Order>() {
@Override
public int compare(Order z1, Order z2) {
return -Integer.compare(z1.priority(ctx), z2.priority(ctx));
}
};
}
private static Comparator<? super Integer> surroundedByNotOwnedComparator(final Context ctx) {
return new Comparator<Integer>() {
@Override
public int compare(Integer z1, Integer z2) {
int nb1 = countNotOwnedAround(z1);
int nb2 = countNotOwnedAround(z2);
return -Integer.compare(nb1, nb2);
}
private int countNotOwnedAround(Integer zId) {
return ctx.numberOfNotOwnedZoneAround(zId);
}
};
}
private static Comparator<? super Region> regionPlatinumSourceComparator = new Comparator<Region>() {
@Override
public int compare(Region r1, Region r2) {
return -Integer.compare(r1.platinumSources(), r2.platinumSources());
}
};
private static Comparator<? super Zone> zonePlatinumSourceComparator(final Context ctx) {
return new Comparator<Zone>() {
@Override
public int compare(Zone z1, Zone z2) {
int compare = -Integer.compare(z1.numberOfPlatinumSources, z2.numberOfPlatinumSources);
if (compare == 0) {
return -Integer.compare(ctx.numberOfPlatinumSourcesAround(z1),
ctx.numberOfPlatinumSourcesAround(z2));
}
return compare;
}
};
}
protected static <T> T randomlyPickOne(Random random, List<T> elements) {
if (elements.isEmpty())
return null;
int index = random.nextInt(elements.size());
return elements.get(index);
}
private static void display(PrintStream out, List<? extends Displayable> displayables) {
if (displayables.isEmpty())
out.println(Wait);
else {
for (int i = 0; i < displayables.size(); i++) {
Displayable displayable = displayables.get(i);
if (i > 0)
out.print(" ");
out.print(displayable.display());
}
out.println();
}
}
//-------------------------------------------------------------------------
// _____
// / _ / ___ _ __ ___
// \// / / _ \| '_ \ / _ \
// / //\ (_) | | | | __/
// /____/\___/|_| |_|\___|
//-------------------------------------------------------------------------
public static class Zone {
public final Integer zoneId;
public final int numberOfPlatinumSources;
public Region region;
public final List<Integer> linkedTo = new ArrayList<Integer>();
public List<Integer> shuffledLinks;
//
public int ownerId;
public int[] pods = new int[4];
//
private int freeForOther;
public int assignedToOtherZones = 0;
public int purchasedNb = 0;
public List<Integer> assignedToThis = new ArrayList<Integer>();
public Zone(int zoneId, int numberOfPlatinumSources) {
this.zoneId = zoneId;
this.numberOfPlatinumSources = numberOfPlatinumSources;
}
public Integer regionId() {
return region.regionId;
}
public void linkedTo(int otherZoneId) {
linkedTo.add(otherZoneId);
}
public void update(int ownerId, int podsP0, int podsP1, int podsP2, int podsP3) {
this.ownerId = ownerId;
this.pods[0] = podsP0;
this.pods[1] = podsP1;
this.pods[2] = podsP2;
this.pods[3] = podsP3;
}
public int myPods(int myId) {
return pods[myId];
}
public int maxOtherPods(int myId) {
int max = 0;
for (int i = 0; i < 4; i++) {
if (i != myId)
max = Math.max(max, pods[i]);
}
return max;
}
public boolean isSpawnPossible(int myId) {
return ownerId == myId || ownerId == -1;
}
public boolean notOwnedBy(int myId) {
return ownerId != myId;
}
public void clearAssignmentsAndStats(Zone[] zones, int myId) {
purchasedNb = 0;
freeForOther = 0;
assignedToOtherZones = 0;
assignedToThis.clear();
}
public List<Integer> shuffledLinks() {
if (shuffledLinks == null)
shuffledLinks = new ArrayList<Integer>(linkedTo);
Collections.shuffle(shuffledLinks);
return shuffledLinks;
}
@Override
public String toString() {
return "Zone{" +
"zoneId=" + zoneId +
'}';
}
}
//-------------------------------------------------------------------------
// ___ _ _
// / __\___ _ __ | |_ _____ _| |_
// / / / _ \| '_ \| __/ _ \ \/ / __|
// / /__| (_) | | | | || __/> <| |_
// \____/\___/|_| |_|\__\___/_/\_\\__|
//-------------------------------------------------------------------------
public static class Context {
private final int myId;
private final Zone[] zones;
private final Random random;
private final int round;
private final int availableForSpawn;
//
private final int[] consumed;
private final int[] affected;
private int spawnConsumed;
private List<String> spawnReasons = new ArrayList<String>();
public int leroyCount = 2;
public Context(int myId,
Zone[] zones,
Random random,
int availableForSpawn,
int round) {
this.myId = myId;
this.zones = zones;
this.random = random;
this.availableForSpawn = availableForSpawn;
this.round = round;
//
this.consumed = new int[zones.length];
this.affected = new int[zones.length];
}
public Zone zone(int zoneId) {
return zones[zoneId];
}
public int availablePods(int zoneId) {
Zone zone = zones[zoneId];
return zone.myPods(myId) - consumed[zoneId];
}
public int maxOtherPods(int zoneId) {
Zone zone = zones[zoneId];
return zone.maxOtherPods(myId);
}
public Random random() {
return random;
}
public void consume(int zoneId) {
consumed[zoneId]++;
}
public void consumeSpawn(String reason) {
consumeSpawn(1, reason);
}
public void consumeSpawn(int spawned, String reason) {
for (int i = 0; i < spawned; i++)
spawnReasons.add(reason);
spawnConsumed += spawned;
}
public boolean ownedByMe(int zoneId) {
Zone zone = zones[zoneId];
return zone.ownerId == myId;
}
public boolean ownedByMeOrNeutral(int zoneId) {
Zone zone = zones[zoneId];
return zone.ownerId == myId || zone.ownerId == -1;
}
public boolean ownedByMeOrNeutralOrEmpty(int zoneId) {
Zone zone = zones[zoneId];
return zone.ownerId == myId
|| zone.ownerId == -1
|| zone.maxOtherPods(myId) == 0;
}
public int availableForSpawn(int zoneId) {
if (ownedByMeOrNeutral(zoneId))
return availableForSpawn - spawnConsumed;
return 0;
}
public int maxAround(Zone zone) {
int max = 0;
for (Integer zId : zone.linkedTo) {
int nb = zones[zId].maxOtherPods(myId);
if (nb > max)
max = nb;
}
return max;
}
public Set<Integer> searchAllNearestZoneNotMineOrWithEnemies(Zone zone, int radius) {
Path path = new Path(zone.zoneId, notMineOrWithEnemies(zones, myId), acceptAll, radius, zones);
return path.computeAllNextMoves();
}
public Set<Integer> searchAllNearestZoneWithEnemies(Zone zone, int radius) {
Path path = new Path(zone.zoneId, withEnemies(zones, myId), acceptAll, radius, zones);
return path.computeAllNextMoves();
}
public Set<Integer> searchAllNearestUnexploredZone(Zone zone, int radius) {
Path path = new Path(zone.zoneId,
notMineOrWithEnemies(zones, myId),
noEnemyPods(zones, myId),
radius, zones);
List<Integer> found = new ArrayList<Integer>(path.collectAllZoneOfInterest());
if (found.isEmpty())
return Collections.emptySet();
Collections.sort(found, surroundedByNotOwnedComparator(this));
path = new Path(zone.zoneId, isEqual(found.get(0)), noEnemyPods(zones, myId), radius, zones);
path.computeOnePath();
HashSet<Integer> integers = new HashSet<Integer>();
integers.add(path.nextMove());
return integers;
}
public int affectedAt(Zone zone) {
return zone.myPods(myId) + affected[zone.zoneId];
}
public int affectedAt(int zoneId) {
return zones[zoneId].myPods(myId) + affected[zoneId];
}
public void affectsAt(int nb, Zone zone) {
affected[zone.zoneId] += nb;
}
public void affectsAt(int nb, int zoneId) {
affected[zoneId] += nb;
}
public int availableAround(Integer zoneId) {
int availableAround = 0;
for (Integer zId : zones[zoneId].linkedTo) {
availableAround += availablePods(zId);
}
return availableAround;
}
public int numberOfControlledZoneAround(Integer zoneId) {
int nb = 0;
for (Integer zId : zones[zoneId].linkedTo) {
if (availablePods(zId) > 0 || affectedAt(zId) > 0)
nb++;
}
return nb;
}
public boolean isRegionNotInfestedYet(Zone zone) {
if (isInfected(zone.zoneId))
return false; // not not! =>
for (Zone other : zone.region.zones) {
if (isInfected(other.zoneId))
return false;
}
return true;
}
private boolean isInfected(int zId) {
return (affectedAt(zId) > 0 || zones[zId].ownerId == myId || availablePods(zId) > 0);
}
public int regionSize(Zone zone) {
return zone.region.zoneCount();
}
public int numberOfPlatinumSourcesAroundMinusEnemies(Zone zone) {
int nb = 0;
for (Integer zId : zones[zone.zoneId].linkedTo) {
nb += zones[zId].numberOfPlatinumSources - zones[zId].maxOtherPods(myId);
}
return nb;
}
public int numberOfPlatinumSourcesAround(Zone zone) {
int nb = 0;
for (Integer zId : zones[zone.zoneId].linkedTo) {
nb += zones[zId].numberOfPlatinumSources;
}
return nb;
}
public int numberOfOwnedZonesAround(Integer zoneId) {
int nb = 0;
for (Integer zId : zones[zoneId].linkedTo) {
if (zones[zId].ownerId == myId && zones[zId].maxOtherPods(myId) == 0)
nb++;
}
return nb;
}
public int numberOfEnemyZonesAround(Integer zoneId) {
int nb = 0;
for (Integer zId : zones[zoneId].linkedTo) {
int ownerId = zones[zId].ownerId;
if (ownerId != myId && ownerId != -1)
nb++;
}
return nb;
}
public int numberOfNotOwnedZoneAround(Integer zoneId) {
int nb = 0;
for (Integer zId : zones[zoneId].linkedTo) {
int ownerId = zones[zId].ownerId;
if (ownerId != myId)
nb++;
}
return nb;
}
public Integer selectLinkWithTheHighestNumberOfPodsAvailable(Integer zoneId) {
Integer selected = null;
int maxAvailable = 0;
for (Integer zId : zones[zoneId].linkedTo) {
int available = availablePods(zId);
if (available > maxAvailable)
selected = zId;
}
return selected;
}
}
//-------------------------------------------------------------------------
// ___ _
// /___\_ __ __| | ___ _ __
// // // '__/ _` |/ _ \ '__|
// / \_//| | | (_| | __/ |
// \___/ |_| \__,_|\___|_|
//-------------------------------------------------------------------------
public interface Order {
int priority(Context context);
boolean evaluate(Context context);
void execute(Context context);
}
//-------------------------------------------------------------------------
// ___ _ ____
// /___\_ __ __| | ___ _ __ / / _\_ __ __ ___ ___ __
// // // '__/ _` |/ _ \ '__/ /\ \| '_ \ / _` \ \ /\ / / '_ \
// / \_//| | | (_| | __/ | / / _\ \ |_) | (_| |\ V V /| | | |
// \___/ |_| \__,_|\___|_|/_/ \__/ .__/ \__,_| \_/\_/ |_| |_|
// |_|
//-------------------------------------------------------------------------
public static class Spawn implements Order {
private final Zone zone;
private final int myId;
private int spawned;
private int lastPriority;
public Spawn(Zone zone, int myId) {
this.zone = zone;
this.myId = myId;
}
@Override
public int priority(Context ctx) {
int weight = 0;
if (zone.notOwnedBy(myId) && ctx.affectedAt(zone) == 0) {
weight += 2 * (zone.numberOfPlatinumSources + 1);
weight += ctx.numberOfPlatinumSourcesAroundMinusEnemies(zone);
}
weight += 2 * Math.min(2, ctx.numberOfEnemyZonesAround(zone.zoneId));
weight += Math.min(2, ctx.numberOfOwnedZonesAround(zone.zoneId));
weight += (ctx.isRegionNotInfestedYet(zone) && ctx.regionSize(zone) > 10) ? 30 : 0;
int[] ints = zone.region.numberOfZoneOwnedByOthers(ctx.myId);
weight += (ints[1] - ints[0]) / (ints[1] + 1);
lastPriority = 80 - weight;
return lastPriority;
}
@Override
public boolean evaluate(Context context) {
spawned = 0;
int spawn = context.availableForSpawn(zone.zoneId);
if (spawn == 0)
return false;
int maxAround = context.maxAround(zone);
if (maxAround == 0) {
spawned = 1;
} else {
int min = Math.max(1, maxAround - context.availablePods(zone.zoneId) + 1);
spawned = Math.min(min, spawn);
}
if (spawned > 0) {
context.consumeSpawn(spawned, getClass().getSimpleName() + "::" + zone.zoneId);
context.affectsAt(spawned, zone);
}
return true;
}
@Override
public void execute(Context context) {
zone.purchasedNb += spawned;
}
public String toString() {
return "P" + lastPriority + "/Spawn#" + zone.zoneId;
}
}
//-------------------------------------------------------------------------
// ___ _ ____ _
// /___\_ __ __| | ___ _ __ / / _\_ _ _ __ _ __ ___ _ __| |_
// // // '__/ _` |/ _ \ '__/ /\ \| | | | '_ \| '_ \ / _ \| '__| __|
// / \_//| | | (_| | __/ | / / _\ \ |_| | |_) | |_) | (_) | | | |_
// \___/ |_| \__,_|\___|_|/_/ \__/\__,_| .__/| .__/ \___/|_| \__|
// |_| |_|
//-------------------------------------------------------------------------
public static class Support implements Order {
private final Zone zone;
private List<Integer> dst = new ArrayList<Integer>();
private int lastPriority = 90;
public Support(Zone zone) {
this.zone = zone;
}
@Override
public int priority(Context context) {
return lastPriority;
}
@Override
public boolean evaluate(Context context) {
dst.clear();
int myPods = context.availablePods(zone.zoneId);
if (myPods == 0)
return false;
for (Integer zId : zone.linkedTo) {
if (context.ownedByMeOrNeutral(zId)) {
dst.add(zId);
}
}
// at least one neighbor to move to
if (dst.isEmpty())
return false;
List<Integer> affected = new ArrayList<Integer>();
// --
Set<Integer> nextMovesToNearest;
if(context.leroyCount > 0) {
nextMovesToNearest = context.searchAllNearestUnexploredZone(zone, 8);
if (!nextMovesToNearest.isEmpty()) {
int p = myPods;
myPods = affect(context, myPods, context.leroyCount, affected, nextMovesToNearest);
context.leroyCount = context.leroyCount - (p - myPods);
}
}
nextMovesToNearest = context.searchAllNearestZoneWithEnemies(zone, 8);
if (!nextMovesToNearest.isEmpty()) {
myPods = affect(context, myPods, Integer.MAX_VALUE, affected, nextMovesToNearest);
} else {
nextMovesToNearest = context.searchAllNearestZoneNotMineOrWithEnemies(zone, 8);
if (!nextMovesToNearest.isEmpty()) {
myPods = affect(context, myPods, Integer.MAX_VALUE, affected, nextMovesToNearest);
}
}
while (myPods > 0) {
Integer zId = randomlyPickOne(context.random(), dst);
affected.add(zId);
context.affectsAt(1, zId);
myPods--;
}
dst = (affected);
return true;
}
private int affect(Context context, int myPods, int maxToSpread, List<Integer> affected, Set<Integer> nextMovesToNearest) {
while (maxToSpread > 0 && myPods > 0) {
for (Integer zId : nextMovesToNearest) {
affected.add(zId);
context.affectsAt(1, zId);
myPods--;
maxToSpread--;
if (maxToSpread == 0 || myPods == 0)
return myPods;
}
}
return myPods;
}
@Override
public void execute(Context context) {
for (Integer zId : dst) {
context.zone(zId).assignedToThis.add(zone.zoneId);
}
}
public String toString() {
return "P" + lastPriority + "/Support#" + zone.zoneId;
}
}
//-------------------------------------------------------------------------
// ___ _ _____
// /___\_ __ __| | ___ _ __ / / __\___ _ __ __ _ _ _ ___ _ __
// // // '__/ _` |/ _ \ '__/ / / / _ \| '_ \ / _` | | | |/ _ \ '__|
// / \_//| | | (_| | __/ | / / /__| (_) | | | | (_| | |_| | __/ |
// \___/ |_| \__,_|\___|_|/_/\____/\___/|_| |_|\__, |\__,_|\___|_|
// |_|
//-------------------------------------------------------------------------
public static class Conquer implements Order {
private final Zone dst;
private final int maxOtherPods;
private final List<Integer> supportedBy = new ArrayList<Integer>();
private int lastPriority;
public Conquer(Zone dst, int maxOtherPods) {
this.dst = dst;
this.maxOtherPods = maxOtherPods;
}
@Override
public int priority(Context context) {
lastPriority = (6 - dst.numberOfPlatinumSources) + 4 - Math.min(4, maxOtherPods);
return lastPriority;
}
@Override
public boolean evaluate(Context context) {
supportedBy.clear();
int myPods = context.availablePods(dst.zoneId);
int otherPods = context.availablePods(dst.zoneId);
int availableAround = context.availableAround(dst.zoneId);
if (// myPods + availableAround < 4 && // otherwise keep the zone!
myPods + availableAround <= otherPods) // or conquer it :)
return false;
int required = otherPods - myPods + 1;
int toConsume = Math.min(otherPods + 1, myPods);
while (toConsume > 0) {
context.consume(dst.zoneId);
context.affectsAt(1, dst.zoneId);
required--;
toConsume--;
}
while (required > 0) {
Integer zId = context.selectLinkWithTheHighestNumberOfPodsAvailable(dst.zoneId);
if (zId != null && context.availablePods(zId) > 0) {
supportedBy.add(zId);
context.consume(zId);
context.affectsAt(1, dst);
required--;
}
}
return true;
}
@Override
public void execute(Context context) {
dst.assignedToThis.addAll(supportedBy);
}
public String toString() {
return "P" + lastPriority + "/Conquer#" + dst.zoneId;
}
}
//-------------------------------------------------------------------------
// ___ _ _____ _
// /___\_ __ __| | ___ _ __ / / __\ | ___ ___
// // // '__/ _` |/ _ \ '__/ / _\ | |/ _ \/ _ \
// / \_//| | | (_| | __/ | / / / | | __/ __/
// \___/ |_| \__,_|\___|_|/_/\/ |_|\___|\___|
//-------------------------------------------------------------------------
public static class Flee implements Order {
private final Zone zone;
private int lastPriority = 100;
public Flee(Zone zone) {
this.zone = zone;
}
@Override
public int priority(Context context) {
return lastPriority;
}
@Override
public boolean evaluate(Context context) {
for (Integer zId : zone.linkedTo) {
if (context.ownedByMeOrNeutral(zId))
return true;
}
return false;
}
@Override
public void execute(Context context) {
Integer thisZoneId = zone.zoneId;
int myPods = context.availablePods(thisZoneId);
while (myPods > 0) {
Integer zId = randomlyPickOne(context.random(), zone.linkedTo);
context.consume(thisZoneId);
context.affectsAt(1, zId);
context.zone(zId).assignedToThis.add(thisZoneId);
myPods--;
}
}
public String toString() {
return "P" + lastPriority + "/Flee#" + zone.zoneId;
}
}
//-------------------------------------------------------------------------
// ___ _ _____ _ _ _
// /___\_ __ __| | ___ _ __ / / __(_) __ _| |__ | |_
// // // '__/ _` |/ _ \ '__/ / _\ | |/ _` | '_ \| __|
// / \_//| | | (_| | __/ | / / / | | (_| | | | | |_
// \___/ |_| \__,_|\___|_|/_/\/ |_|\__, |_| |_|\__|
// |___/
//-------------------------------------------------------------------------
public static class Fight implements Order {
private final Zone zone;
private final List<Integer> supportedBy = new ArrayList<Integer>();
private int purchaseNb = 0;
private int lastPriority;
public Fight(Zone zone) {
this.zone = zone;
}
@Override
public int priority(Context context) {
this.lastPriority = (6 - zone.numberOfPlatinumSources);
return lastPriority;
}
@Override
public boolean evaluate(Context context) {
supportedBy.clear();
purchaseNb = 0;
int myPods = context.availablePods(zone.zoneId);
int otherPods = context.maxOtherPods(zone.zoneId);
int availableAround = context.availableAround(zone.zoneId);
int availableSpawn = context.availableForSpawn(zone.zoneId);
if (myPods + availableAround + availableSpawn <= otherPods) // (1)
return false;
int required = otherPods - myPods + 1;
while (required > 0) {
Integer zId = randomlyPickOne(context.random(), zone.linkedTo);
if (zId != null && context.availablePods(zId) > 0) {
supportedBy.add(zId);
context.consume(zId);
context.affectsAt(1, zone);
required--;
}
// no more available around;
// one will rely on spawn afterwards
if (required > 0 && context.availableAround(zone.zoneId) == 0)
break;
}
// availableSpawn should be valid at this point due to equation (1)
while (required > 0) {
purchaseNb++;
context.consumeSpawn(getClass().getSimpleName() + "::" + zone.zoneId);
context.affectsAt(1, zone);
required--;
}
return true;
}
@Override
public void execute(Context context) {
zone.purchasedNb += purchaseNb;
zone.assignedToThis.addAll(supportedBy);
}
public String toString() {
return "P" + lastPriority + "/Fight#" + zone.zoneId;
}
}
//-------------------------------------------------------------------------
// ___ ___ _
// / _ \__ _ _ __ ___ ___ /___\_ __ __| | ___ _ __
// / /_\/ _` | '_ ` _ \ / _ \_____ // // '__/ _` |/ _ \ '__|
// / /_\\ (_| | | | | | | __/_____/ \_//| | | (_| | __/ |
// \____/\__,_|_| |_| |_|\___| \___/ |_| \__,_|\___|_|
//-------------------------------------------------------------------------
public static final String Wait = "WAIT";
public interface Displayable {
String display();
}
public static class Purchase implements Displayable {
public int nb;
public int zoneTo;
public Purchase(int nb, int zoneTo) {
this.nb = nb;
this.zoneTo = zoneTo;
}
@Override
public String display() {
return nb + " " + zoneTo;
}
}
public static class Move implements Displayable {
public int nb;
public int zoneFrom;
public int zoneTo;
public Move(int zoneFrom, int zoneTo) {
this.zoneFrom = zoneFrom;
this.zoneTo = zoneTo;
}
@Override
public String display() {
return nb + " " + zoneFrom + " " + zoneTo;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Move move = (Move) o;
return zoneFrom == move.zoneFrom && zoneTo == move.zoneTo;
}
@Override
public int hashCode() {
return 31 * zoneFrom + zoneTo;
}
}
//-------------------------------------------
// ___ _ _ _
// / _ \_ __ ___ __| (_) ___ __ _| |_ ___
// / /_)/ '__/ _ \/ _` | |/ __/ _` | __/ _ \
// / ___/| | | __/ (_| | | (_| (_| | || __/
// \/ |_| \___|\__,_|_|\___\__,_|\__\___|
//-------------------------------------------
public interface Predicate {
boolean test(Integer zId);
}
public static Predicate isEqual(final Integer target) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
return zId.equals(target);
}
};
}
public static Predicate emptyButNotMine(final Zone[] zones, final int myId) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
return zones[zId].ownerId != myId && zones[zId].maxOtherPods(myId) == 0;
}
};
}
public static Predicate notMine(final Zone[] zones, final int myId) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
return zones[zId].ownerId != myId;
}
};
}
public static Predicate notMineOrWithEnemies(final Zone[] zones, final int myId) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
return zones[zId].ownerId != myId || zones[zId].maxOtherPods(myId) > 0;
}
};
}
public static Predicate acceptAll = new Predicate() {
@Override
public boolean test(Integer zId) {
return true;
}
};
public static Predicate noEnemyPods(final Zone[] zones, final int myId) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
return zones[zId].maxOtherPods(myId) == 0;
}
};
}
public static Predicate withEnemies(final Zone[] zones, final int myId) {
return new Predicate() {
@Override
public boolean test(Integer zId) {
Zone zone = zones[zId];
return (zone.ownerId != myId && zone.ownerId != -1) || zone.maxOtherPods(myId) > 0;
}
};
}
//-------------------------------------------
// _ _
// _ __ __ _| |_| |__
// | '_ \ / _` | __| '_ \
// | |_) | (_| | |_| | | |
// | .__/ \__,_|\__|_| |_|
// |_|
//-------------------------------------------
public static class Path {
public final int start;
public final Predicate end;
private final Predicate zoneAccepted;
private final int ringLimit;
public final Player.Zone[] zones;
private List<Integer> onePath;
public Path(int start, Predicate end, Predicate zoneAccepted, int ringLimit, Zone[] zones) {
this.start = start;
this.end = end;
this.zoneAccepted = zoneAccepted;
this.ringLimit = ringLimit;
this.zones = zones;
}
public void computeOnePath() {
Set<Integer> ringP = new HashSet<Integer>();
Set<Integer> ring0 = new HashSet<Integer>();
ring0.add(start);
List<Set<Integer>> alreadyTraversed = new ArrayList<Set<Integer>>();
while (!ring0.isEmpty()) {
Set<Integer> ringN = new HashSet<Integer>();
for (Integer zId : ring0) {
for (Integer link : zones[zId].linkedTo) {
if (!zoneAccepted.test(link))
continue;
if (end.test(link)) {
onePath = extractPath(link, zId, alreadyTraversed);
return;
}
if (ringP.contains(link) || ring0.contains(link))
continue;
ringN.add(link);
}
}
alreadyTraversed.add(ringN);
ringP = ring0;
ring0 = ringN;
if (ringLimit > 0 && alreadyTraversed.size() > ringLimit)
return;
}
}
private List<Integer> extractPath(Integer end, Integer zId, List<Set<Integer>> alreadyTraversed) {
List<Integer> path = new ArrayList<Integer>();
path.add(end);
path.add(zId);
if (zId != start) {
Integer cId = zId;
ringLbl:
for (int i = alreadyTraversed.size() - 2; i >= 0; i--) {
Set<Integer> ring = alreadyTraversed.get(i);
for (Integer link : zones[cId].shuffledLinks()) {
if (ring.contains(link)) {
path.add(link);
cId = link;
continue ringLbl;
}
}
}
path.add(start);
}
return path;
}
public List<Integer> getOnePath() {
return onePath;
}
public Integer nextMove() {
return nextMove(onePath);
}
private static Integer nextMove(List<Integer> path) {
if (path == null)
return null;
if (path.size() >= 2)
return path.get(path.size() - 2);
return path.get(path.size() - 1);
}
public Set<Integer> collectAllZoneOfInterest() {
Set<Integer> ringP = new HashSet<Integer>();
Set<Integer> ring0 = new HashSet<Integer>();
ring0.add(start);
Set<Integer> reachables = new HashSet<Integer>();
List<Set<Integer>> alreadyTraversed = new ArrayList<Set<Integer>>();
while (!ring0.isEmpty()) {
Set<Integer> ringN = new HashSet<Integer>();
for (Integer zId : ring0) {
for (Integer link : zones[zId].linkedTo) {
if (!zoneAccepted.test(link))
continue;
if (ringP.contains(link) || ring0.contains(link))
continue;
if (end.test(link)) {
reachables.add(link);
}
ringN.add(link);
}
}
alreadyTraversed.add(ringN);
ringP = ring0;
ring0 = ringN;
if (ringLimit > 0 && alreadyTraversed.size() > ringLimit)
return reachables;
}
return reachables;
}
public Set<Integer> computeAllNextMoves() {
Set<Integer> ringP = new HashSet<Integer>();
Set<Integer> ring0 = new HashSet<Integer>();
ring0.add(start);
Set<Integer> nextMoves = new HashSet<Integer>();
List<Set<Integer>> alreadyTraversed = new ArrayList<Set<Integer>>();
while (!ring0.isEmpty()) {
Set<Integer> ringN = new HashSet<Integer>();
for (Integer zId : ring0) {
for (Integer link : zones[zId].linkedTo) {
if (!zoneAccepted.test(link))
continue;
if (ringP.contains(link) || ring0.contains(link))
continue;
if (end.test(link)) {
List<Integer> path = extractPath(link, zId, alreadyTraversed);
Integer nextMove = nextMove(path);
if (nextMove != null) {
nextMoves.add(nextMove);
}
}
ringN.add(link);
}
}
if (!nextMoves.isEmpty()) {
return nextMoves;
}
alreadyTraversed.add(ringN);
ringP = ring0;
ring0 = ringN;
if (ringLimit > 0 && alreadyTraversed.size() > ringLimit)
return nextMoves;
}
return nextMoves;
}
}
}
@Arnauld
Copy link
Author

Arnauld commented Jun 3, 2021

...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment