Загрузка данных
```txt
========================
requirements.txt
========================
fastapi
uvicorn
jinja2
websockets
python-multipart
========================
main.py
========================
from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
import random
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
players = []
connections = []
roles = {}
WORDS = [
"Airport",
"School",
"Hospital",
"Bank",
"Hotel"
]
@app.get("/", response_class=HTMLResponse)
async def index(request: Request):
return templates.TemplateResponse(
"index.html",
{"request": request}
)
@app.get("/room", response_class=HTMLResponse)
async def room(request: Request, nickname: str):
return templates.TemplateResponse(
"room.html",
{
"request": request,
"nickname": nickname
}
)
@app.websocket("/ws/{nickname}")
async def websocket_endpoint(websocket: WebSocket, nickname: str):
await websocket.accept()
connections.append(websocket)
players.append(nickname)
print(f"{nickname} connected")
try:
while True:
data = await websocket.receive_text()
for connection in connections:
await connection.send_text(f"{nickname}: {data}")
except WebSocketDisconnect:
connections.remove(websocket)
if nickname in players:
players.remove(nickname)
print(f"{nickname} disconnected")
@app.get("/start")
async def start_game():
if len(players) < 2:
return {
"error": "Need at least 2 players"
}
spy = random.choice(players)
location = random.choice(WORDS)
for player in players:
if player == spy:
roles[player] = "SPY"
else:
roles[player] = location
return roles
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"main:app",
host="127.0.0.1",
port=8000,
reload=True
)
========================
database.py
========================
import sqlite3
conn = sqlite3.connect(
"data/skyfall.db"
)
cursor = conn.cursor()
cursor.execute("""
CREATE TABLE IF NOT EXISTS players (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nickname TEXT
)
""")
conn.commit()
conn.close()
========================
templates/index.html
========================
<!DOCTYPE html>
<html>
<head>
<title>SkyFall</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div class="container">
<h1>SKYFALL</h1>
<input type="text" id="nickname" placeholder="Enter nickname">
<button onclick="joinGame()">
Join Game
</button>
</div>
<script>
function joinGame() {
const nickname =
document.getElementById("nickname").value;
if (!nickname) {
alert("Enter nickname");
return;
}
window.location.href =
`/room?nickname=${nickname}`;
}
</script>
</body>
</html>
========================
templates/room.html
========================
<!DOCTYPE html>
<html>
<head>
<title>Game Room</title>
<link rel="stylesheet"
href="/static/style.css">
</head>
<body>
<div class="container">
<h1>Room</h1>
<p>
Player:
<b id="playerName">
{{ nickname }}
</b>
</p>
<button onclick="startGame()">
Start Game
</button>
<div id="roleBox"></div>
<div id="chat"></div>
<input type="text"
id="messageInput"
placeholder="Message">
<button onclick="sendMessage()">
Send
</button>
</div>
<script>
const nickname =
"{{ nickname }}";
const socket =
new WebSocket(
`ws://${location.host}/ws/${nickname}`
);
socket.onmessage = function(event) {
const chat =
document.getElementById("chat");
const div =
document.createElement("div");
div.innerText = event.data;
chat.appendChild(div);
};
function sendMessage() {
const input =
document.getElementById("messageInput");
socket.send(input.value);
input.value = "";
}
async function startGame() {
const response =
await fetch("/start");
const data =
await response.json();
const role =
data[nickname];
const roleBox =
document.getElementById("roleBox");
roleBox.innerHTML =
`<h2>Your Role:</h2>
<h1>${role}</h1>`;
}
</script>
</body>
</html>
========================
static/style.css
========================
body {
background: #111;
color: white;
font-family: Arial;
text-align: center;
}
.container {
margin-top: 60px;
}
input {
padding: 10px;
width: 250px;
margin: 10px;
}
button {
padding: 10px 20px;
background: #00aaff;
border: none;
color: white;
cursor: pointer;
}
#chat {
width: 400px;
height: 300px;
overflow-y: scroll;
border: 1px solid white;
margin: 20px auto;
padding: 10px;
text-align: left;
}
========================
static/app.js
========================
// future scripts
========================
СТРУКТУРА ПАПОК
========================
skyfall-project/
│
├── data/
│ └── skyfall.db
│
├── static/
│ ├── app.js
│ └── style.css
│
├── templates/
│ ├── index.html
│ └── room.html
│
├── database.py
├── main.py
└── requirements.txt
========================
КОМАНДЫ ЗАПУСКА
========================
pip install -r requirements.txt
python main.py
========================
ОТКРЫТЬ В БРАУЗЕРЕ
========================
http://127.0.0.1:8000
```