Skip to content

Add simple example game - Dungeon Postman#59

Merged
utilForever merged 5 commits into
utilForever:mainfrom
JoeYunHa:feat/example-dungeon-postman-clean
May 19, 2026
Merged

Add simple example game - Dungeon Postman#59
utilForever merged 5 commits into
utilForever:mainfrom
JoeYunHa:feat/example-dungeon-postman-clean

Conversation

@JoeYunHa
Copy link
Copy Markdown
Contributor

@JoeYunHa JoeYunHa commented May 7, 2026

What

Add dungeon_postman example: a 5-level roguelike that showcases bracket-lib's RNG, FOV, and A* pathfinding APIs in an interactive game context.

Why

The existing examples demonstrate individual APIs in isolation. dungeon_postman provides a cohesive, game-sized example that shows how bracket_random, bracket_pathfinding, and bracket_terminal compose together — giving new users a realistic reference for building their own games.

Closes #25.

Checklist

Required

  • cargo check --all passes
  • cargo fmt --all -- --check passes
  • cargo clippy --workspace --all-targets -- -D warnings -A clippy::multiple-crate-versions passes
  • cargo test --all passes
  • I linked the related issue (for example: Closes #123)

Functional Validation

  • Behavior related to this change was verified locally (if applicable)
  • Rendering/backend behavior was verified when runtime code changed (if applicable; no runtime code changed)
  • Algorithm behavior (pathfinding/FOV/noise/random) was verified when affected (if applicable; not affected)
  • I added or updated tests for changed behavior (if applicable; workflow configuration only)

Configuration & Docs

  • User-facing docs were updated (README.md, ARCHITECTURE.md, or relevant manual pages, if applicable; not applicable)
  • New dependencies/configuration are documented (if applicable; no new dependencies)
  • No sensitive values or credentials were introduced

If Applicable

  • Security impact considered (run cargo audit locally if needed; not needed for workflow-only change)
  • Breaking behavior changes are clearly described in this PR (not applicable)

Validation Notes

  • git diff --check passes.
  • .github/workflows/rust.yml and .github/workflows/sonarcloud.yml were parsed successfully as YAML.
  • Cargo build/test commands were not run because this PR only changes GitHub Actions configuration.

Summary by CodeRabbit

  • New Features
    • Added the "Dungeon Postman" example game: fixed-size dungeon with torch-style field-of-view, HUD and toast overlays, key/exit gating, multi-level progression, and keyboard controls (arrows/WASD/numpad).
    • Goblin enemies with multi-stage AI (chase, search, wander), rate-limited movement, and toast notifications on behavior changes.
    • Web (WASM) support for in-browser play.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

📝 Walkthrough

Walkthrough

Adds a standalone Dungeon Postman example: procedural dungeon generation, torch-based FOV with revealed/visible tiles, key/exit progression, goblin monsters with three-tier AI, toast HUD, run-state overlays, and a main loop with WASM support.

Changes

Dungeon Postman Game Example

Layer / File(s) Summary
Constants & Types
bracket-terminal/examples/dungeon_postman.rs
WASM support, imports, gameplay constants, coordinate/helpers, and toast type/layout setup.
Dungeon Generation
bracket-terminal/examples/dungeon_postman.rs
Map creation, room/tunnel carving, Algorithm2D/BaseMap adapters for FOV/pathing, and map indexing.
State & Level Init
bracket-terminal/examples/dungeon_postman.rs
State, RunState, monster types, non-overlapping room placement, player/exit/key/monster spawning, HUD/log/toasts init, initial FOV.
Player Movement & Interactions
bracket-terminal/examples/dungeon_postman.rs
Movement with bounds/wall checks, monster collision -> Lost, key pickup, exit gating and level/game clear transitions.
Toasts & FOV
bracket-terminal/examples/dungeon_postman.rs
Toast deduplication/cap/expiration, FOV recompute marking visible/revealed, and FOV-toast cooldown logic.
Monster AI
bracket-terminal/examples/dungeon_postman.rs
Three-tier AI: A* chase when visible, search to last-known position, wander otherwise; level-paced ticks and AI-transition toasts.
Rendering Pipeline
bracket-terminal/examples/dungeon_postman.rs
Render revealed vs visible tiles with distance dimming, conditional monster/key rendering, player glyph, toast overlay, and two HUD rows.
Overlays (end states)
bracket-terminal/examples/dungeon_postman.rs
Full-screen LevelClear, GameClear, and Lost overlays with restart/advance controls.
Game Loop & Entry
bracket-terminal/examples/dungeon_postman.rs
tick handles single-move input per frame, toast/FOV updates, monster advancement on timer, run-state rendering, and main() starts the 80×50 terminal loop.

Sequence Diagram

sequenceDiagram
    participant Player
    participant Engine as GameLoop
    participant Map as Dungeon+FOV
    participant Monsters
    participant Renderer

    Player->>Engine: Move input (arrow/WASD/numpad)
    Engine->>Map: Validate move (bounds/walls)
    alt Key pickup
        Map->>Engine: collect key
    end
    alt Exit reached
        Map->>Engine: LevelClear or GameClear
    end

    Engine->>Map: Recompute FOV
    Map->>Engine: visible/revealed update

    alt Monster timer elapsed
        Engine->>Monsters: tick
        Monsters->>Map: check visibility to player
        alt Player visible
            Monsters->>Monsters: A* pathfind & chase
        else Memory exists
            Monsters->>Monsters: move toward last-known
        else Wander
            Monsters->>Monsters: random neighbor
        end
        alt collision
            Monsters->>Engine: set Lost state
        end
    end

    Engine->>Renderer: render tiles, monsters, key, player, toasts, HUD
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 In shadowed halls the Postman goes,
A tiny torch and pockets of bows,
He finds the key, he dares the gate,
Goblins grumble — he outruns fate,
Toasts sing softly: "Deliveries great!"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add simple example game - Dungeon Postman' directly and clearly reflects the main change: adding a new example game called Dungeon Postman to the codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bracket-terminal/examples/dungeon_postman.rs (1)

1-788: 🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Add tests for the new gameplay logic.

This introduces substantial behavior (map generation, movement, AI transitions, win/lose states), but no tests are included in the changed Rust module set. Please add focused tests for core transitions (e.g., locked exit behavior, key pickup, collision loss, AI state transitions).
As per coding guidelines, "Add tests for new functionality in the relevant module; for split domains, prefer colocated tests.rs".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bracket-terminal/examples/dungeon_postman.rs` around lines 1 - 788, Add unit
tests colocated with this module (e.g., a tests.rs under cfg(test)) that
exercise the new gameplay transitions: create a deterministically initialised
State via State::build(level) (or a helper that sets player_pos/monsters/map
directly), then assert behavior of State::try_move_player for the locked exit
(player cannot enter Exit without has_key), key pickup (stepping onto key_pos
sets has_key and clears key_pos and updates key_status_line/log), collision loss
(place a Monster at player_pos and call move_monsters or inspect run_state/log),
and AI transitions (toggle map.visible and last_known_pos and call move_monsters
to assert alerted/last_known_pos changes and that appropriate transitions
trigger). Reference State::build, State::try_move_player, State::move_monsters,
State::push_toast/toasts, and RunState to locate logic; keep tests focused,
deterministic, and colocated per guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bracket-terminal/examples/dungeon_postman.rs`:
- Around line 706-734: The code marks player_moved true on any movement key
press even if movement was blocked; modify try_move_player to return a bool
(true when the player actually moved) and change each call site in the key match
to set player_moved = self.try_move_player(dx, dy) (or player_moved |=
self.try_move_player(...)) so update_fov(), push_toast(TOAST_FOV, ...), and
fov_toast_cooldown logic only run when actual movement occurred; also update any
other callers of try_move_player to handle the new boolean return.
- Around line 347-384: try_move_player currently lets the player step onto a
tile occupied by a monster and relies on move_monsters() to handle combat later;
update try_move_player to check for a monster at new_pos immediately (e.g.
inspect self.monsters for an entry with pos == new_pos) and handle the collision
synchronously by setting self.run_state to the appropriate defeat state (e.g.
RunState::GameOver or RunState::PlayerDead), updating self.log with a defeat
message, and reverting player_pos if needed; this ensures immediate, consistent
collision semantics between try_move_player, player_pos, monsters, run_state,
and log.

---

Outside diff comments:
In `@bracket-terminal/examples/dungeon_postman.rs`:
- Around line 1-788: Add unit tests colocated with this module (e.g., a tests.rs
under cfg(test)) that exercise the new gameplay transitions: create a
deterministically initialised State via State::build(level) (or a helper that
sets player_pos/monsters/map directly), then assert behavior of
State::try_move_player for the locked exit (player cannot enter Exit without
has_key), key pickup (stepping onto key_pos sets has_key and clears key_pos and
updates key_status_line/log), collision loss (place a Monster at player_pos and
call move_monsters or inspect run_state/log), and AI transitions (toggle
map.visible and last_known_pos and call move_monsters to assert
alerted/last_known_pos changes and that appropriate transitions trigger).
Reference State::build, State::try_move_player, State::move_monsters,
State::push_toast/toasts, and RunState to locate logic; keep tests focused,
deterministic, and colocated per guidelines.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 65a6d80b-5199-41ae-be28-cd3a556691cb

📥 Commits

Reviewing files that changed from the base of the PR and between df886d7 and cf933ed.

📒 Files selected for processing (1)
  • bracket-terminal/examples/dungeon_postman.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format all Rust code using cargo fmt --all
Fix all cargo clippy warnings — the CI enforces -D warnings
Add tests for new functionality in the relevant module; for split domains, prefer colocated tests.rs

Files:

  • bracket-terminal/examples/dungeon_postman.rs

Comment thread bracket-terminal/examples/dungeon_postman.rs Outdated
Comment thread bracket-terminal/examples/dungeon_postman.rs Outdated
@utilForever utilForever self-requested a review May 7, 2026 12:35
@JoeYunHa
Copy link
Copy Markdown
Contributor Author

JoeYunHa commented May 8, 2026

@utilForever 혹시 저한테 coderabbitai bot의 리뷰가 보이지 않는게 정상일까요?

@utilForever
Copy link
Copy Markdown
Owner

@coderabbitai Can you review it?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Tip

For best results, initiate chat on the files or code changes.

@utilForever Sure! I'll start reviewing the PR right away.

[review]

JoeYunHa

This comment was marked as abuse.

JoeYunHa

This comment was marked as abuse.

@JoeYunHa
Copy link
Copy Markdown
Contributor Author

JoeYunHa commented May 8, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
bracket-terminal/examples/dungeon_postman.rs (1)

746-751: ⚡ Quick win

Preserve timer overflow to keep monster cadence stable under frame spikes.

At Lines 746-751, resetting self.monster_timer to 0.0 drops residual elapsed time. This can make monster movement slower/inconsistent when frame_time_ms is large.

Suggested change
-                if self.monster_timer >= monster_interval && self.run_state == RunState::Running {
-                    self.monster_timer = 0.0;
-                    self.move_monsters();
-                }
+                while self.monster_timer >= monster_interval && self.run_state == RunState::Running {
+                    self.monster_timer -= monster_interval;
+                    self.move_monsters();
+                }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@bracket-terminal/examples/dungeon_postman.rs` around lines 746 - 751, The
timer reset drops leftover frame time causing inconsistent monster cadence;
instead of setting self.monster_timer = 0.0 in the block that checks
self.monster_timer >= monster_interval and self.run_state == RunState::Running,
preserve overflow by subtracting monster_interval from self.monster_timer (or
use a while loop that repeatedly subtracts monster_interval and calls
self.move_monsters() to handle multiple intervals in one large frame) so
residual elapsed time is kept and monster movement cadence remains stable;
changes should be applied around the self.monster_timer, monster_interval,
RunState::Running and self.move_monsters() logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@bracket-terminal/examples/dungeon_postman.rs`:
- Around line 224-795: Add a colocated test module (#[cfg(test)] mod tests) in
this file (or a new tests.rs next to it) and add focused unit tests that
exercise deterministic rules by constructing or mutating State instances and
calling the exposed methods: 1) test blocked movement: set up a State/map where
the target tile is TileType::Wall and assert State::try_move_player returns
false and player_pos is unchanged; 2) test key pickup and exit gating: place
key_pos on an adjacent tile, step onto it and assert has_key becomes true and
key_pos becomes None, then place Exit on an adjacent tile and assert stepping
onto it without key leaves run_state as Running and player_pos reset, but
stepping with has_key transitions run_state to RunState::LevelClear or
RunState::GameClear depending on level; 3) test monster interactions and loss:
create a State with a monster positioned on the destination tile (or move a
monster onto player_pos), call try_move_player or move_monsters as appropriate
and assert run_state becomes RunState::Lost and log updated; for move_monsters
tests set map.visible / last_known_pos to force alert/search paths and assert
monsters[].alerted and last_known_pos update accordingly. Construct State via
State::build(1) then mutate fields (map, player_pos, key_pos, monsters,
map.visible) so tests remain deterministic and avoid UI; use asserts on
RunState, has_key, player_pos, monsters and key_pos to validate behavior.

