Rating: 4.0

The strategy is to recursively test each bit for a match to flag{, and if a match is found, iterate over all 8 possible directions (north, north-east, east, etc..) and test for the next bit.

```
from PIL import Image

img = Image.open("BinaryWordSearch.png")
data = img.convert('1').load()

size_x, size_y = img.size

HEAD = "flag{"
head_ar = "".join([f'{ord(c):08b}' for c in HEAD])

# offsets to iterate over certain direction
"""
7 0 1
6 2
5 4 3
"""
direction_map = (
(0, -1),
(1, -1),
(1, 0),
(1, 1),
(0, 1),
(-1, 1),
(-1, 0),
(-1, -1)
)

def test(x, y, offset, head_index):
# checks if data[x, y] == head_ar[head_index]
# returns False if no match,
# otherwise, advance x, y by offset and test the next bit
if head_index == (len(head_ar) - 1):
return True

if (data[x, y] == 255 and head_ar[head_index] == '1') or (data[x, y] == 0 and head_ar[head_index] == '0'):
new_x = x + offset[0]
new_y = y + offset[1]

# if exceed image bounds, dont bother
if new_x < 0 or new_x >= size_x or new_y < 0 or new_y >= size_y:
return False

return test(new_x, new_y, offset, head_index + 1)
else:
return False

def find():
for x in range(size_x):
for y in range(size_y):
for d in range(8):
if test(x, y, offset=direction_map[d], head_index=0):
return (x, y, d)

x, y, d = find()

offset = direction_map[d]

flag = []
for _ in range(20 * 8):
c_raw = 0
for i in range(8):
if data[x, y] == 255:
c_raw += 1<<(7-i)

x += offset[0]
y += offset[1]

c = chr(c_raw)
flag.append(c)
if c == '}':
break

print("".join(flag))
```

Original writeup (https://blog.justins.in/hsctf20#binary-word-search).