gitquest 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
gitquest-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 gitquest contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,226 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitquest
3
+ Version: 0.1.0
4
+ Summary: Turn your git commit history into a playable ASCII dungeon roguelike.
5
+ Author-email: jithin-jz <jithinjzx@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/jithin-jz/gitquest
8
+ Project-URL: Repository, https://github.com/jithin-jz/gitquest
9
+ Project-URL: Issues, https://github.com/jithin-jz/gitquest/issues
10
+ Keywords: git,game,roguelike,cli,ascii,terminal,rich
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Games/Entertainment
19
+ Classifier: Topic :: Software Development :: Version Control :: Git
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: rich>=13.0.0
24
+ Requires-Dist: GitPython>=3.1.30
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
27
+ Dynamic: license-file
28
+
29
+ # gitquest ๐Ÿ—ก๏ธ
30
+
31
+ > **Your commits. Your dungeon. Your legend.**
32
+ > Turn any git repository's history into a procedurally generated, playable
33
+ > ASCII dungeon roguelike โ€” right in your terminal.
34
+
35
+ `gitquest` reads your repo's real commit history and deterministically builds a
36
+ dungeon from it. Each commit becomes a room. Bug-fix commits spawn bugs. Merge
37
+ commits become mini-bosses. The languages you've coded fill your skill tree.
38
+ Clear every room from the repo's first commit to `HEAD`, then flex your career
39
+ on a shareable stats card.
40
+
41
+ **Same repo + same seed = the same dungeon, every time.** Reproducible and
42
+ shareable.
43
+
44
+ ---
45
+
46
+ ## โœจ Demo
47
+
48
+ <!--
49
+ ๐Ÿ“ฝ๏ธ ANIMATED GIF PLACEHOLDER
50
+ Drop a terminal recording here (e.g. via `asciinema` + `agg`, or a screen GIF).
51
+ Recommended: a ~20s clip of a fight + the final flex card.
52
+ ![gitquest demo](docs/demo.gif)
53
+ -->
54
+
55
+ ```text
56
+ ____ _ _ ___ _
57
+ / ___(_) |_ / _ \ _ _ ___ ___| |_
58
+ | | _| | __| | | | | | |/ _ \/ __| __|
59
+ | |_| | | |_| |_| | |_| | __/\__ \ |_
60
+ \____|_|\__|\__\_\\__,_|\___||___/\__|
61
+
62
+ Your commits. Your dungeon. Your legend.
63
+
64
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Room 2/5 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
65
+ โ”‚ fix: bug in output handling โ”‚
66
+ โ”‚ 33b27d3 ยท +2/-0 ยท a tight crawlspace of tangled diffs โ”‚
67
+ โ”‚ ๐Ÿง™ You meet Ada Lovelace, an ally from this commit. โ”‚
68
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
69
+ ๐Ÿง  Skill XP: +1 Python, +1 JavaScript
70
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ A Bug appears! โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
71
+ โ”‚ (>_<) โ”‚
72
+ โ”‚ Off-by-One โ”‚
73
+ โ”‚ HP 11 ยท ATK 4 ยท DEF 0 โ”‚
74
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
75
+ Attack Defend Item(0) Run
76
+ Your move (a): ยป Hero hits Off-by-One for 6 damage.
77
+ โœ” Off-by-One defeated! (+10 XP, +6 gold)
78
+ ```
79
+
80
+ And the grand finale โ€” the shareable **flex card**:
81
+
82
+ ```text
83
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ flex card โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
84
+ โ”‚ โš” GITQUEST CAREER CARD โš” โ”‚
85
+ โ”‚ my-repo seed 17391773614721965407 โ”‚
86
+ โ”‚ โ”‚
87
+ โ”‚ RANK: Senior Crusader โ”‚
88
+ โ”‚ SCORE: 2310 โ”‚
89
+ โ”‚ STATUS: VICTORIOUS โ”‚
90
+ โ”‚ โ”‚
91
+ โ”‚ CAREER STATS โ”‚
92
+ โ”‚ Level 11 Gold 642 โ”‚
93
+ โ”‚ Kills 148 Bosses 12 โ”‚
94
+ โ”‚ SKILL TREE โ”‚
95
+ โ”‚ Python โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 220 โ”‚
96
+ โ”‚ TypeScript โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 130 โ”‚
97
+ โ”‚ Specialization: Python ยท 6 skill paths explored โ”‚
98
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
99
+ ```
100
+
101
+ ---
102
+
103
+ ## ๐Ÿš€ Install
104
+
105
+ The zero-friction way (isolated, recommended):
106
+
107
+ ```bash
108
+ pipx install gitquest
109
+ ```
110
+
111
+ Or with pip:
112
+
113
+ ```bash
114
+ pip install gitquest
115
+ ```
116
+
117
+ From source:
118
+
119
+ ```bash
120
+ git clone https://github.com/jithin-jz/gitquest
121
+ cd gitquest
122
+ pip install .
123
+ ```
124
+
125
+ ---
126
+
127
+ ## ๐ŸŽฎ Play
128
+
129
+ Run it inside any git repository โ€” no arguments needed:
130
+
131
+ ```bash
132
+ gitquest
133
+ ```
134
+
135
+ `python -m gitquest` works too.
136
+
137
+ ### Flags
138
+
139
+ | Flag | Description |
140
+ | ---------------- | --------------------------------------------------------- |
141
+ | `--path <repo>` | Play on another repository (default: current directory). |
142
+ | `--seed <n>` | Force a specific dungeon seed (default: derived from repo).|
143
+ | `--fast` | Skip animations and "press Enter" pauses. |
144
+ | `--stats-only` | Skip gameplay and print just the flex card. |
145
+ | `--max-commits` | Cap/sample commits for huge repos (default: 300). |
146
+ | `--version` | Print the version. |
147
+
148
+ Examples:
149
+
150
+ ```bash
151
+ gitquest --path ../some-other-repo
152
+ gitquest --seed 42 --fast
153
+ gitquest --stats-only # instant career card, no fighting
154
+ ```
155
+
156
+ ---
157
+
158
+ ## ๐Ÿง  How it works
159
+
160
+ `gitquest` maps real repository data onto game mechanics:
161
+
162
+ | Git data | Becomesโ€ฆ |
163
+ | ------------------------------------- | ----------------------------------------------- |
164
+ | **Commit** | A room in the dungeon |
165
+ | **Lines added/removed** | Room size + monster difficulty |
166
+ | **Merge commit** | A mini-boss room |
167
+ | **Files changed** | Loot/items in the room |
168
+ | **Commit author** | An ally/NPC you meet |
169
+ | **Languages (by file extension)** | Your skill tree / XP categories |
170
+ | **Message keywords** | Enemy types (`fix` โ†’ Bug, `feat` โ†’ Featureโ€ฆ) |
171
+ | **Total repo stats** | Your final rank (e.g. *Senior Crusader*) |
172
+
173
+ ### Determinism
174
+
175
+ The dungeon seed is derived from the SHA of the repository's **first commit**
176
+ (unless you pass `--seed`). All procedural generation โ€” monster names, stats,
177
+ loot rolls, room sizes โ€” flows from that single seed via a `random.Random`
178
+ instance with a fixed call order. The result: identical, reproducible dungeons
179
+ that you and a teammate can compare.
180
+
181
+ ### Architecture
182
+
183
+ ```
184
+ gitquest/
185
+ cli.py # entry point + argument parsing (argparse)
186
+ git_parser.py # extract & normalize commit data (GitPython + git CLI fallback)
187
+ generator.py # commit data -> dungeon/rooms/monsters (seeded)
188
+ engine.py # game loop, state, turn handling
189
+ combat.py # combat math (pure, rng-driven, testable)
190
+ entities.py # Player, Monster, Room, Item, Dungeon dataclasses
191
+ renderer.py # all rich-based rendering
192
+ flexcard.py # final shareable stats card + ranking
193
+ data/ # monster/item name lists, ranks, ascii art
194
+ tests/ # pytest: parser, generator determinism, combat
195
+ ```
196
+
197
+ Everything runs **locally and offline** โ€” no network calls, ever.
198
+
199
+ ---
200
+
201
+ ## ๐Ÿ› ๏ธ Development
202
+
203
+ ```bash
204
+ pip install -e ".[dev]"
205
+ pytest
206
+ ```
207
+
208
+ Tests cover history parsing, generator **determinism**, and combat logic.
209
+
210
+ ### Edge cases handled
211
+
212
+ - Not a git repository โ†’ friendly error, no traceback.
213
+ - Empty history / no commits โ†’ friendly nudge to commit first.
214
+ - Huge repos โ†’ evenly down-sampled to `--max-commits` (still deterministic).
215
+ - Missing `GitPython` โ†’ automatic fallback to the `git` CLI.
216
+
217
+ ---
218
+
219
+ ## ๐Ÿค Contributing
220
+
221
+ Issues and PRs welcome! Ideas: more monster archetypes, a `textual` dungeon map,
222
+ achievements, or exporting the flex card as an image.
223
+
224
+ ## ๐Ÿ“„ License
225
+
226
+ MIT โ€” see [`LICENSE`](LICENSE).
@@ -0,0 +1,198 @@
1
+ # gitquest ๐Ÿ—ก๏ธ
2
+
3
+ > **Your commits. Your dungeon. Your legend.**
4
+ > Turn any git repository's history into a procedurally generated, playable
5
+ > ASCII dungeon roguelike โ€” right in your terminal.
6
+
7
+ `gitquest` reads your repo's real commit history and deterministically builds a
8
+ dungeon from it. Each commit becomes a room. Bug-fix commits spawn bugs. Merge
9
+ commits become mini-bosses. The languages you've coded fill your skill tree.
10
+ Clear every room from the repo's first commit to `HEAD`, then flex your career
11
+ on a shareable stats card.
12
+
13
+ **Same repo + same seed = the same dungeon, every time.** Reproducible and
14
+ shareable.
15
+
16
+ ---
17
+
18
+ ## โœจ Demo
19
+
20
+ <!--
21
+ ๐Ÿ“ฝ๏ธ ANIMATED GIF PLACEHOLDER
22
+ Drop a terminal recording here (e.g. via `asciinema` + `agg`, or a screen GIF).
23
+ Recommended: a ~20s clip of a fight + the final flex card.
24
+ ![gitquest demo](docs/demo.gif)
25
+ -->
26
+
27
+ ```text
28
+ ____ _ _ ___ _
29
+ / ___(_) |_ / _ \ _ _ ___ ___| |_
30
+ | | _| | __| | | | | | |/ _ \/ __| __|
31
+ | |_| | | |_| |_| | |_| | __/\__ \ |_
32
+ \____|_|\__|\__\_\\__,_|\___||___/\__|
33
+
34
+ Your commits. Your dungeon. Your legend.
35
+
36
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Room 2/5 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
37
+ โ”‚ fix: bug in output handling โ”‚
38
+ โ”‚ 33b27d3 ยท +2/-0 ยท a tight crawlspace of tangled diffs โ”‚
39
+ โ”‚ ๐Ÿง™ You meet Ada Lovelace, an ally from this commit. โ”‚
40
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
41
+ ๐Ÿง  Skill XP: +1 Python, +1 JavaScript
42
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ A Bug appears! โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
43
+ โ”‚ (>_<) โ”‚
44
+ โ”‚ Off-by-One โ”‚
45
+ โ”‚ HP 11 ยท ATK 4 ยท DEF 0 โ”‚
46
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
47
+ Attack Defend Item(0) Run
48
+ Your move (a): ยป Hero hits Off-by-One for 6 damage.
49
+ โœ” Off-by-One defeated! (+10 XP, +6 gold)
50
+ ```
51
+
52
+ And the grand finale โ€” the shareable **flex card**:
53
+
54
+ ```text
55
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ flex card โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
56
+ โ”‚ โš” GITQUEST CAREER CARD โš” โ”‚
57
+ โ”‚ my-repo seed 17391773614721965407 โ”‚
58
+ โ”‚ โ”‚
59
+ โ”‚ RANK: Senior Crusader โ”‚
60
+ โ”‚ SCORE: 2310 โ”‚
61
+ โ”‚ STATUS: VICTORIOUS โ”‚
62
+ โ”‚ โ”‚
63
+ โ”‚ CAREER STATS โ”‚
64
+ โ”‚ Level 11 Gold 642 โ”‚
65
+ โ”‚ Kills 148 Bosses 12 โ”‚
66
+ โ”‚ SKILL TREE โ”‚
67
+ โ”‚ Python โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ 220 โ”‚
68
+ โ”‚ TypeScript โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ 130 โ”‚
69
+ โ”‚ Specialization: Python ยท 6 skill paths explored โ”‚
70
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
71
+ ```
72
+
73
+ ---
74
+
75
+ ## ๐Ÿš€ Install
76
+
77
+ The zero-friction way (isolated, recommended):
78
+
79
+ ```bash
80
+ pipx install gitquest
81
+ ```
82
+
83
+ Or with pip:
84
+
85
+ ```bash
86
+ pip install gitquest
87
+ ```
88
+
89
+ From source:
90
+
91
+ ```bash
92
+ git clone https://github.com/jithin-jz/gitquest
93
+ cd gitquest
94
+ pip install .
95
+ ```
96
+
97
+ ---
98
+
99
+ ## ๐ŸŽฎ Play
100
+
101
+ Run it inside any git repository โ€” no arguments needed:
102
+
103
+ ```bash
104
+ gitquest
105
+ ```
106
+
107
+ `python -m gitquest` works too.
108
+
109
+ ### Flags
110
+
111
+ | Flag | Description |
112
+ | ---------------- | --------------------------------------------------------- |
113
+ | `--path <repo>` | Play on another repository (default: current directory). |
114
+ | `--seed <n>` | Force a specific dungeon seed (default: derived from repo).|
115
+ | `--fast` | Skip animations and "press Enter" pauses. |
116
+ | `--stats-only` | Skip gameplay and print just the flex card. |
117
+ | `--max-commits` | Cap/sample commits for huge repos (default: 300). |
118
+ | `--version` | Print the version. |
119
+
120
+ Examples:
121
+
122
+ ```bash
123
+ gitquest --path ../some-other-repo
124
+ gitquest --seed 42 --fast
125
+ gitquest --stats-only # instant career card, no fighting
126
+ ```
127
+
128
+ ---
129
+
130
+ ## ๐Ÿง  How it works
131
+
132
+ `gitquest` maps real repository data onto game mechanics:
133
+
134
+ | Git data | Becomesโ€ฆ |
135
+ | ------------------------------------- | ----------------------------------------------- |
136
+ | **Commit** | A room in the dungeon |
137
+ | **Lines added/removed** | Room size + monster difficulty |
138
+ | **Merge commit** | A mini-boss room |
139
+ | **Files changed** | Loot/items in the room |
140
+ | **Commit author** | An ally/NPC you meet |
141
+ | **Languages (by file extension)** | Your skill tree / XP categories |
142
+ | **Message keywords** | Enemy types (`fix` โ†’ Bug, `feat` โ†’ Featureโ€ฆ) |
143
+ | **Total repo stats** | Your final rank (e.g. *Senior Crusader*) |
144
+
145
+ ### Determinism
146
+
147
+ The dungeon seed is derived from the SHA of the repository's **first commit**
148
+ (unless you pass `--seed`). All procedural generation โ€” monster names, stats,
149
+ loot rolls, room sizes โ€” flows from that single seed via a `random.Random`
150
+ instance with a fixed call order. The result: identical, reproducible dungeons
151
+ that you and a teammate can compare.
152
+
153
+ ### Architecture
154
+
155
+ ```
156
+ gitquest/
157
+ cli.py # entry point + argument parsing (argparse)
158
+ git_parser.py # extract & normalize commit data (GitPython + git CLI fallback)
159
+ generator.py # commit data -> dungeon/rooms/monsters (seeded)
160
+ engine.py # game loop, state, turn handling
161
+ combat.py # combat math (pure, rng-driven, testable)
162
+ entities.py # Player, Monster, Room, Item, Dungeon dataclasses
163
+ renderer.py # all rich-based rendering
164
+ flexcard.py # final shareable stats card + ranking
165
+ data/ # monster/item name lists, ranks, ascii art
166
+ tests/ # pytest: parser, generator determinism, combat
167
+ ```
168
+
169
+ Everything runs **locally and offline** โ€” no network calls, ever.
170
+
171
+ ---
172
+
173
+ ## ๐Ÿ› ๏ธ Development
174
+
175
+ ```bash
176
+ pip install -e ".[dev]"
177
+ pytest
178
+ ```
179
+
180
+ Tests cover history parsing, generator **determinism**, and combat logic.
181
+
182
+ ### Edge cases handled
183
+
184
+ - Not a git repository โ†’ friendly error, no traceback.
185
+ - Empty history / no commits โ†’ friendly nudge to commit first.
186
+ - Huge repos โ†’ evenly down-sampled to `--max-commits` (still deterministic).
187
+ - Missing `GitPython` โ†’ automatic fallback to the `git` CLI.
188
+
189
+ ---
190
+
191
+ ## ๐Ÿค Contributing
192
+
193
+ Issues and PRs welcome! Ideas: more monster archetypes, a `textual` dungeon map,
194
+ achievements, or exporting the flex card as an image.
195
+
196
+ ## ๐Ÿ“„ License
197
+
198
+ MIT โ€” see [`LICENSE`](LICENSE).
@@ -0,0 +1,9 @@
1
+ """gitquest - Turn your git commit history into a playable ASCII dungeon roguelike.
2
+
3
+ Same repo + same seed = same dungeon. Explore rooms generated from real
4
+ commits, fight keyword-spawned monsters, gain language XP, and finish with a
5
+ shareable career flex card.
6
+ """
7
+
8
+ __version__ = "0.1.0"
9
+ __all__ = ["__version__"]
@@ -0,0 +1,8 @@
1
+ """Enable ``python -m gitquest`` to launch the game."""
2
+
3
+ import sys
4
+
5
+ from .cli import main
6
+
7
+ if __name__ == "__main__":
8
+ sys.exit(main())
@@ -0,0 +1,149 @@
1
+ """Command-line entry point and argument parsing for gitquest.
2
+
3
+ Step 1 (scaffold): wires up argument parsing and prints a placeholder banner so
4
+ ``gitquest`` and ``python -m gitquest`` both work. Later build steps replace the
5
+ placeholder with the real game loop.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import os
12
+ import sys
13
+
14
+ from . import __version__
15
+
16
+ BANNER = r"""
17
+ ____ _ _ ___ _
18
+ / ___(_) |_ / _ \ _ _ ___ ___| |_
19
+ | | _| | __| | | | | | |/ _ \/ __| __|
20
+ | |_| | | |_| |_| | |_| | __/\__ \ |_
21
+ \____|_|\__|\__\_\\__,_|\___||___/\__|
22
+
23
+ Your commits. Your dungeon. Your legend.
24
+ """
25
+
26
+
27
+ def build_parser() -> argparse.ArgumentParser:
28
+ """Construct the argument parser for the ``gitquest`` command."""
29
+ parser = argparse.ArgumentParser(
30
+ prog="gitquest",
31
+ description="Turn your git commit history into a playable ASCII dungeon roguelike.",
32
+ formatter_class=argparse.RawDescriptionHelpFormatter,
33
+ epilog=(
34
+ "examples:\n"
35
+ " gitquest play on the current repo\n"
36
+ " gitquest --path ../repo play on another repo\n"
37
+ " gitquest --seed 42 force a specific dungeon seed\n"
38
+ " gitquest --stats-only skip the dungeon, just show the flex card\n"
39
+ ),
40
+ )
41
+ parser.add_argument(
42
+ "--path",
43
+ default=".",
44
+ metavar="REPO",
45
+ help="path to the git repository to play (default: current directory)",
46
+ )
47
+ parser.add_argument(
48
+ "--seed",
49
+ type=int,
50
+ default=None,
51
+ metavar="N",
52
+ help="override the procedural-generation seed (default: derived from repo)",
53
+ )
54
+ parser.add_argument(
55
+ "--fast",
56
+ action="store_true",
57
+ help="skip animations and typewriter effects",
58
+ )
59
+ parser.add_argument(
60
+ "--stats-only",
61
+ action="store_true",
62
+ help="skip gameplay and print only the final flex card",
63
+ )
64
+ parser.add_argument(
65
+ "--max-commits",
66
+ type=int,
67
+ default=300,
68
+ metavar="N",
69
+ help="cap/sample commits for very large repos (default: 300)",
70
+ )
71
+ parser.add_argument(
72
+ "--version",
73
+ action="version",
74
+ version=f"gitquest {__version__}",
75
+ )
76
+ return parser
77
+
78
+
79
+ def main(argv: list[str] | None = None) -> int:
80
+ """Entry point. Parses args and runs gitquest.
81
+
82
+ Returns a process exit code.
83
+ """
84
+ parser = build_parser()
85
+ args = parser.parse_args(argv)
86
+
87
+ # Imports are local so ``--help``/``--version`` stay fast and dependency-light.
88
+ import random
89
+
90
+ from rich.console import Console
91
+ from rich.text import Text
92
+
93
+ from .engine import GameEngine
94
+ from .entities import Player
95
+ from .flexcard import render_flexcard
96
+ from .generator import generate_dungeon
97
+ from .git_parser import (
98
+ EmptyHistoryError,
99
+ NotAGitRepoError,
100
+ parse_repo,
101
+ )
102
+ from .renderer import Renderer
103
+
104
+ console = Console()
105
+
106
+ # --- Parse the repository --------------------------------------------- #
107
+ try:
108
+ repo = parse_repo(args.path, max_commits=args.max_commits)
109
+ except NotAGitRepoError:
110
+ console.print(
111
+ f"[bold red]โœ— {os.path.abspath(args.path)} is not a git repository.[/bold red]\n"
112
+ "[grey62]Run gitquest from inside a repo, or pass --path <repo>.[/grey62]"
113
+ )
114
+ return 2
115
+ except EmptyHistoryError:
116
+ console.print(
117
+ "[bold red]โœ— This repository has no commits yet.[/bold red]\n"
118
+ "[grey62]Make a commit and try again โ€” every legend starts somewhere.[/grey62]"
119
+ )
120
+ return 2
121
+ except Exception as exc: # pragma: no cover - defensive
122
+ console.print(f"[bold red]โœ— Failed to read repository:[/bold red] {exc}")
123
+ return 1
124
+
125
+ # --- Generate the dungeon --------------------------------------------- #
126
+ dungeon = generate_dungeon(repo, user_seed=args.seed)
127
+ player = Player(name=repo.head.author_name or "Hero")
128
+
129
+ # --- Stats-only: silent auto run, then just the flex card ------------- #
130
+ if args.stats_only:
131
+ engine = GameEngine(dungeon, player, interactive=False)
132
+ engine.run()
133
+ render_flexcard(player, dungeon, engine.victorious, console=console)
134
+ return 0
135
+
136
+ # --- Full interactive play -------------------------------------------- #
137
+ console.print(Text(BANNER, style="bold green"))
138
+ renderer = Renderer(console=console, fast=args.fast)
139
+ rng = random.Random(dungeon.seed ^ 0x5EED)
140
+ engine = GameEngine(dungeon, player, renderer=renderer, rng=rng, interactive=True)
141
+ engine.run()
142
+
143
+ render_flexcard(player, dungeon, engine.victorious, console=console)
144
+ return 0
145
+
146
+
147
+
148
+ if __name__ == "__main__":
149
+ sys.exit(main())