Quick Overview

Live coding simulation problem: a ball sits in a grid maze on a board that can tilt up, down, left or right or lie flat, and timed events change the tilt. Return the ball's cell at an end time that can be very large. It tests precise timing rules, wall handling and movement code that scales to long time spans.

Ball Position in a Tilting Maze After Timed Tilt Events

Company: Hudson

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: easy

Interview Round: Technical Screen

A game board holds a rectangular maze and a single ball. At any moment the board is in one of five states: `"up"`, `"down"`, `"left"`, `"right"` or `"flat"`. While the board is tilted, that is, in any state other than `"flat"`, the ball rolls one cell per second in the tilt direction, as long as the cell next to it in that direction is not a wall. You are given the maze, the ball's starting cell, a list of events that each tilt the board to a new state at a given time, and an end time. Return the cell the ball occupies at the end time. ### Function Signature ```python def ball_position(maze: list[str], start: list[int], events: list[tuple[int, str]], end_time: int) -> list[int]: ``` `maze[i][j]` is `'#'` for a wall and `'.'` for an open cell. `start` is `[row, col]`. Each event is `(time, state)`. ### Rules - Row `0` is the top row and column `0` is the leftmost column. From `(row, col)`, `"up"` leads to `(row - 1, col)`, `"down"` to `(row + 1, col)`, `"left"` to `(row, col - 1)` and `"right"` to `(row, col + 1)`. - The board is `"flat"` from time `0` until the first event. An event `(t, state)` puts the board into `state` at time `t`, and the board stays in that state until the next event. - Time advances in whole seconds. For each second `s = 0, 1, ..., end_time - 1`, the board's state during that second is the state set by the last event with `time <= s`, or `"flat"` if there is none. If that state is not `"flat"` and the neighboring cell in that direction is inside the maze and open, the ball moves into it at the end of the second. Otherwise the ball does not move. - Cells outside the maze behave like walls, so the ball never leaves the maze. - Events with `time >= end_time` have no effect. - Return the ball's cell `[row, col]` at time `end_time`. If `end_time` is `0`, this is `start`. ### Constraints - `1 <= len(maze) <= 100` and `1 <= len(maze[0]) <= 100`; all rows have the same length, and every character is `'#'` or `'.'`. - `start` is an open cell. - `0 <= len(events) <= 10^4` - `0 <= time <= 10^9` for every event, and event times are strictly increasing. - Every `state` is one of `"up"`, `"down"`, `"left"`, `"right"` and `"flat"`. - `0 <= end_time <= 10^9` ### Examples **Example 1** ```text Input: maze = ["#######", "#.....#", "#.###.#", "#.....#", "#######"], start = [1, 1], events = [(0, "right"), (2, "flat"), (5, "down"), (8, "right")], end_time = 12 Output: [1, 5] ``` During seconds 0 and 1 the ball rolls right to `(1, 3)`. During seconds 2 to 4 the board is flat. During seconds 5 to 7 the board tilts down, but `(2, 3)` is a wall, so the ball stays. From second 8 it rolls right to `(1, 4)` and then `(1, 5)`; `(1, 6)` is a wall, so it stays at `(1, 5)` through second 11. **Example 2** ```text Input: maze = ["#######", "#.....#", "#.###.#", "#.....#", "#######"], start = [1, 5], events = [(1, "down"), (3, "left"), (100, "up")], end_time = 103 Output: [1, 1] ``` Second 0 is flat. During seconds 1 and 2 the ball rolls down to `(3, 5)`. During seconds 3 to 6 it rolls left to `(3, 1)`, and `(3, 0)` is a wall, so it rests there through second 99. During seconds 100 and 101 it rolls up through `(2, 1)` to `(1, 1)`, and during second 102 the wall at `(0, 1)` blocks it. **Example 3** ```text Input: maze = ["..", ".."], start = [0, 0], events = [(0, "left"), (1, "down"), (2, "right"), (4, "up")], end_time = 4 Output: [1, 1] ``` During second 0 the ball would leave the maze, so it stays. Second 1 moves it down to `(1, 0)` and second 2 moves it right to `(1, 1)`. During second 3 the edge of the maze blocks it. The event at time 4 is not before `end_time`, so it has no effect.

Overview: Live coding simulation problem: a ball sits in a grid maze on a board that can tilt up, down, left or right or lie flat, and timed events change the tilt. Return the ball's cell at an end time that can be very large. It tests precise timing rules, wall handling and movement code that scales to long time spans.

Read the full Hudson Software Engineer interview experience this question came from

