Skip to content

Commit a4c981c

Browse files
add KillingZombies solution
1 parent a9911db commit a4c981c

File tree

2 files changed

+201
-0
lines changed

2 files changed

+201
-0
lines changed
File renamed without changes.

veryhard400/KillingZombies.java

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package veryhard400;
2+
3+
import java.util.*;
4+
5+
public class KillingZombies {
6+
char turnClockwise(char c) {
7+
if (c == 'N')
8+
return 'E';
9+
else if (c == 'E')
10+
return 'S';
11+
else if (c == 'S')
12+
return 'W';
13+
else if (c == 'W')
14+
return 'N';
15+
16+
return c;
17+
}
18+
19+
class Zombie {
20+
int id;
21+
int x, y;
22+
char direction;
23+
24+
public Zombie(int id, int x, int y, char direction) {
25+
this.id = id;
26+
this.x = x;
27+
this.y = y;
28+
this.direction = direction;
29+
}
30+
31+
@Override
32+
public boolean equals(Object o) {
33+
if (this == o)
34+
return true;
35+
if (o == null || getClass() != o.getClass())
36+
return false;
37+
Zombie zombie = (Zombie) o;
38+
return x == zombie.x && y == zombie.y && direction == zombie.direction;
39+
}
40+
41+
@Override
42+
public int hashCode() {
43+
return Objects.hash(x, y, direction);
44+
}
45+
}
46+
47+
class State {
48+
int x, y;
49+
List<Zombie> zombies;
50+
int mask;
51+
52+
public State(int x, int y, List<Zombie> zombies, int mask) {
53+
this.x = x;
54+
this.y = y;
55+
this.zombies = zombies;
56+
this.mask = mask;
57+
}
58+
59+
@Override
60+
public boolean equals(Object o) {
61+
if (this == o)
62+
return true;
63+
if (o == null || getClass() != o.getClass())
64+
return false;
65+
State state = (State) o;
66+
return x == state.x && y == state.y && Objects.equals(zombies, state.zombies);
67+
}
68+
69+
@Override
70+
public int hashCode() {
71+
return Objects.hash(x, y, zombies);
72+
}
73+
}
74+
75+
Zombie moveZombie(Zombie z, int n, int m, String[] field) {
76+
if (z.direction == 'N') {
77+
if (field[z.x - 1].charAt(z.y) != '#')
78+
return new Zombie(z.id, z.x - 1, z.y, z.direction);
79+
else
80+
return new Zombie(z.id, z.x, z.y, turnClockwise(z.direction));
81+
} else if (z.direction == 'S') {
82+
if (field[z.x + 1].charAt(z.y) != '#')
83+
return new Zombie(z.id, z.x + 1, z.y, z.direction);
84+
else
85+
return new Zombie(z.id, z.x, z.y, turnClockwise(z.direction));
86+
} else if (z.direction == 'W') {
87+
if (field[z.x].charAt(z.y - 1) != '#')
88+
return new Zombie(z.id, z.x, z.y - 1, z.direction);
89+
else
90+
return new Zombie(z.id, z.x, z.y, turnClockwise(z.direction));
91+
} else if (z.direction == 'E') {
92+
if (field[z.x].charAt(z.y + 1) != '#')
93+
return new Zombie(z.id, z.x, z.y + 1, z.direction);
94+
else
95+
return new Zombie(z.id, z.x, z.y, turnClockwise(z.direction));
96+
}
97+
98+
return new Zombie(0, 0, 0, 'x');
99+
}
100+
101+
public int timeToKill(String[] field) {
102+
103+
int n = field.length, m = field[0].length();
104+
int sx = 0, sy = 0;
105+
int cnt = 0;
106+
List<Zombie> zombies = new ArrayList<>();
107+
for (int i = 0; i < n; i++) {
108+
for (int j = 0; j < m; j++) {
109+
if (field[i].charAt(j) == 'H') {
110+
sx = i;
111+
sy = j;
112+
}
113+
if (field[i].charAt(j) == 'N' || field[i].charAt(j) == 'W' || field[i].charAt(j) == 'S'
114+
|| field[i].charAt(j) == 'E') {
115+
zombies.add(new Zombie(cnt++, i, j, field[i].charAt(j)));
116+
}
117+
}
118+
}
119+
120+
// Map<State, Boolean> visited = new HashMap<>();
121+
// Map<State, Integer> dp = new HashMap<>();
122+
123+
int[][][] dp = new int[21][21][1 << 12];
124+
125+
for (int i = 0; i < n; i++)
126+
for (int j = 0; j < m; j++)
127+
for (int k = 0; k < 1 << cnt; k++)
128+
dp[i][j][k] = 1 << 25;
129+
130+
Queue<State> q = new LinkedList<>();
131+
132+
State start = new State(sx, sy, zombies, 0);
133+
dp[sx][sy][0] = 0;
134+
q.add(start);
135+
136+
int[] dx = { -1, 1, 0, 0, 0 };
137+
int[] dy = { 0, 0, -1, 1, 0 };
138+
139+
while (!q.isEmpty()) {
140+
State curr = q.remove();
141+
// System.out.println(curr.x + " " + curr.y + " " +
142+
// Integer.toBinaryString(curr.mask) + " " + " Zombies: ");
143+
// for (int i=0; i< curr.zombies.size(); i++)
144+
// System.out.println(curr.zombies.get(i).x + " " + curr.zombies.get(i).y + " "
145+
// + curr.zombies.get(i).direction);
146+
if (dp[curr.x][curr.y][curr.mask] > 100)
147+
continue;
148+
if (curr.mask == ((1 << cnt) - 1)) {
149+
return dp[curr.x][curr.y][curr.mask];
150+
}
151+
152+
List<Zombie> movedZombies = new ArrayList<>();
153+
154+
for (Zombie z : curr.zombies)
155+
movedZombies.add(moveZombie(z, n, m, field));
156+
157+
for (int move = 0; move < 5; move++) {
158+
int nx = curr.x + dx[move], ny = curr.y + dy[move];
159+
if (nx >= 0 && nx < n && ny >= 0 && ny < m && field[nx].charAt(ny) != '#') {
160+
161+
List<Zombie> samePos = new ArrayList<>();
162+
for (Zombie zombie : movedZombies) {
163+
if ((nx == zombie.x && ny == zombie.y))
164+
samePos.add(zombie);
165+
}
166+
167+
if (dp[nx][ny][curr.mask] > dp[curr.x][curr.y][curr.mask] + 1) {
168+
State next = new State(nx, ny, movedZombies, curr.mask);
169+
dp[nx][ny][curr.mask] = dp[curr.x][curr.y][curr.mask] + 1;
170+
q.add(next);
171+
}
172+
173+
if (samePos.size() > 0) {
174+
for (Zombie samePo : samePos) {
175+
List<Zombie> nextZombies = new ArrayList<>(movedZombies);
176+
nextZombies.remove(samePo);
177+
int nmask = (curr.mask | (1 << samePo.id));
178+
State next = new State(nx, ny, nextZombies, nmask);
179+
if (dp[nx][ny][nmask] > dp[curr.x][curr.y][curr.mask] + 1) {
180+
dp[nx][ny][nmask] = dp[curr.x][curr.y][curr.mask] + 1;
181+
q.add(next);
182+
}
183+
}
184+
}
185+
186+
}
187+
}
188+
189+
}
190+
return -1;
191+
}
192+
193+
public static void main(String[] args) {
194+
KillingZombies k = new KillingZombies();
195+
System.out.println(k.timeToKill(new String[] { "#######", "#H E #", "#######" }));
196+
System.out.println(k.timeToKill(
197+
new String[] { "#######", "# # # #", "## N##", "#W #", "#H# #", "#N ## #", "#######" }));
198+
System.out.println(k.timeToKill(
199+
new String[] { "#######", "## # ##", "# E##", "# S # #", "# E S #", "#H ##", "#######" }));
200+
}
201+
}

0 commit comments

Comments
 (0)