Web Games with FastAPI

Games come in various forms, from text-based adventures to immersive 3D experiences. In this article, we’ll explore the creation of a simple game using FastAPI, a modern web framework for building APIs with Python. 

Our focus will be on developing a Wordle-like game, incorporating both client-side and server-side interactions.

Python Game Packages:

Before diving into game development, it’s worth noting some Python game packages for those interested in more complex gaming projects. However, our primary goal is to keep the game code simple and concise, aligning with the theme of creating web content with FastAPI.

Splitting Game Logic:

Creating a game involves deciding where to store and manage game logic. The web is stateless, so maintaining state across game steps is crucial. We explore different approaches, from client-side JavaScript to server-heavy applications and single-page applications (SPAs).

Game Design:

Our game will be a simplified Wordle-style challenge, using creature names from a database. The design involves initializing the game, processing user guesses, scoring them, and providing visual feedback on the client side.

Web Part One: Game Initialization:

We introduce two new FastAPI web endpoints under the namespace “/game”. The first endpoint initializes the game, retrieving a random creature name from the database. The response includes a Jinja template containing HTML, CSS, and JavaScript to implement the game logic.

Python Code:

# web/game.py

from pathlib import Path

from fastapi import APIRouter, Body, Request

from fastapi.templating import Jinja2Templates

from service import game as service

router = APIRouter(prefix=”/game”)

# Initial game request

@router.get(“”)

def game_start(request: Request):

name = service.get_word()

top = Path(__file__).resolve().parents[1]

templates = Jinja2Templates(directory=f”{top}”)

return templates.TemplateResponse(“game.html”, {“request”: request, “word”: name})

# Subsequent game requests

@router.post(“”)

async def game_step(word: str = Body(), guess: str = Body()):

score = service.get_score(word, guess)

return score

Web Part Two: Game Steps:

The client-side template is crucial for game interaction. It includes HTML, CSS, and JavaScript to display the game interface, handle user input, and communicate with the server using the fetch() function. The template also manages the scoring and visual feedback for user guesses.

HTML Code

<!– template/game.html –>

<head>

<!– Styles and head content as mentioned in the example –>

</head>

<body>

<!– JavaScript and HTML content as mentioned in the example –>

</body>

Service Part One: Initialization:

The service layer connects the web layer’s game initialization function to the data layer, ensuring a random creature name is provided to start the game.

Python Code:

# service/game.py

import data.game as data

 

def get_word() -> str:

return data.get_word()

 

Service Part Two: Scoring:

The scoring logic is added to the service layer, determining whether a guessed letter is a hit, close, or miss. The results are sent back to the client for visual representation.

Python Code:

# service/game.py

from collections import Counter, defaultdict

HIT = “H”

MISS = “M”

CLOSE = “C”

def get_score(actual: str, guess: str) -> str:

length: int = len(actual)

  if len(guess) != length:

return “”

actual_counter = Counter(actual)

guess_counter = defaultdict(int)

result = [MISS] * length

for pos, letter in enumerate(guess):

     if letter == actual[pos]:

result[pos] = HIT

guess_counter[letter] += 1

 

for pos, letter in enumerate(guess):

if result[pos] == HIT:

continue

guess_counter[letter] += 1

if (letter in actual and

guess_counter[letter] <= actual_counter[letter]):

result[pos] = CLOSE

result = ”.join(result)

return result

Test:

We include pytest exercises to test the service layer’s score calculation, ensuring the correctness of the game logic.

Python Code:

# test/unit/service/test_game.py

import pytest

from service import game

 

word = “bigfoot”

guesses = [

(“bigfoot”, “HHHHHHH”),

(“abcdefg”, “MCMMMCC”),

(“toofgib”, “CCCHCCC”),

(“wronglength”, “”),

(“”, “”),

]

@pytest.mark.parametrize(“guess, score”, guesses)

def test_match(guess, score):

assert game.get_score(word, guess) == score

 

Data: Initialization:

The data layer provides a function to retrieve a random creature name from the database.

Python Code:

# data/game.py

from .init import curs

def get_word() -> str:

qry = “select name from creature order by random() limit 1”

curs.execute(qry)

row = curs.fetchone()

if row:

name = row[0]

else:

name = “bigfoot”

return name

Let’s Play Cryptonomicon:

A demonstration of the game is provided, showcasing the interactive nature of the Wordle-style challenge. Users can input guesses, receive scores, and continue playing until they guess the creature name or give up.

This article guides you through the process of creating an interactive web game using FastAPI and Python. We’ve covered aspects of game design, web development, and backend logic. The provided code examples serve as a foundation for building more complex games and exploring the world of web-based gaming with Python.

 

Visited 4 times, 1 visit(s) today