← Glean Interview Insights

Glean·Software Engineer·Technical Phone Screen·Intermediate

IntermediatePrefer not to say
Jul 2026

Summary

Coding round at Glean for a software engineer role. The main problem was implementing the movement logic for 2048, which sounds straightforward until you actually have to get the merge semantics right under interview pressure.

Questions Asked (4)

Q1

Implement the core move logic for a 2048 board. Given an n x n grid, write a method that slides and merges tiles in a given direction (up, down, left, right) according to standard 2048 rules.

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

I started by trying to write separate logic for all four directions and immediately saw how messy that gets.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Clarify the rules and constraints, then design a solution that processes each row/column independently by extracting non-zero tiles, merging adjacent equal tiles once, and padding with zeros. Implement a generic slide-and-merge function and apply it to rows or columns based on direction, using rotation or reversal to handle all four directions uniformly.

Pro tip: Emphasize that each tile can merge only once per move (e.g., [2,2,2,2] becomes [4,4] not [8]), and discuss trade-offs between in-place modification and creating a new board, considering time/space complexity and potential follow-up questions about optimization.

1. Clarify requirements and edge cases

Ask about board size, input format, whether the method should return a new board or modify in-place, and confirm merge rules (e.g., no double merges).

2. Choose a strategy for direction handling

Decide whether to implement separate logic for each direction or use a generic approach with rotation/reversal to reduce code duplication.

3. Implement slide-and-merge for a single line

Write a helper function that takes a list of tiles, removes zeros, merges adjacent equal values once, and pads with zeros to the original length.

4. Apply to the board based on direction

For left/right, process each row; for up/down, process each column. Use rotation or reversal to reuse the same helper.

5. Test and analyze complexity

Walk through examples, including edge cases like all zeros or multiple merges, and state time/space complexity (O(n^2) time, O(n) extra space per line).

Key Points to Mention

  • Merge rule: each tile can merge only once per move, so process from the direction of movement to avoid double merges.
  • Use a helper function to slide and merge a single line, then apply it to rows or columns based on direction.
  • For up/down, either transpose the board or process columns directly; for right/down, reverse the line before and after processing.
  • Time complexity is O(n^2) since each cell is visited a constant number of times; space complexity can be O(n) for temporary line storage or O(1) if modifying in-place.
  • Consider trade-offs: in-place modification saves memory but may be trickier; creating a new board is simpler but uses O(n^2) extra space.
  • Test with cases like [2,2,2,2] -> [4,4,0,0], [2,0,2,2] -> [4,2,0,0], and all zeros.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q2

Follow-up: implement an isGameOver() check that returns true when no legal move remains, without necessarily simulating all four full moves.

Algorithms & Data Structures
Author's notes

They asked this near the end and I kind of fumbled it.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

First, clarify the game rules and the definition of a legal move. Then, propose an efficient check that avoids simulating all four full moves by using early termination and incremental state updates, such as tracking empty cells or precomputing move validity.

Pro tip: Mention that you can maintain a count of empty cells or a bitmask of available moves to make the check O(1) or O(log n) instead of O(n). This shows you think about performance and data structure design.

1. Clarify the game and move rules

Ask or state the specific rules: what constitutes a legal move, how moves are generated, and what the board state looks like. This ensures the solution is tailored to the game.

2. Identify inefficiencies in naive simulation

Explain that simulating all four moves for each empty cell is O(n) per move and can be optimized by checking only necessary conditions or using incremental updates.

3. Propose an efficient algorithm

Suggest maintaining a data structure (e.g., count of empty cells, bitmask of possible moves) that allows quick detection of any legal move. Alternatively, use early termination: check if any move is possible by scanning until one is found.

4. Handle edge cases and correctness

Consider edge cases like full board, moves that merge tiles, or special rules. Ensure the check correctly returns true only when no legal move exists.

5. Analyze complexity and trade-offs

Discuss time and space complexity of your approach versus the naive method, and justify why your solution is efficient and maintainable.

