Advance Web Dev project, Card-Jitsu simulator
Card-Jitsu is a simple but strategic card game from Club Penguin.
Players battle using cards based on three elements
- Fire
- Water
- Grass
- Elements follow rock-paper-scissors logic
- Fire beats Grass
- Grass beats Water
- Water beats Fire
- If both cards are the same element, the higher power number wins
- Players reveal cards simultaneously
- Games proceed through multiple rounds
- A match ends when one player gets either
- A player wins a round with each type of element
- A player wins 3 rounds with different colors of the same element
This application recreates the Card-jitsu experience as a full-stack web app using:
- Python Flask for backend and API
- SQLAlchemy ORM
- JWT Authentication for a secure login
- Some External API
- HTML forms for a simple UI
You can either open the website at the link we provided in the submission
or
You can clone the repo, create a venv, and run
pip install -r requirements.txtto install the libraries
Then you can run
python app.pyin the root directory
The Style is Monolithic
- User enters username, email, password
- Password is hased before storage
- System
- creates a User
- assigns 30 random cards (UserCard rows)
- creates an empty Deck
- User logs in with username + password
- Backend verifies the hash
- Backend returns a JWT token for authenticated requests
Endpoint: GET api/user/cards
- User sees their 30 assigned cards
- User selects 25 of their 30 cards
- Simple interface
- Each card displayed with:
- element
- power
- colour
- "Select"/"Deselect" button
- Backend validates:
- exactly 25 cards
- all belong to the user
- Then updates DeckCard rows
User enters a room code
Player 1 creates room
POST api/rooms
Player 2 joins room
POST api/rooms/join
Room moves to active status
Each Round:
- Both Players send POST api/rooms/<room>/play{"card_id":123}
- When boths moves are in:
- Backend compares element & power
- Determines winner using the rules from above
- Stores the round in Move
- Scores update
- When match ends:
- Room.winner_id filled
- Status becomes finished
| Attribute | Type | Description |
|---|---|---|
| id | int | Primary Key |
| username | str | Unique username |
| password_hash | str | Hashed password |
Relationships:
- decks, the users decks
- user_cards, the 30 base cards assigned at registration
- rooms_as_p1, rooms_as_p2, rooms they are participating in
| Attribute | Type | Description |
|---|---|---|
| id | int | Primary Key |
| element | str | "fire","water","grass" |
| power | int | 1-12 |
| colour | str | "red", "blue", "yellow", "green", "purple", "orange" |
| name | str | "fire 12 blue" |
These cards form the global card pool. User recieve 30 random ones
| Attribute | Type |
|---|---|
| id | int |
| user_id | Foreign Key -> User |
| card_id | Foreign Key -> Card |
This determines which card a user can place in a deck
| Attribute | Type |
|---|---|
| id | int |
| user_id | Foreign Key -> User |
| name | str |
| is_active | bool |
| created_at | DateTime |
A deck of exactly 25 chosen cards
| Attribute | Type |
|---|---|
| id | int |
| deck_id | Foreign Key -> Deck |
| card_id | Foreign Key -> Card |
| Attribute | Type | Description |
|---|---|---|
| id | int | Primary Key |
| room_code | str | Code users enter to join |
| player1_id | Foreign Key -> User | First Player |
| player2_id | Foreign Key -> User | Second Player |
| status | str | "waiting","active", "finished" |
| winner_id | Foreign Key -> User | Winner of match |
| Attribute | Type |
|---|---|
| id | int |
| room_id | Foreign Key -> Room |
| round_number | int |
| player1_card_id | Foreign Key -> Card |
| player2_card_id | Foreign Key -> Card |
| resolved | bool |
| winner_user_id | Foreign Key -> User |
Our testing strategy combines unit test, integration tests, and end to end tests to verify core functionality. We used pytest for automated backend testinf and Selenium for browser bases end to end testinf. The goal was not exhaustive coverage, but to ensure that critical features (game rules, authentication, and user stats) behave correctly.
In the file test_game_logic.py we have 3 unit tests
- test_compare_cards_fire_beats_grass: this ensures that the elemental rules correctly give fire a win over grass when power is equal or advantage applies
- test_compate_cards_grass_beats_water: this is similar to the last one but with grass and water
- test_has_club_penguin_win_three_same_element_diff_colours: checks that the win condition is triggered when a player has three cards of the same element with three different colours.
In the file test_api_flow.py we have 1 integration test
It calls /api/register and registers a user, then calls /api/login to login with that same user and obtains a JWT, uses the token to access /api/me, and then confirms the win_count and total_games are changed correctly.
python -m pytestThe Selenium test is in the file test_login_flow.py .
run_login_flow:
- Opens the real
/loginpage in a browser - Enter credentials for the user that was already created in that browser
- Submits the form and waits for the redirect
- Verifies that the page title corresponds to the home page and that the main heading and the button are visible.
- This validates the full path from frontend form ->
/api/login-> homepage UI.
The app must already be running and you must register the user 'Aradtesting' with the password 'test'
#Terminal 1
python app.py
#Terminal 2
python selenium_tests/test_login_flow.py# Run unit + Integration tests
python -m pytest
# Run Selenium End to End tests (with app running)
python selenium_tests/test_login_flow.pyThis project is fully containerized using Docker to ensure consistent execution across different environments
docker build -t cardjitsu .docker run -p 5000:5000 cardjitsuContainerization solves:
- "Works on my machine" problems
- OS & dependency inconsistencies
- Environment replication fro testing and deployment
This application runs inside a stable Python 3.12-slim container regardless of the host system.
This project uses a GitHub Actions CI workflow that runs automatically on every push or pull request to main.
The Workflow performs the following steps
- Installs dependencies
- Runs linting
- Executes autmated pytest unit & integration tests
- Ensures that the build remains stable before merging
If tests fail, GitHub prevents merging changes into the main branch
This application is designed to be deployed on a Linux server using Docker
git pull
docker build -t cardjitsu .
docker stop cardjitsu || true
docker rm cardjitsu || true
docker run -d --name cardjitsu -p 5000:5000 cardjitsu- Developer pushes code to GitHub
- CI pipeline runs tests
- If all tests pass -> merge to main
- Server pulls latest code
- Docker rebuilds & restarts container
- Updated app goes live
This ensures safe deployments, predictable environments, repeatable builds, and confident iteration velocity

