In a field of geometry 5x5, put down 3 wolves and 5 sheeps. However, the wolves will kill the sheeps that they see in any diagonal or axial (horizonal and vertical) directions.
Actually, there is only one solution (ignoring transpose).
\[\begin{array}{ccccc} W & W & \_ & \_ & \_ \\ \_ & \_ & \_ & S & S \\ \_ & \_ & \_ & \_ & S \\ W & \_ & \_ & \_ & \_ \\ \_ & \_ & S & S & \_ \end{array}\]How to solve: (1) By enumeration.
import itertools
GRIDSIZE = 5
WOLVES = 3
SHEEPS = 5
solution = [['_' for j in range(GRIDSIZE)] for i in range(GRIDSIZE)]
coordinates = list(itertools.product(range(GRIDSIZE), range(GRIDSIZE)))
def getTransforms(coords):
yield [(x, GRIDSIZE-1-y) for x, y in coords] # mirror vertically, aka rotate transpose 90 degree
yield [(y, GRIDSIZE-1-x) for x, y in coords] # rotate 90 degree, aka mirror of transpose vertically
yield [(y, x) for x, y in coords] # transpose
yield [(GRIDSIZE-1-x, y) for x, y in coords] # mirror horizontally, aka rotate transpose 270 degree
yield [(GRIDSIZE-1-x, GRIDSIZE-1-y) for x, y in coords] # rotate 180 degree
yield [(GRIDSIZE-1-y, x) for x, y in coords] # rotate 270 degree, aka rotate transpose horizontally
yield [(GRIDSIZE-1-y, GRIDSIZE-1-x) for x, y in coords] # rotate transpose 180 degree
def sameSet(coords1, coords2):
coords1 = sorted(coords1)
return any(coords1 == sorted(coords) for coords in getTransforms(coords2))
def wolfSee(wolfcoord):
wx, wy = wolfcoord
coords = [
(wx,y) for y in range(GRIDSIZE) # coordinates of same row
] + [
(x,wy) for x in range(GRIDSIZE) # coordinates of same column
] + [
(wx+i,wy+i) for i in range(-GRIDSIZE+1,GRIDSIZE) # coordinates of forward diagonal
] + [
(wx+i,wy-i) for i in range(-GRIDSIZE+1,GRIDSIZE) # coordinates of backward diagonal
]
return set((x,y) for x,y in coords)
if __name__=='__main__':
checked = set([])
for wolves in itertools.combinations(coordinates, WOLVES):
if any(sameSet(wolves, old_wolves) for old_wolves in checked):
continue # just a transformation, skip
checked.add(wolves)
goodcoordinates = set(coordinates)
for wolf in wolves:
goodcoordinates = goodcoordinates - wolfSee(wolf)
if len(goodcoordinates) < SHEEPS:
break # no way to place sheeps in this config
else:
print "Solution found:"
print " Wolves: %s" % list(wolves)
print " Sheeps: %s" % list(goodcoordinates)
Also, (2) there is an analytical method to solve (in MathProg):
param N, integer, >0; /* grid size */
param W, integer, >0; /* number of wolves */
param S, integer, >0; /* number of sheeps */
var WOLF {1..N, 1..N}, binary; /* WOLF[j,k]=1 iff a wolf is in coordinate (j,k) */
var SHEEP {1..N, 1..N}, binary; /* SHEEP[j,k]=1 iff a sheep is in coordinate (j,k) */
var hb{1..N} binary; /* constraint helper */
var vb{1..N} binary;
var db{1-N..N-1} binary;
var bb{2..N*2} binary;
/* Every wolf has a unique coordinate */
s.t. wolf_coordinate: sum{x in 1..N, y in 1..N} WOLF[x,y] = W;
/* Every sheep has a unique coordinate */
s.t. sheep_coordinate: sum{x in 1..N, y in 1..N} SHEEP[x,y] = S;
/* No wolf see any sheep horizontally */
s.t. horizontals{y in 1..N}: sum{x in 1..N} SHEEP[x,y] <= (S+W)*hb[y];
s.t. horizontalw{y in 1..N}: sum{x in 1..N} WOLF[x,y] <= (S+W)*(1-hb[y]);
/* On every horizontal scan, we either find sheeps or wolves or neither but not both */
/* No wolf see any sheep vertically */
s.t. verticals{x in 1..N}: sum{y in 1..N} SHEEP[x,y] <= (S+W)*vb[x];
s.t. verticalw{x in 1..N}: sum{y in 1..N} WOLF[x,y] <= (S+W)*(1-vb[x]);
/* On every vertical scan, we either find sheeps or wolves or neither but not both */
/* No wolf see any sheep forward diagonally */
s.t. diagonals{i in 1-N..N-1}: sum{x in 1..N, y in 1..N: x-y=i} SHEEP[x,y] <= (S+W)*db[i];
s.t. diagonalw{i in 1-N..N-1}: sum{x in 1..N, y in 1..N: x-y=i} WOLF[x,y] <= (S+W)*(1-db[i]);
/* On every diagonal scan, we either find sheeps or wolves or neither but not both */
/* No wolf see any sheep backward diagonally */
s.t. backwards{i in 2..N*2}: sum{x in 1..N, y in 1..N: x+y=i} SHEEP[x,y] <= (S+W)*bb[i];
s.t. backwardw{i in 2..N*2}: sum{x in 1..N, y in 1..N: x+y=i} WOLF[x,y] <= (S+W)*(1-bb[i]);
/* On every diagonal scan, we either find sheeps or wolves or neither but not both */
solve;
printf "Wolves: ";
for {x in 1..N} {
for {y in 1..N: WOLF[x,y] == 1} {
printf "(%d,%d) ", x, y;
}
}
printf "\n";
printf "Sheeps: ";
for {x in 1..N} {
for {y in 1..N: SHEEP[x,y] == 1} {
printf "(%d,%d) ", x, y;
}
}
printf "\n";
data;
param N := 5;
param W := 3;
param S := 5;
end;