Key Points to Mention

  • Definition of a legal move and how it's determined
  • Early termination: stop as soon as a legal move is found
  • Incremental state tracking (e.g., empty cell count, move availability bitmask)
  • Time complexity comparison: O(n) naive vs O(1) or O(log n) optimized
  • Edge cases: full board, no empty cells but possible merges, special tiles
  • Trade-offs between simplicity and performance, and when to choose each

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q3

How would you signal to the caller that the board actually changed after a move, so the game knows when to spawn a new tile?

Technical Trade-offsAPI & Integrations
Author's notes

Short question, pretty easy.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the context: the board is likely a 2048-like game where a move may or may not change the board. Propose that the move function returns a boolean indicating whether any tile moved or merged, and the caller uses that to decide whether to spawn a new tile. Emphasize that this keeps the API simple and avoids unnecessary state checks.

Pro tip: Mention that returning a boolean is a common pattern in game logic (e.g., 2048 implementations) and that it decouples the move logic from the spawning logic, making the code easier to test and maintain.

1. Clarify the requirement

Restate the problem: after a move, the game needs to know if the board changed to decide whether to spawn a new tile. This avoids spawning a tile when the move was invalid or had no effect.

2. Choose a signaling mechanism

Propose returning a boolean from the move function, where true indicates the board changed. Alternatively, return a result object with a 'changed' flag and possibly other metadata.

3. Implement the move logic

Inside the move function, track whether any tile moved or merged. Set the flag accordingly and return it.

4. Use the signal in the caller

In the game loop, call the move function and check the returned value. If true, spawn a new tile; otherwise, do nothing.

5. Discuss trade-offs

Compare returning a boolean vs. an enum vs. a result object. Mention that a boolean is simple but may lack context; a result object can provide more information for future needs.

Key Points to Mention

  • Return a boolean from the move function to indicate if the board changed.
  • Track changes by comparing board state before and after the move, or by setting a flag during tile movement/merging.
  • Use the boolean in the caller to conditionally spawn a new tile.
  • Consider returning a result object for extensibility (e.g., score gained, tiles merged).
  • Ensure the move function is pure or has no side effects related to spawning, to keep responsibilities separate.
  • Test the move function independently to verify it correctly reports changes.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.

Q4

How would you unit test the movement logic? What invariants always hold across any valid move?

Algorithms & Data StructuresTechnical Trade-offs
Author's notes

This one I liked.

Create a free account to read the full note

AI HintsAI Generated

Suggested Approach

Start by clarifying the movement rules and the system under test, then outline a unit testing strategy that isolates the movement logic from dependencies. Focus on verifying both expected outcomes for valid moves and invariants that must hold across all moves, using a mix of example-based and property-based tests.

Pro tip: Emphasize that invariants are best tested with property-based testing (e.g., QuickCheck) to cover edge cases, and mention that you would also test invalid moves to ensure they are rejected without violating invariants.

1. Clarify the movement logic and system boundaries

Ask questions to understand the rules of movement, the state involved, and what constitutes a valid move. Identify the unit under test and its dependencies to isolate it properly.

2. Identify key invariants

List invariants that must always hold after any valid move, such as position bounds, no overlapping pieces, or conservation of resources. These will guide your test design.

3. Design example-based tests for valid and invalid moves

Write specific test cases for typical valid moves, edge cases (e.g., moving to boundary), and invalid moves (e.g., out of bounds). Assert both the resulting state and that invariants are preserved.

4. Incorporate property-based tests for invariants

Use property-based testing to generate random valid moves and verify that invariants hold across all of them. This catches subtle bugs that example-based tests might miss.

5. Discuss trade-offs and test maintenance

Explain how you balance thoroughness with test maintainability, and how you would handle flaky tests or performance concerns in property-based testing.

Key Points to Mention

  • Isolation of movement logic using mocks or stubs for dependencies like board state or external services.
  • Invariants such as position within bounds, no collisions, turn alternation, and resource conservation.
  • Property-based testing to verify invariants across a wide range of inputs.
  • Testing invalid moves to ensure they are rejected and do not corrupt state.
  • Edge cases like boundary moves, blocked paths, and simultaneous moves.
  • Trade-offs between exhaustive testing and practical test suite size.

AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.