A complete implementation of the classic Pong game written entirely in SQL, running on SQLite with a C# host application.
Note: This is a C# port of the original DuckPong by Thomas Zeutschler. The original project demonstrates the power of DuckDB and SQL by implementing Pong purely in SQL. This port adapts the concept to SQLite and C#, maintaining the core philosophy while adding cross-platform support and modern terminal features.
SQLitePong is an educational project that showcases the capabilities of SQL by implementing a fully playable Pong game where:
- All game logic runs in SQL - Physics, collisions, AI, and scoring
- Rendering is done in SQL - The entire game screen is generated via SQL queries
- C# provides only I/O - Keyboard input, display output, and timing
- No game logic in C# - Everything except display and input is pure SQL
This demonstrates that SQL is not just a query language but a complete computational platform capable of complex real-time applications.
- โ Complete Pong gameplay with classic physics
- โ Advanced AI with distance-based strategy and trick shots
- โ 3ร5 pixel font rendering for large score display
- โ Dynamic FPS control (15, 30, 60, 120 FPS, and MAX mode)
- โ Sound effects (scoring and paddle hits)
- โ Color terminal output using Spectre.Console
- โ Alternate screen buffer (like vim/less)
- โ Cross-platform (Windows, Linux, macOS)
- .NET 10 SDK or later
- A terminal with ANSI escape sequence support (Windows Terminal, iTerm2, etc.)
This project uses the new .NET 10 dotnet run app feature:
# Clone the repository
git clone https://github.com/tsabo/sqlitepong
cd sqlitepong
# Run the game (no build or project file needed!)
dotnet run app.csThe required NuGet packages (Microsoft.Data.Sqlite and Spectre.Console) are automatically restored from the #:package directives at the top of the file.
| Key | Action |
|---|---|
ESC |
Exit game |
S |
Toggle sound effects |
+ |
Increase FPS (15 โ 30 โ 60 โ 120 โ MAX) |
- |
Decrease FPS (MAX โ 120 โ 60 โ 30 โ 15) |
graph TB
subgraph "C# Host Application (app.cs)"
KB[Keyboard Input]
DISP[Display Rendering<br/>Spectre.Console]
TIME[Frame Timing & Sound]
end
subgraph "SQLite In-Memory Database"
STATE[Game State Table<br/>โข Paddle positions<br/>โข Ball position/velocity<br/>โข Scores<br/>โข Tick counter]
subgraph "Game Logic (tickSql - CTE Chain)"
AI[Step 1: AI Decision<br/>trick shots + tracking]
MOVE[Step 2: Ball Movement]
WALL[Step 3: Wall Collision]
PADDLE[Step 4: Paddle Collision<br/>angle physics]
SCORE[Step 5: Scoring Detection]
UPDATE[Step 6: State Update]
AI --> MOVE --> WALL --> PADDLE --> SCORE --> UPDATE
end
subgraph "Rendering (renderSql - 80ร25 grid)"
GRID[Generate Coordinates]
PIXEL[Pixel-by-Pixel CASE]
FONT[3ร5 Font Lookup]
COLOR[Color Metadata]
GRID --> PIXEL
PIXEL --> FONT
PIXEL --> COLOR
end
end
KB -->|ESC, S, +/-| TIME
TIME -->|Execute tickSql| UPDATE
UPDATE -->|UPDATE state| STATE
STATE -->|SELECT pixels| GRID
COLOR -->|Markup| DISP
DISP -->|Terminal Output| USER((Player))
TIME -->|Beep| USER
style STATE fill:#e1f5ff
style UPDATE fill:#ffe1e1
style DISP fill:#e1ffe1
style USER fill:#fff4e1
- Common Table Expressions (CTEs) - Breaking complex logic into steps
- Recursive CTEs - Generating sequences (field coordinates)
- Window Functions - Not used here, but could be for advanced scoring
- CASE Expressions - Conditional logic (AI decisions, rendering)
- JOINs - Font rendering, coordinate mapping
- Aggregate Functions - String concatenation for rendering
- Random Number Generation - Ball serves, AI imperfection
- State Management - Single-row UPDATE pattern
The AI uses a sophisticated distance-based approach:
When ball is CLOSE (โค5 pixels):
- Attempts trick shots by positioning paddle for specific angles
- 25% chance: Hit top edge (steep up, vy=-2)
- 25% chance: Hit upper section (diagonal up, vy=-1)
- 5% chance: Hit center (straight, vy=0) - RARE!
- 25% chance: Hit lower section (diagonal down, vy=+1)
- 20% chance: Hit bottom edge (steep down, vy=+2)
When ball is FAR:
- 85% accuracy defensive tracking
- 15% chance: Don't move (creates scoring opportunities)
Ball Movement:
- Horizontal velocity: ยฑ1
- Vertical velocity: -2, -1, 0, 1, 2
Collision Detection:
- Top/bottom walls: Flip vertical velocity
- Paddles: Reverse horizontal + calculate angle based on hit zone
Paddle Zones (7 zones on a 7-pixel paddle):
Position 0 (top): vy = -2 (steep up)
Positions 1-2: vy = -1 (diagonal up)
Positions 3-4: vy = 0 (straight)
Position 5: vy = 1 (diagonal down)
Position 6 (bottom): vy = 2 (steep down)
The game uses a pixel-by-pixel rendering approach:
- Generate an 80ร25 grid of coordinates
- For each (x, y) position, determine:
- Is it a border, paddle, ball, center line, or score digit?
- What character to display?
- What color (grey/dim or white/bold)?
- Assemble into lines with Spectre.Console markup
- Output to alternate screen buffer
- Score Sound: 440 Hz beep + 500ms game pause
- Paddle Hit: 880 Hz beep (throttled to max 120 Hz)
- Cross-platform: Windows uses
Console.Beep(), others use bell character (\a)
| Feature | DuckPong (Python/DuckDB) | SQLitePong (C#/SQLite) |
|---|---|---|
| SQL Engine | DuckDB | SQLite |
| Host Language | Python | C# (.NET 10) |
| Terminal Library | curses | Spectre.Console |
| Color Support | โ 4 color pairs | โ Grey + White Bold + Yellow |
| Alternate Screen | โ curses automatic | โ ANSI escape codes |
| Cross-platform | โ Linux/macOS/Windows | โ Linux/macOS/Windows |
| Package Management | pip | NuGet (inline directives) |
| AI Complexity | Advanced (trick shots) | Advanced (trick shots) |
| Font Rendering | 3ร5 digits | 3ร5 digits |
| Sound Effects | โ curses.beep() | โ Console.Beep() + \a |
Both implementations share the same core philosophy and ~95% of the SQL logic!
This project demonstrates:
- SQL is Turing-complete - Can implement complex algorithms
- CTEs for procedural logic - Breaking down problems step-by-step
- SQL for game engines - Real-time state management
- Recursive queries - Generating series and coordinates
- Advanced CASE logic - Multi-level conditional branching
- Cross-platform .NET - Modern C# features (raw strings, top-level statements)
- Terminal UI techniques - Alternate screens, ANSI colors, cursor control
app.cs (single file - 600+ lines)
โโโ Header Comment (Attribution)
โโโ Package Directives (#:package)
โโโ Using Statements
โโโ Main()
โ โโโ Terminal Setup (alternate screen)
โ โโโ Database Setup (in-memory SQLite)
โ โโโ setupSql (CREATE tables, INSERT font data)
โ โโโ tickSql (Game logic - 6-step CTE chain)
โ โโโ renderSql (Rendering - pixel-by-pixel)
โ โโโ Game Loop
โ โโโ Input handling
โ โโโ Tick execution (UPDATE state)
โ โโโ Render execution (SELECT pixels)
โ โโโ Display output (Spectre.Console)
โ โโโ Sound effects
โ โโโ Frame rate limiting
โโโ Helper Functions
โโโ PlayBeep() - Cross-platform sound
โโโ ExecuteNonQuery() - SQL execution
โโโ GetABVx() - State retrieval
โโโ ExecuteRenderQuery() - Pixel fetching
- Author: Thomas Zeutschler
- Repository: github.com/Zeutschler/duckdb-pong-in-sql
- License: MIT
- Concept: Complete Pong game in SQL using DuckDB
- Author: Jeremy Brown (Tsabo)
- Adaptation: SQLite + C# + Spectre.Console
- License: MIT (same as original)
- Key Changes:
- Ported from DuckDB to SQLite
- Ported from Python/curses to C#/Spectre.Console
- Added alternate screen buffer support
- Adapted to .NET 10's
dotnet run appfeature - Cross-platform sound handling
- Original DuckPong: github.com/Zeutschler/duckdb-pong-in-sql
- SQLite: sqlite.org
- Spectre.Console: spectreconsole.net
- .NET: dotnet.microsoft.com
dotnet run app.csPress + to speed up the game, - to slow down, S to enable sound, and ESC to exit.
Enjoy watching SQL play against itself! ๐ฎโจ
Built with โค๏ธ for SQL enthusiasts and retro gaming fans