A game board holds a rectangular maze and a single ball. At any moment the board is in one of five states: `"up"`, `"down"`, `"left"`, `"right"` or `"flat"`. While the board is tilted (any state other than `"flat"`), the ball rolls one cell per second in the tilt direction, as long as the cell next to it in that direction is not a wall. You are given the maze, the ball's starting cell, a list of events that each tilt the board to a new state at a given time, and an end time. Return the cell the ball occupies at the end time. `maze[i][j]` is `'#'` for a wall and `'.'` for an open cell. `start` is `[row, col]`. Each event is a pair `(time, state)`; in JavaScript and Java it arrives as a two-element list `[time, state]`, and in C++ as a `std::pair<int, std::string>`. ### Rules - Row `0` is the top row and column `0` is the leftmost column. From `(row, col)`, `"up"` leads to `(row - 1, col)`, `"down"` to `(row + 1, col)`, `"left"` to `(row, col - 1)` and `"right"` to `(row, col + 1)`. - The board is `"flat"` from time `0` until the first event. An event `(t, state)` puts the board into `state` at time `t`, and the board stays in that state until the next event. - Time advances in whole seconds. For each second `s = 0, 1, ..., end_time - 1`, the board's state during that second is the state set by the last event with `time <= s`, or `"flat"` if there is none. If that state is not `"flat"` and the neighboring cell in that direction is inside the maze and open, the ball moves into it at the end of the second. Otherwise the ball does not move. - Cells outside the maze behave like walls, so the ball never leaves the maze. - Events with `time >= end_time` have no effect. - Return the ball's cell `[row, col]` at time `end_time`. If `end_time` is `0`, this is `start`. ### Constraints - `1 <= len(maze) <= 100` and `1 <= len(maze[0]) <= 100`; all rows have the same length, and every character is `'#'` or `'.'`. - `start` is an open cell. - `0 <= len(events) <= 10^4` - `0 <= time <= 10^9` for every event, and event times are strictly increasing. - Every `state` is one of `"up"`, `"down"`, `"left"`, `"right"` and `"flat"`. - `0 <= end_time <= 10^9` - Every time value fits in a signed 32-bit integer; no value exceeds `2^31 - 1`. ### Example 1 ```text Input: maze = ["#######", "#.....#", "#.###.#", "#.....#", "#######"], start = [1, 1], events = [(0, "right"), (2, "flat"), (5, "down"), (8, "right")], end_time = 12 Output: [1, 5] ``` During seconds 0 and 1 the ball rolls right to `(1, 3)`. During seconds 2 to 4 the board is flat. During seconds 5 to 7 the board tilts down, but `(2, 3)` is a wall, so the ball stays. From second 8 it rolls right to `(1, 4)` and then `(1, 5)`; `(1, 6)` is a wall, so it stays at `(1, 5)` through second 11. ### Example 2 ```text Input: maze = ["..", ".."], start = [0, 0], events = [(0, "left"), (1, "down"), (2, "right"), (4, "up")], end_time = 4 Output: [1, 1] ``` During second 0 the ball would leave the maze, so it stays. Second 1 moves it down to `(1, 0)` and second 2 moves it right to `(1, 1)`. During second 3 the edge of the maze blocks it. The event at time 4 is not before `end_time`, so it has no effect.

Constraints

  • 1 <= len(maze) <= 100 and 1 <= len(maze[0]) <= 100; all rows have the same length, and every character is '#' or '.'.
  • start is an open cell.
  • 0 <= len(events) <= 10^4
  • 0 <= time <= 10^9 for every event, and event times are strictly increasing.
  • Every state is one of "up", "down", "left", "right" and "flat".
  • 0 <= end_time <= 10^9
  • Every time value fits in a signed 32-bit integer; no value exceeds 2^31 - 1.

Examples

Input: (['.'], [0, 0], [], 0)

Expected Output: [0, 0]

Explanation: Minimum: 1x1 maze, no events, end_time 0 returns start.

Input: (['...'], [0, 1], [(0, 'left')], 0)

Expected Output: [0, 1]

Explanation: end_time 0: the event at time 0 is not before end_time, so start is returned unchanged.

Hints

  1. The board state only changes at event times. Think about what the ball can do during one stretch where the state stays the same, however long that stretch is.
  2. The maze never changes, so a ball that is blocked in the current tilt direction stays blocked until the state changes.
  3. Watch the boundaries: an event at time t governs second t, a move happens at the end of a second, only seconds 0 through end_time - 1 count, and events at or after end_time have no effect.

Loading coding console...

Show the approach

Approach

Process the timeline one segment at a time instead of one second at a time. The board state is constant on each interval [t_k, min(t_{k+1}, end_time)) between consecutive events. The interval before the first event is flat, and events with time >= end_time are skipped, which also makes end_time = 0 return start. A flat segment moves nothing. During a tilted segment of length d, the ball moves one cell per second until the next cell in the tilt direction is a wall or outside the maze. Within a segment neither the maze nor the state changes, so once the ball is blocked it stays blocked for the rest of the segment. The inner loop can therefore stop at the first blocked step or after d moves, whichever comes first. Invariant: after segment k, (r, c) equals the position the per-second rule gives at time min(t_{k+1}, end_time). This holds by induction, because each loop iteration applies exactly one second of the rule and the skipped tail seconds of a segment are all blocked seconds. Every segment makes at most max(R, C) - 1 moves however long it lasts, so times up to 10^9 need no per-second simulation. Edge cases: a 1x1 maze never moves; a tilt into an adjacent wall or the maze edge leaves the ball in place; repeated identical states continue the same roll; an event at exactly end_time is ignored; the last segment is cut by end_time, not by a later event.

Time complexity:
O(E * max(R, C)), where E is the number of events and the maze is R x C
Space complexity:
O(1)