---

Nitpick comments:
In `@bracket-terminal/examples/dungeon_postman.rs`:
- Around line 746-751: The timer reset drops leftover frame time causing
inconsistent monster cadence; instead of setting self.monster_timer = 0.0 in the
block that checks self.monster_timer >= monster_interval and self.run_state ==
RunState::Running, preserve overflow by subtracting monster_interval from
self.monster_timer (or use a while loop that repeatedly subtracts
monster_interval and calls self.move_monsters() to handle multiple intervals in
one large frame) so residual elapsed time is kept and monster movement cadence
remains stable; changes should be applied around the self.monster_timer,
monster_interval, RunState::Running and self.move_monsters() logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5bcddbda-12d4-45d3-8b00-f5ffc4980f6e

📥 Commits

Reviewing files that changed from the base of the PR and between cf933ed and bfa0e2b.

📒 Files selected for processing (1)
  • bracket-terminal/examples/dungeon_postman.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Format all Rust code using cargo fmt --all
Fix all cargo clippy warnings — the CI enforces -D warnings
Add tests for new functionality in the relevant module; for split domains, prefer colocated tests.rs

Files:

  • bracket-terminal/examples/dungeon_postman.rs

Comment thread bracket-terminal/examples/dungeon_postman.rs
JoeYunHa

This comment was marked as abuse.

coderabbitai[bot]
coderabbitai Bot previously approved these changes May 8, 2026
Copy link
Copy Markdown
Owner

@utilForever utilForever left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 리뷰가 많이 늦어져 죄송합니다. 확인 부탁드립니다.

Comment thread bracket-terminal/examples/dungeon_postman.rs Outdated
Comment thread bracket-terminal/examples/dungeon_postman.rs Outdated
Comment thread bracket-terminal/examples/dungeon_postman.rs
Comment thread bracket-terminal/examples/dungeon_postman.rs Outdated
@utilForever utilForever changed the title feat: add dungeon postman example Add simple example game - Dungeon Postman May 17, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 18, 2026
Copy link
Copy Markdown
Owner

@utilForever utilForever left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now. Thanks for your work! 🎉

@utilForever utilForever merged commit 7c426b4 into utilForever:main May 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RLTK를 사용하는 예제 게임 만들기

2 participants