Two-player Tic-Tac-Toe
Pick a seat below to play, or just watch. Open this page in a separate browser or window to take the other seat — every move syncs instantly over WebSocket. No API, no polling, no JavaScript. A seat frees up the moment that player leaves or closes the tab.
apps/tictactoe/views.pypython
@action
def take_seat(self, seat="", **kwargs):
if seat not in ("X", "O"):
return # guard the wire input
me = self._me()
if not me:
return # a seat is leased to a live WebSocket connection only
g = Game.shared()
self._reap_dead_seats(g)
g = Game.shared()
if g.winner: # don't join a finished game; click "New game" first
self._broadcast(g)
return
if g.seat_of(me): # already seated — no seat-swapping
self._broadcast(g)
return
field = "player_x" if seat == "X" else "player_o"
# Atomic claim-if-open: the WHERE clause IS the check, applied with the
# write in one statement, so two simultaneous claims can't both win.
# 1 row updated → we got the seat; 0 rows → someone beat us.
won = Game.objects.filter(pk=1, **{field: ""}).update(**{field: me})
g = Game.shared()
self.mark = seat if won else g.seat_of(me)
self._broadcast(g)
X wins!