Skip to content

Commit ef77e3a

Browse files
authored
fix: practice mode hp stacking glitch (#68)
* refactor + fix hp stacking * docs: update docs.md * clean code
1 parent e6872de commit ef77e3a

14 files changed

Lines changed: 553 additions & 561 deletions

File tree

.env.example

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ STARTING_MP=100
7171
MANA_RECHARGE=50
7272

7373
# Unranked Problem Distribution #
74-
UNRANKED_PROBS="0.8, 0.19, 0.01"
74+
UNRANKED_PROBS="0.4, 0.3, 0.3"
7575

7676
# HP Deduction Settings
7777
HP_DEDUCTION_BASE=4
@@ -81,15 +81,15 @@ HP_MULTIPLIER="1.0, 1.5, 2.0"
8181
RATING_K_FACTOR=32
8282
RANK_THRESHOLDS="0, 100, 200, 500, 1200, 1600, 2400"
8383
RANK_NAMES="O(n!), O(2ⁿ), O(n²), O(nlogn), O(n), O(logn), O(1)"
84-
RANK_PROBLEM_DISTRIBUTION="3-0-0, 2-1-0, 1-2-0, 0-3-0, 0-2-1, 0-1-2, 0-0-3"
84+
RANK_PROBLEM_DISTRIBUTION="3-0-0, 2-1-0, 1-2-0, 0-3-0, 0-2-1, 0-1-2, 0-0-3" # Only 3 problems per match
8585

8686
### Custom Room Settings ###
8787
ROOM_CODE_LENGTH=6
8888
ROOM_PROBLEM_COUNT=3
8989
ROOM_STARTING_HP=100
9090
ROOM_HP_MULTIPLIER="1.0, 1.5, 2.0"
9191
ROOM_DISTRIBUTION="auto"
92-
ROOM_PROBLEM_DISTRIBUTION="0.8, 0.19, 0.01"
92+
ROOM_PROBLEM_DISTRIBUTION="0.4, 0.3, 0.3"
9393
ROOM_UPDATE_THROTTLE=0
9494
ROOM_BASE_HP_DEDUCTION=4
9595
ROOM_STARTING_SP=100
@@ -112,4 +112,4 @@ PRACTICE_THINKING_TIME=30
112112
BOT_THINKING_MULTIPLIER="1.0, 2.0, 3.0"
113113
BOT_ACTION_INTERVAL_MULTIPLIER="1.2, 1.0, 0.7"
114114
BOT_DAMAGE_MULTIPLIER="0.8, 1.0, 1.2"
115-
BOT_ABILITY_USE_CHANCE="0.5, 0.4, 0.3"
115+
BOT_ABILITY_USE_CHANCE="0.5, 0.4, 0.3"

DOCS.md

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
### General Notes
44
⚠️ FastAPI automatically generates Swagger-style documentation at /docs for all the HTTP endpoints (no WebSockets).
55

6-
⚠️ The default API endpoint starts with `/api` (after your host address)
6+
⚠️ The default API endpoint starts with `/api` (after your host address)
77

88
⚠️ The URL suffix matters! When connecting to HTTP endpoints you'll use `http://` but whe connecting to WS endpoints you'll use `ws://`. The secure version of these protocols are `https://` and `wss://`, respectively.
99

@@ -38,7 +38,7 @@ ALTERNATIVELY: Send a POST request to `/api/users/guest` to get `access_token` a
3838
1. To start queueing for a match, join the WebSocket endpoint `/game/queue` (unranked) or `/game/ranked-queue` (ranked).
3939
- These two are pretty much the same, except ranked games are matched based on rating proximity and give rating changes.
4040
- The problems distribution in unranked matches are based on appearance chances, but in ranked the distribution of problemsare predetermined (check .env settings)
41-
2. Once a match is found, a WebSocket JSON object of `type: "match_found"` will be sent to you. Inside `data` includes information like your `"match_id"` and opponent details.
41+
2. Once a match is found, a WebSocket JSON object of `type: "match_found"` will be sent to you. Inside `data` includes information like your `"match_id"` and opponent details.
4242
3. Use the mentioned `"match_id"` to connect to the WebSocket of the game e.g. `/game/play/{match_id}`
4343
4. While inside the game websocket, here are the messages you'll receive:
4444
- `type: "game_state"`: sent on join/query; contains information about the current state of the game (you and your opponent)
@@ -52,7 +52,7 @@ ALTERNATIVELY: Send a POST request to `/api/users/guest` to get `access_token` a
5252
- `code: string`: your code string (includes boilerplate)
5353
- `lang: 'python' | 'java' | 'cpp'`: your code's language
5454
- `type: "forfeit"`: used to forfeit the match
55-
- `type: "query"`: used to fetch current match data.
55+
- `type: "query"`: used to fetch current match data.
5656
- `type: "ability"`: used to signal a buy/use of abilities. Inside your `"data"` property:
5757
- `action: string`: either `buy` or `use`
5858
- `ability_id: string`: the ID string of the ability
@@ -87,6 +87,12 @@ ALTERNATIVELY: Send a POST request to `/api/users/guest` to get `access_token` a
8787
- `type: "chat"`: used to send a message to your opponent in the room. Inside your `"data"` property:
8888
- `message: string`: the message you want to send
8989

90+
#### 9. Practice Mode
91+
1. Connect to practice mode WebSocket at `/practice`.
92+
2. You will receive the same JSON objects as in the [Game Mode](#4-matchmaking-and-game-flow)
93+
3. Additional JSON objects you can send:
94+
- `type: "change_bot_difficulty"`: change the difficulty of the bot ("easy", "medium", "hard") in `"difficulty"` field inside `"data"`.
95+
9096
⚠️ Both players will still remain in the room while in-match.
91-
⚠️ Disconnection from the room WebSocket counts as leaving the room.
92-
> Hence it is advised the frontend keeps the room WebSocket alive during game as well and have the players return to the room screen after finishing the match e.g. `"match_end"` event
97+
⚠️ Disconnection from the room WebSocket counts as leaving the room.
98+
> Hence it is advised the frontend keeps the room WebSocket alive during game as well and have the players return to the room screen after finishing the match e.g. `"match_end"` event

app/api/endpoints/game/websockets.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,6 @@ async def game_websocket(
206206
{"type": "game_state", "data": game_view.model_dump()}
207207
)
208208

209-
# Send the current problem if the game is in progress
210209
if (
211210
game_state.status == GameStatus.IN_PROGRESS
212211
and player.current_problem_index < len(game_state.problems)
@@ -216,7 +215,6 @@ async def game_websocket(
216215
)
217216
await websocket.send_json({"type": "problem", "data": current_problem})
218217

219-
# Start the game if both players are connected and the game is waiting
220218
opponent = game_state.get_opponent_state(current_user.id)
221219
if opponent and opponent.ws and game_state.status == GameStatus.WAITING:
222220
game_state.status = GameStatus.IN_PROGRESS
@@ -231,7 +229,6 @@ async def game_websocket(
231229
try:
232230
data = await asyncio.wait_for(websocket.receive_json(), timeout=1.0)
233231

234-
# No longer accept messages if the game is finished
235232
if game_state.status == GameStatus.FINISHED:
236233
break
237234

@@ -258,6 +255,9 @@ async def game_websocket(
258255
)
259256

260257
elif data["type"] == "query":
258+
game_view = game_manager.create_game_view(
259+
game_state, current_user.id
260+
)
261261
await websocket.send_json(
262262
{"type": "game_state", "data": game_view.model_dump()}
263263
)
@@ -269,7 +269,6 @@ async def game_websocket(
269269
submission_cooldown = (
270270
settings.SUBMISSION_COOLDOWN if not settings.TESTING else 2
271271
)
272-
# Check if the player is submitting too fast
273272
if (
274273
player.last_submission is not None
275274
and current_time - player.last_submission < submission_cooldown
@@ -341,7 +340,6 @@ async def game_websocket(
341340
)
342341
)
343342

344-
# Send the next problem if the current one was solved
345343
if (
346344
submission_result["problem_solved"]
347345
and problem_index < len(game_state.problems) - 1
@@ -356,7 +354,6 @@ async def game_websocket(
356354
if await game_manager.check_game_end(game_id):
357355
await game_manager.handle_game_end(game_state, db)
358356
else:
359-
# Submission failed, send the result to the player
360357
await player.send_event(
361358
GameEvent(type="submission_result", data=result)
362359
)

0 commit comments

Comments
 (0)