Skip to content

Commit 882b897

Browse files
committed
Base version of game written
1 parent 6fadcce commit 882b897

File tree

1 file changed

+358
-0
lines changed

1 file changed

+358
-0
lines changed
Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
package main.java.codingame;
2+
3+
import java.util.*;
4+
5+
public class Pirates {
6+
7+
public static final String SHIP = "SHIP";
8+
public static final String BARREL = "BARREL";
9+
public static final String FIRE = "FIRE ";
10+
public static final String MOVE = "MOVE ";
11+
public static final String SLOWER = "SLOWER";
12+
public static final String WAIT = "WAIT";
13+
public static final String FASTER = "FASTER";
14+
public static final String MINE = "MINE";
15+
public static final String CANNONBALL = "CANNONBALL";
16+
public static final String STARBOARD = "STARBOARD";
17+
public static final String PORT = "PORT";
18+
private static final Random random = new Random();
19+
20+
public static void main(String args[]) {
21+
final Scanner in = new Scanner(System.in);
22+
final boolean canFire[] = new boolean[100];
23+
for (int i = 0; i < canFire.length; i++) {
24+
canFire[i] = true;
25+
}
26+
while (true) {
27+
final int myShipCount = in.nextInt();
28+
final int entityCount = in.nextInt();
29+
final List<Ship> myShips = new ArrayList<>();
30+
final List<Ship> enemyShips = new ArrayList<>();
31+
final List<Barrel> barrels = new ArrayList<>();
32+
final List<Mine> mines = new ArrayList<>();
33+
final List<CannonBall> cannonBalls = new ArrayList<>();
34+
for (int i = 0; i < entityCount; i++) {
35+
final int entityId = in.nextInt();
36+
final String entityType = in.next();
37+
final int x = in.nextInt();
38+
final int y = in.nextInt();
39+
final int arg1 = in.nextInt();
40+
final int arg2 = in.nextInt();
41+
final int arg3 = in.nextInt();
42+
final int arg4 = in.nextInt();
43+
if (entityType.equals(SHIP)) {
44+
if (arg4 == 1) {
45+
myShips.add(new Ship(arg1, arg2, arg3, arg4, x, y, entityId));
46+
} else {
47+
enemyShips.add(new Ship(arg1, arg2, arg3, arg4, x, y, entityId));
48+
}
49+
} else if (entityType.equals(BARREL)) {
50+
barrels.add(new Barrel(arg1, x, y, entityId));
51+
} else if (entityType.equals(MINE)) {
52+
mines.add(new Mine(x, y, entityId));
53+
} else if (entityType.equals(CANNONBALL)) {
54+
cannonBalls.add(new CannonBall(x, y, arg1, arg2, entityId));
55+
} else {
56+
throw new RuntimeException();
57+
}
58+
}
59+
final Ship myBestShip = myShips.stream().max(Comparator.comparingInt(o -> o.rum)).orElseThrow(RuntimeException::new);
60+
final Ship opponentBestShip = enemyShips.stream().max(Comparator.comparingInt(o -> o.rum)).orElseThrow(RuntimeException::new);
61+
for (final Ship myShip : myShips) {
62+
Ship nearestEnemy = enemyShips.get(0);
63+
final boolean canFireNow = canFire[myShip.id];
64+
for (final Ship enemyShip : enemyShips) {
65+
if (myShip.calculateDistance(enemyShip) < myShip.calculateDistance(nearestEnemy)) {
66+
nearestEnemy = enemyShip;
67+
}
68+
}
69+
final CannonBall incomingCannonBall = myShip.willHitOnTime(cannonBalls);
70+
if (incomingCannonBall != null) {
71+
System.err.println("Gonna be hit with cannons!" + incomingCannonBall.targetX + " " + incomingCannonBall.targetY);
72+
if (myShip.speed > 0) {
73+
System.out.println(Math.random() > 0.5 ? STARBOARD : PORT);
74+
} else {
75+
System.out.println(FASTER);
76+
}
77+
} else {
78+
final Mine willCollide = myShip.willCollide(mines);
79+
if (willCollide != null && myShip.calculateDistance(willCollide) < Ship.MAX_MINE_DISTANCE) {
80+
System.err.println("Gonna hit a mine! " + willCollide);
81+
if (myShip.speed > 0) {
82+
System.out.println(Math.random() > 0.5 ? STARBOARD : PORT);
83+
} else {
84+
System.out.println(FASTER);
85+
}
86+
} else if (myShip.calculateDistance(nearestEnemy) <= 6) {
87+
final Coordinate shot = myShip.shoot(nearestEnemy);
88+
if (shot.x != -1 && canFireNow) {
89+
System.out.println(FIRE + shot.x + " " + shot.y);
90+
canFire[myShip.id] = false;
91+
} else {
92+
System.err.println("Weird..." + myShip.calculateDistance(nearestEnemy));
93+
if (barrels.isEmpty()) {
94+
System.out.println(MOVE + opponentBestShip.x + " " + opponentBestShip.y);
95+
} else {
96+
final Barrel nearest = findTheNearestBarrel(barrels, myShip);
97+
System.out.println(MOVE + nearest.x + " " + nearest.y);
98+
}
99+
}
100+
} else if (!barrels.isEmpty()) {
101+
final Barrel nearest = findTheNearestBarrel(barrels, myShip);
102+
if (myShip.rum < 87 || myShip.calculateDistance(nearest) > 5) {
103+
System.out.println(MOVE + nearest.x + " " + nearest.y);
104+
} else {
105+
System.out.println(SLOWER);
106+
}
107+
} else if (barrels.isEmpty() && myShip.equals(myBestShip) && myShip.rum > opponentBestShip.rum) {
108+
if (myShip.calculateDistance(nearestEnemy) > 11) {
109+
final Mine nearestMine = findTheNearestMine(mines, myShip);
110+
if (canFireNow && nearestMine != null && myShip.calculateDistance(nearestMine) < 10) {
111+
System.out.println(FIRE + nearestMine.x + " " + nearestMine.y);
112+
canFire[myShip.id] = false;
113+
} else if (myShip.speed != 0) {
114+
System.out.println(SLOWER);
115+
} else {
116+
System.out.println(WAIT);
117+
}
118+
} else {
119+
final Coordinate run = evade(myShips, myBestShip, opponentBestShip, myShip, nearestEnemy);
120+
if (run.isOutSideMap()) {
121+
System.out.println(MOVE + random.nextInt(21) + " " + random.nextInt(21));
122+
} else {
123+
if (myShip.calculateDistance(nearestEnemy) > 5 && myShip.speed < 2) {
124+
System.out.println(FASTER);
125+
} else {
126+
System.out.println(MOVE + run.x + " " + run.y);
127+
}
128+
}
129+
}
130+
} else if (myShip.calculateDistance(nearestEnemy) <= 9) {
131+
final Coordinate shot = myShip.shoot(nearestEnemy);
132+
if (shot.x != -1 && canFireNow) {
133+
System.out.println(FIRE + shot.x + " " + shot.y);
134+
canFire[myShip.id] = false;
135+
} else {
136+
System.out.println(MOVE + opponentBestShip.x + " " + opponentBestShip.y);
137+
}
138+
} else {
139+
//pursue
140+
System.out.println(MOVE + opponentBestShip.x + " " + opponentBestShip.y);
141+
}
142+
}
143+
if (!canFireNow) {
144+
canFire[myShip.id] = true;
145+
}
146+
// System.err.println("Keep firing!");
147+
}
148+
}
149+
}
150+
151+
private static Mine findTheNearestMine(final List<Mine> mines, final Ship myShip) {
152+
return mines.stream().max(Comparator.comparingInt(o -> o.calculateDistance(myShip))).orElse(null);
153+
}
154+
155+
private static Coordinate evade(List<Ship> myShips, Ship myBestShip, Ship opponentBestShip, Ship myShip, Ship nearestEnemy) {
156+
int deltaX = nearestEnemy.x > myShip.x ? -5 : 5;
157+
int deltaY = nearestEnemy.y > myShip.y ? -5 : 5;
158+
if (myShips.size() == 1 && myBestShip.rum < opponentBestShip.rum) {
159+
deltaX = -deltaX;
160+
deltaY = -deltaY;
161+
}
162+
return new Coordinate(myShip.x + deltaX, myShip.y + deltaY);
163+
}
164+
165+
private static Barrel findTheNearestBarrel(List<Barrel> barrels, Ship myShip) {
166+
Barrel nearest = barrels.get(0);
167+
for (final Barrel barrel : barrels) {
168+
if (myShip.calculateDistance(barrel) * Math.sqrt(Math.sqrt(barrel.rum)) < myShip.calculateDistance(nearest) * Math.sqrt(Math.sqrt(nearest.rum))) {
169+
nearest = barrel;
170+
}
171+
}
172+
return nearest;
173+
}
174+
}
175+
176+
class Coordinate {
177+
public static final int WIDTH = 23;
178+
public static final int HEIGHT = 21;
179+
int x, y;
180+
181+
public Coordinate(int x, int y) {
182+
this.x = x;
183+
this.y = y;
184+
}
185+
186+
@Override
187+
public boolean equals(Object o) {
188+
if (this == o) return true;
189+
if (o == null || getClass() != o.getClass()) return false;
190+
Coordinate that = (Coordinate) o;
191+
return x == that.x && y == that.y;
192+
}
193+
194+
@Override
195+
public int hashCode() {
196+
int result = x;
197+
result = 31 * result + y;
198+
return result;
199+
}
200+
201+
@Override
202+
public String toString() {
203+
return "Coordinate{" +
204+
"x=" + x +
205+
", y=" + y +
206+
'}';
207+
}
208+
209+
public int calculateDistance(final Coordinate coordinate) {
210+
final int x1 = y - (x + (x & 1)) / 2, z1 = x, y1 = -x1 - z1;
211+
final int x2 = coordinate.y - (coordinate.x + (coordinate.x & 1)) / 2, z2 = coordinate.x, y2 = -x2 - z2;
212+
return (Math.abs(x1 - x2) + Math.abs(y1 - y2) + Math.abs(z1 - z2)) >> 1;
213+
}
214+
215+
public boolean isOutSideMap() {
216+
return x >= HEIGHT || x < 0 || y >= WIDTH || y < 0;
217+
}
218+
}
219+
220+
class Entity extends Coordinate {
221+
222+
final int id;
223+
224+
public Entity(int id, int x, int y) {
225+
super(x, y);
226+
this.id = id;
227+
}
228+
229+
}
230+
231+
class CannonBall extends Entity {
232+
final int targetX;
233+
final int targetY;
234+
final int firedBy;
235+
int turnsToHitTarget;
236+
237+
public CannonBall(final int x, final int y, final int firedBy, final int turnsToHitTarget, int id) {
238+
//todo: set the x and y correctly, if required
239+
super(id, -1, -1);
240+
this.targetX = x;
241+
this.targetY = y;
242+
this.firedBy = firedBy;
243+
this.turnsToHitTarget = turnsToHitTarget;
244+
}
245+
246+
public final static int findTimeToReach(final Coordinate currentPosition, final Coordinate target) {
247+
return (int) (Math.round(1 + (currentPosition.calculateDistance(target)) / 3.0));
248+
}
249+
}
250+
251+
class Barrel extends Entity {
252+
final int rum;
253+
254+
public Barrel(final int rum, final int x, final int y, int id) {
255+
super(id, x, y);
256+
this.rum = rum;
257+
}
258+
}
259+
260+
class Ship extends Entity {
261+
public static final int MAX_MINE_DISTANCE = 5;
262+
public static final double MAX_CANNON_TIME = 4;
263+
int rotation;
264+
int speed;
265+
int rum;
266+
final int player;
267+
private static final int oddMovement[][] = new int[][]{{1, 0}, {1, -1}, {0, -1}, {-1, 0}, {0, 1}, {1, 1}};
268+
private static final int evenMovement[][] = new int[][]{{1, 0}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}};
269+
private static final int movement[][] = new int[][]{{2, 0}, {1, -2}, {-1, -2}, {-2, 0}, {-1, 2}, {1, 2}};
270+
271+
public Ship(final int rotation, final int speed, final int rum, final int player, final int x, final int y, int id) {
272+
super(id, x, y);
273+
this.rotation = rotation;
274+
this.speed = speed;
275+
this.rum = rum;
276+
this.player = player;
277+
}
278+
279+
public Coordinate shoot(final Ship ship) {
280+
if (ship.player == player) {
281+
throw new RuntimeException("Don't fire at friendlies, retard!");
282+
} else {
283+
for (int time = 0; time < 4; time++) {
284+
final int predictedX = ship.x + (time * ship.speed * movement[ship.rotation][0]) / 2;
285+
final int predictedY = ship.y + (time * ship.speed * movement[ship.rotation][1]) / 2;
286+
final Coordinate prediction = new Coordinate(predictedX, predictedY);
287+
final int movement[] = x % 2 == 0 ? evenMovement[rotation] : oddMovement[rotation];
288+
if (calculateDistance(prediction) <= 10 && CannonBall.findTimeToReach(new Coordinate(x + movement[0], y + movement[1]), prediction) == time) {
289+
return prediction;
290+
}
291+
}
292+
return new Coordinate(-1, -1);
293+
}
294+
}
295+
296+
public int slowDown() {
297+
if (speed > 0) {
298+
speed--;
299+
}
300+
return speed;
301+
}
302+
303+
public Mine willCollide(final List<Mine> mines) {
304+
if (mines.isEmpty()) {
305+
return null;
306+
}
307+
Coordinate current = this;
308+
int rumOnTheWay = 0;
309+
for (int i = 0; i <= MAX_MINE_DISTANCE; i++) {
310+
if (current instanceof Barrel) {
311+
rumOnTheWay += ((Barrel) current).rum;
312+
}
313+
for (final Mine mine : mines) {
314+
if (isAHit(current, mine, rotation)) {
315+
return !(rumOnTheWay > 0 && i >= MAX_MINE_DISTANCE - 1) ? mine : null;
316+
}
317+
}
318+
final int[] movement = current.x % 2 == 0 ? evenMovement[rotation] : oddMovement[rotation];
319+
current = new Coordinate(current.x + speed * movement[0], current.y + speed * movement[1]);
320+
}
321+
return null;
322+
}
323+
324+
private boolean isAHit(final Coordinate current, final Coordinate bomb, final int rotation) {
325+
final int[] front = current.x % 2 == 0 ? evenMovement[rotation] : oddMovement[rotation];
326+
int halfway = (rotation + 3) % 6;
327+
final int[] back = current.x % 2 == 0 ? evenMovement[halfway] : oddMovement[halfway];
328+
return current.equals(bomb) || bomb.equals(new Coordinate(current.x + front[0], current.y + front[1])) || bomb.equals(new Coordinate(current.x + back[0], current.y + back[1]));
329+
}
330+
331+
public CannonBall willHitOnTime(final List<CannonBall> cannonBalls) {
332+
if (cannonBalls.isEmpty()) {
333+
return null;
334+
}
335+
Coordinate current = this;
336+
int rumOnTheWay = 0;
337+
for (int i = 0; i <= MAX_CANNON_TIME; i++) {
338+
if (current instanceof Barrel) {
339+
rumOnTheWay += ((Barrel) current).rum;
340+
}
341+
for (final CannonBall cannonBall : cannonBalls) {
342+
if (cannonBall.turnsToHitTarget == i + 1 && isAHit(current, new Coordinate(cannonBall.targetX, cannonBall.targetY), rotation)) {
343+
return !(rumOnTheWay > 0 && i >= MAX_CANNON_TIME - 1) ? cannonBall : null;
344+
}
345+
}
346+
final int[] movement = current.x % 2 == 0 ? evenMovement[rotation] : oddMovement[rotation];
347+
current = new Coordinate(current.x + speed * movement[0], current.y + speed * movement[1]);
348+
}
349+
return null;
350+
}
351+
}
352+
353+
class Mine extends Entity {
354+
355+
public Mine(int x, int y, int id) {
356+
super(id, x, y);
357+
}
358+
}

0 commit comments

Comments
 (0)