Open this page in another window to see real-time sync.

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!