Deep Blue Sea
Deep Blue Sea
Platform: undutmaning | Category: Misc | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-03-21 | Status: Solved Techniques: bfs_pathfinding, image_to_grid_conversion, obstacle_avoidance, two_phase_navigation
Summary
English summary: Navigate through a flooded underwater lab maze to retrieve a battery and return to the exit. The lab is dark and filled with sharks. You receive shark positions via radar every 6 seconds and must plan your entire path before moving (hitting a wall alerts the sharks). The challenge r
Deep Blue Sea — Undutmaning
Description
Att använda CASCADAs räddningskappslar för att ta sig till ytan verkar vara en bra plan. Tyvärr är underhållet lite eftersatt och man har inte bytt batterierna till de livsuppehållande systemen enligt det rekommenderade schemat. För att göra saken etter värre så ligger förrådet med batterier i en för närvarande oåtkomlig del av anläggningen.
Lyckligtvis kommer forskaren Perseus Plankton ihåg att han har ett passande batteri i sitt labb. Vilken lättnad! Nu är det bara det lilla abret att labbet ligger i den del av CASCADA som delvis fyllts med vatten och hajar!
Perseus ger dig en karta över labbet där han ritat in var batteriet finns. Han kan också, med hjälp av labbets mikrovågsradar, hålla lite koll på var hajarna befinner sig. Tyvärr är utrustningen stor, tung och långsam så det dröjer lite mellan varje radarsvep. Han kan därför bara ge dig informationen om hajarna med 6 sekunders mellanrum. Inte nog med det, på grund av vattnet fungerar inte belysningen i labbet. Det är bara vid ingången och hörnet där batteriet ligger, där det är ljust nog att titta på kartan. Går du in i en vägg så kommer hajarna uppfatta var du är och kasta sig över dig, så du måste redan innan du springer in i labbet bestämma hur du ska röra dig hela vägen fram till batteriet (respektive utgången)!
Du måste ta dig till batteriet och ta med det tillbaka till utgången.
English summary: Navigate through a flooded underwater lab maze to retrieve a battery and return to the exit. The lab is dark and filled with sharks. You receive shark positions via radar every 6 seconds and must plan your entire path before moving (hitting a wall alerts the sharks). The challenge requires two-phase navigation: to the battery and back.
- Service: undutmaning-deep.chals.io (SSL on port 443)
- Map: lab-map.png (868x868 PNG maze)
- Flag format:
undut{...}
Analysis
Map Structure
The maze image is 868x868 pixels representing a 31x31 grid (28 pixels per cell):
- Start position: Cell (1,1) - top-left area (marked with running person icon)
- Battery location: Cell (29,29) - bottom-right area (marked with green battery icon)
- White cells: Passable paths
- Black cells: Walls
Server Protocol
- Connect via SSL to port 443
- Receive instructions in Swedish
- Receive JSON with shark positions:
{"sharks": [[row, col], ...]} - Send direction string using Swedish notation: N (North/up), S (South/down), Ö (East/right), V (West/left)
- After reaching battery, receive new shark positions
- Send return path direction string
- Receive flag on success
Key Constraints
- Must plan entire path before moving (no mid-path corrections)
- Hitting a wall = death (sharks detect you)
- Sharks block cells - must avoid them
- Two-phase journey: start → battery → start
Solution
Step 1: Parse the Maze Image
Convert the PNG into a binary grid representation:
python read-only • copy allowedfrom PIL import Image def parse_maze(image_path): img = Image.open(image_path).convert('RGB') cell_size = 28 # 868 / 31 = 28 pixels per cell grid_size = 31 maze = [] for row in range(grid_size): maze_row = [] for col in range(grid_size): # Sample center of each cell x = col * cell_size + cell_size // 2 y = row * cell_size + cell_size // 2 # Count white pixels in cell white_count = 0 total = 0 for dy in range(-5, 6): for dx in range(-5, 6): px, py = x + dx, y + dy if 0 <= px < img.width and 0 <= py < img.height: r, g, b = img.getpixel((px, py)) if r > 200 and g > 200 and b > 200: white_count += 1 total += 1 # Cell is passable if >50% white maze_row.append(0 if white_count > total * 0.5 else 1) maze.append(maze_row) return maze
Step 2: BFS Pathfinding with Shark Avoidance
python read-only • copy allowedfrom collections import deque def bfs_avoid_sharks(maze, start, end, sharks): """Find shortest path avoiding walls and sharks""" shark_set = set((s[0], s[1]) for s in sharks) queue = deque([(start, [start])]) visited = {start} # Swedish direction notation directions = [ (-1, 0, 'N'), # North (up) (1, 0, 'S'), # South (down) (0, 1, 'Ö'), # East (right) - Swedish Ö (0, -1, 'V') # West (left) ] while queue: (row, col), path = queue.popleft() if (row, col) == end: return path for dr, dc, _ in directions: new_row, new_col = row + dr, col + dc if (0 <= new_row < 31 and 0 <= new_col < 31 and maze[new_row][new_col] == 0 and (new_row, new_col) not in visited and (new_row, new_col) not in shark_set): visited.add((new_row, new_col)) queue.append(((new_row, new_col), path + [(new_row, new_col)])) return None # No path found def path_to_directions(path): """Convert path coordinates to direction string""" direction_map = { (-1, 0): 'N', (1, 0): 'S', (0, 1): 'Ö', (0, -1): 'V' } directions = [] for i in range(1, len(path)): dr = path[i][0] - path[i-1][0] dc = path[i][1] - path[i-1][1] directions.append(direction_map[(dr, dc)]) return ''.join(directions)
Step 3: Two-Phase Navigation
python read-only • copy allowedimport ssl import socket import json def solve(): maze = parse_maze('lab-map.png') start = (1, 1) battery = (29, 29) # SSL connection context = ssl.create_default_context() sock = socket.create_connection(('undutmaning-deep.chals.io', 443)) ssl_sock = context.wrap_socket(sock, server_hostname='undutmaning-deep.chals.io') # Read initial instructions data = ssl_sock.recv(4096).decode() print(data) # Phase 1: Start to Battery # Parse shark positions from JSON shark_data = json.loads(ssl_sock.recv(4096).decode()) sharks = shark_data['sharks'] path1 = bfs_avoid_sharks(maze, start, battery, sharks) directions1 = path_to_directions(path1) ssl_sock.send((directions1 + '\n').encode()) # Server response: "Med andan i halsen hittar du fram och plockar upp batteriet." response = ssl_sock.recv(4096).decode() print(response) # Phase 2: Battery back to Start shark_data = json.loads(ssl_sock.recv(4096).decode()) sharks = shark_data['sharks'] path2 = bfs_avoid_sharks(maze, battery, start, sharks) directions2 = path_to_directions(path2) ssl_sock.send((directions2 + '\n').encode()) # Receive flag flag = ssl_sock.recv(4096).decode() print(flag) ssl_sock.close() if __name__ == '__main__': solve()
Server Responses
Phase 1 success:
"Med andan i halsen hittar du fram och plockar upp batteriet." (Translation: "Breathlessly, you find your way and pick up the battery.")
Phase 2 success:
Returns the flag
Notes
- The flag quote "REDACTED" is from Herman Melville's Moby-Dick, fitting the underwater shark theme
- Swedish direction Ö (Öst) = East, V (Väst) = West
- The 6-second radar delay mentioned in the description is flavor text - in practice, you receive shark positions immediately when needed
- BFS guarantees shortest path, which is important when sharks might block longer routes
- Image parsing must handle the start/battery icons (not just pure white/black cells)