Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-tests.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Python package
name: WHOT Tests

on:
push:
Expand Down
3 changes: 3 additions & 0 deletions examples/whot-web/.env-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ADDRESS=127.0.0.1
PORT=8080
WEBSOCKET_PORT=8765
78 changes: 78 additions & 0 deletions examples/whot-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Web Whot

A web-based implementation of **Whot**. With Web Whot, you can play the game over any network. Just create a game and share the link with another player.

> Currently supports **two players per game**.

## Technologies Used

This project is built using simple, lightweight technologies:

**Client:**

* HTML
* Vanilla JavaScript
* CSS

**Communication:**

* HTTP
* WebSocket (for real-time updates)

**Server:**

* [aiohttp](https://github.com/aio-libs/aiohttp) – HTTP framework for Python
* [whot](https://github.com/EteimZ/whot) – Whot engine that powers the logic

## Getting Started

### 1. Clone the Game Engine

Start by cloning the [`whot`](https://github.com/EteimZ/whot) repository:

```bash
git clone https://github.com/EteimZ/whot.git
cd whot/examples/whot-web
```

### 2. Set Up Your Environment

Make sure you have **Python 3.11+** installed.

(Optional) Create and activate a virtual environment:

```bash
python -m venv env
source env/bin/activate
```

### 3. Install Dependencies

```bash
pip install -r requirements.txt
```

### 4. Configure Environment Variables

Create a `.env` file in the root of the project and define the following variables:

```dotenv
ADDRESS=127.0.0.1
PORT=8080
WEBSOCKET_PORT=8765
```

`ADDRESS` should be your local or network IP address.
`PORT` is for the HTTP server.
`WEBSOCKET_PORT` is for WebSocket communication.

## Running the App

Start the application with:

```bash
python main.py
```

Visit `http://<ADDRESS>:<PORT>` in your browser and start playing.

61 changes: 61 additions & 0 deletions examples/whot-web/html/game.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/game.css" />
<title>Whot Game</title>
</head>

<body>

<div class="game-layout">
<div class="spacer"></div>

<div id="board">
<div id="opponent_cards"></div>

<div id="middle_area">
<div id="middle_card">
<img id="card_top" src="assets/images/whot_back.png" alt="" width="100" height="120" />
</div>
<div id="market">
<img src="assets/images/whot_back.png" alt="" width="100" height="120" />
</div>
</div>

<div id="player_cards"></div>
</div>

<div id="sidebar">
<div class="status-container">
<p id="current_player" class="status-label">Current Player:</p>
<p id="player_id" class="status-label">Player ID:</p>
</div>
<div id="join_link_container" style="display: none;"></div>
</div>
</div>

<!-- Modal for Request Suits -->
<div id="suitModal" class="modal">
<div class="modal-content">
<p class="modal-title">What do you need?</p>
<div class="modal-buttons">
<button id="circle" class="suit-btn">Circle</button>
<button id="square" class="suit-btn">Square</button>
<button id="star" class="suit-btn">Star</button>
<button id="cross" class="suit-btn">Cross</button>
<button id="triangle" class="suit-btn">Triangle</button>
</div>
</div>
</div>

<script>
const WEBSOCKET_URL = "{{ websocket_url }}";
</script>
<script src="./js/script.js"></script>

</body>

</html>
48 changes: 48 additions & 0 deletions examples/whot-web/html/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="./css/index.css">
<title>Whot Game</title>
</head>
<body>
<h1>Create Whot Game</h1>
<p class="description">Play Whot with your friends by starting or joining a game using a link</p>
<div class="actions">
<a href="/game" class="btn-primary"> New Game</a>

<div class="input-container">
<input type="text" id="game_id" name="game_id" placeholder="Enter Game ID" oninput="toggleJoinButton()" />
<button id="joinBtn" class="join" disabled>Join</button>
</div>
</div>

<script>
const gameIdInput = document.getElementById('game_id');
const joinButton = document.getElementById('joinBtn');

joinButton.addEventListener('click', function(event) {
// event.preventDefault();
const gameId = gameIdInput.value.trim();
if (gameId) {
window.location.href = `${window.location.href}game?join=${gameId}`;
} else {
alert('Please enter a valid Game ID.');
}
});

function toggleJoinButton() {
const input = document.getElementById('game_id');
const button = document.getElementById('joinBtn');
if (input.value.trim()) {
button.disabled = false;
button.classList.add('enabled');
} else {
button.disabled = true;
button.classList.remove('enabled');
}
}
</script>
</body>
</html>
49 changes: 0 additions & 49 deletions examples/whot-web/index.html

This file was deleted.

49 changes: 37 additions & 12 deletions examples/whot-web/main.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
from aiohttp import web
import asyncio
import os

from aiohttp import web
import aiohttp_jinja2
from dotenv import load_dotenv
import jinja2
from websockets.asyncio.server import serve
from server import handler

PORT = 8080
WEBSOCKET_PORT = 8765
from server import WhotServer

load_dotenv()

ADDRESS = os.environ.get("ADDRESS", "127.0.0.1")
PORT = int(os.environ.get("PORT", 8080))
WEBSOCKET_PORT = int(os.environ.get("WEBSOCKET_PORT", 8765))

# Create an aiohttp web app
app = web.Application()

# Create an instance of the whot server
whot_server = WhotServer()

aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('.'))

# Serve index.html
async def handle_index(request):
return web.FileResponse("index.html")
return web.FileResponse("html/index.html")

async def handle_game(request):
return aiohttp_jinja2.render_template("html/game.html", request, context={
"websocket_url": f"ws://{ADDRESS}:{WEBSOCKET_PORT}"
})

async def handler(websocket):
await whot_server.handle(websocket)

# WebSocket server function
async def websocket_server():
async with serve(handler, "0.0.0.0", WEBSOCKET_PORT):
print(f"WebSocket server running at ws://0.0.0.0:{WEBSOCKET_PORT}")
async with serve(handler, ADDRESS, WEBSOCKET_PORT):
print(f"WebSocket server running at ws://{ADDRESS}:{WEBSOCKET_PORT}")
await asyncio.Future() # Keep the WebSocket server running

# Create an aiohttp web app
app = web.Application()
# Define routes
app.router.add_get("/", handle_index)
app.router.add_static("/", path=".", name="static")
app.router.add_get("/game", handle_game)
app.router.add_static("/", path="static", name="static")

# Function to run the aiohttp server
async def run_server():
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, "0.0.0.0", PORT)
print(f"HTTP server running at http://0.0.0.0:{PORT}")
site = web.TCPSite(runner, ADDRESS, PORT)
print(f"HTTP server running at http://{ADDRESS}:{PORT}")
await site.start()
await asyncio.Future() # Keep running

Expand Down
3 changes: 3 additions & 0 deletions examples/whot-web/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
websockets==13.0.1
aiohttp
whot
python-dotenv
aiohttp-jinja2
Loading