Project assignments 2026 fall
One project, six assignments, three defenses. You build a classic two-player board game — first as a console application, then as a web application that reuses the same game engine and persistence libraries. The game is assigned by your student code, the rules of grading are in the Extended Syllabus.
| Assignment | What | Weeks | Soft milestone | Hard deadline (code freeze) | Defended at |
|---|---|---|---|---|---|
| A1 | Menu system class library | 1–3 | Fri 18.09 | Thu 08.10 23:59:59 | D1 (Week 6–7) |
| A2 | Console game: configuration, board, game brain, hot-seat | 3–5 | Fri 02.10 | Thu 08.10 23:59:59 | D1 (Week 6–7) |
| A3 | JSON persistence and CRUD | 4–5 | Fri 02.10 | Thu 08.10 23:59:59 | D1 (Week 6–7) |
| A4 | EF Core persistence + interface-based repository | 6–8 | Fri 23.10 | Thu 12.11 23:59:59 | D2 (Week 11–12) |
| A5 | AI opponent | 8–10 | Fri 06.11 | Thu 12.11 23:59:59 | D2 (Week 11–12) |
| A6 | Razor Pages web app + full demo | 11–15 | Fri 11.12 | Thu 17.12 23:59:59 | D3 (Week 16–17) |
Soft milestones are the pace you should keep to; nothing happens if you miss one. The code freeze is the only real deadline: the last commit pushed before it is what gets graded at the defense, whichever of the two defense Fridays you book. Tag it (d1, d2, d3) — the tag is also your fallback if the newest commit does not compile at defense. All times are Tallinn local time.
Retakes: Week 8 (D1), Week 13 (D2), Week 18 (D3). One retake in total, capped at 75% of the points. Details in the syllabus.
The bar: how complex must the game be?
Every game in this course must be at least as demanding as the Connect Four project of the 2025 course. This was the whole spec last year:
Project: Connect Four (customized). Extended rules: board size and winning connection size are customizable; board can be either a rectangle or a cylinder. Technical requirements: configurations can be precreated (classical, connect5, connect3, connect4-cylinder, …); games can be saved, loaded, continued, deleted — using both JSON text files and an EF Core database; game solver (AI) with difficulty levels; human vs human, human vs AI, AI vs AI; console app where players take turns; web app with an unlimited amount of parallel games, players in different browsers/tabs; a game can be started in console and continued in web — and vice versa.
That is the minimum. Concretely, your game passes the complexity bar only if all of these hold:
- The board is parameterised, not fixed. Width, height, winning length, piece counts, grid size — whatever your game has — come from a
GameConfiguration, never from constants. A fixed 3×3 board is not a game configuration, it is a hard-coded demo. - Both mandatory custom-rule extensions of your game are implemented (table below) and actually change how the rules behave. They are not optional flavour; they are what separates your engine from a textbook example.
- Presets exist and custom configurations have full CRUD. At least the presets listed for your game are seeded on first run; users can create, edit, list and delete their own, and every configuration is validated (no 2×2 board with a winning length of 5).
- Win and draw detection are general. They work for any legal configuration, including the extensions (a win across the cylinder edge, through a movable grid, with an overline rule, with a mill on a graph board).
- The game is deep enough that minimax needs a depth cutoff and an evaluation function. 3×3 tic-tac-toe is fully solvable in milliseconds; that is why it is only allowed as a test preset, never as the deliverable. On a 7×6 Connect Four board, a 15×15 Gomoku board or an 8×8 Reversi board your AI has to make decisions under a time budget. That is the exercise.
- The whole solution is one architecture. Menu library, engine, DAL and two UIs as separate projects; no duplicated game logic anywhere; persistence behind interfaces; console and web share the same saved games.
What is not enough, seen every year:
- Tic-tac-toe on a fixed 3×3 board with "we can add the size later".
- A board size that can be changed in code but not from the configuration UI.
- An "AI" that picks a random legal move, or a minimax with no depth limit that freezes on anything bigger than 4×4.
- One save slot instead of a list of saved games; saving only the board and not whose turn it is.
- A web app with a second copy of the rules in the
PageModel, or a web app that cannot open a game saved from the console.
"But my game is simpler than Connect Four" is not an argument. Every one of the five games below is at least as complex once its extensions are in — that is why they were chosen. If you think your assigned game is too simple, you have not read the extensions.
Your game — assigned by student code
Take the last digit of the numeric part of your student code (e.g. 2234566IADB → 6) and integer-divide it by 2. The result 0–4 picks the row. Write the assigned game into your README in Week 1; it cannot be changed later.
| Last digit | Game | Rules | Mandatory custom-rule extensions | Preset configurations (seeded on first run) |
|---|---|---|---|---|
| 0, 1 | Connect Four | Wikipedia, Hasbro instructions | (1) Board width, height and winning connection length are configurable. (2) Board is either a rectangle or a cylinder — columns wrap around, so a winning line may cross the side edge. | Classic 7×6 / 4 · Connect3 5×4 / 3 · Connect5 9×7 / 5 · Cylinder 7×6 / 4 |
| 2, 3 | Tic-Tac-Two | Review with rules, GamesCrafters, Video | (1) Board N×N, movable grid M×M (M ≤ N), winning length W (W ≤ M) and pieces per player P are all configurable. (2) Unlock threshold — the number of pieces a player must place before moving the grid or moving a piece is allowed. | Classic 5×5, grid 3, win 3, 4 pieces, unlock 2 · Big 7×7, grid 4, win 4, 6 pieces, unlock 3 · Tiny 4×4, grid 3, win 3, 3 pieces, unlock 1 · Plain 3×3, grid 3 (= tic-tac-toe, for AI tests only) |
| 4, 5 | Reversi / Othello | Wikipedia, World Othello rules | (1) Board size configurable (even, 4–16, rectangle allowed) and opening variant (Othello fixed diagonal start vs Reversi free placement of the first four). (2) Blocked cells (walls) — a configurable set of unplayable cells; flanking cannot pass through a wall. | Othello 8×8 · Mini 6×6 · Reversi 8×8 free opening · Walls 8×8 with 4 blocked cells |
| 6, 7 | Gomoku | Wikipedia | (1) Board size (9–19, rectangle allowed) and winning length (4–6) are configurable. (2) Overline rule toggle — exactly N wins (standard) vs N-or-more wins (free-style). Optional: pro opening (first move in the centre, first player's second move at least 3 away). | Free-style 15×15 / 5 · Standard 15×15 exact-5 · Small 9×9 / 4 · Pro 19×19 / 5 with opening rule |
| 8, 9 | Nine Men's Morris | Wikipedia | (1) Variant family — pieces per player and board topology (Three / Six / Nine / Twelve Men's Morris; Twelve adds diagonals). (2) Flying threshold (fly at 3 pieces, at 4, or disabled) and a "may remove from a mill when no free piece exists" toggle. The board is a graph of points with adjacency and mill lists, not a grid; moves are multi-step (select, destination, capture). | Nine classic · Twelve (diagonals, no flying) · Six · Three |
All five are perfect-information games, so minimax with alpha-beta applies to every one of them. They differ in rule complexity; TA calibration accounts for that, the rubric is the same for all.
Where each game bites (so you can plan):
- Connect Four: gravity (a move is a column, the row is derived); win detection that wraps on the cylinder without double counting; presets with different sizes must draw correctly in console and web.
- Tic-Tac-Two: three kinds of moves (place a piece, move the grid, move a piece) with an unlock threshold; win detection only inside the grid; the AI's move generator has to produce all three kinds.
- Reversi: flanking in eight directions, the pass move when a player has no legal move, game end when neither player can move, walls that block flanking; the board is never "full" in the tic-tac-toe sense.
- Gomoku: large boards, so naive win scanning and naive move generation are too slow for the AI — you will need to scan around the last move and to order moves near existing stones.
- Nine Men's Morris: no grid at all — 24 points with adjacency and 16 (or 20) mill lines; three game phases; a move can trigger a capture that is a second decision; the AI must search over multi-step moves.
Project technical requirements (all assignments)
Repository and tooling
- One git repository per student, created in Week 1. The git server, repository naming and setup are defined in Git usage.
README.mdat the root: full name, student code, school email, uni-id, assigned game, how to run the console app, the tests and (from A6) the web app, which extensions are implemented, and a short AI usage log (what you used AI for, what it got wrong, what you changed)..gitignorefor Visual Studio + Rider (dotnet new gitignore); never commitbin/,obj/,.idea/,*.db, user secrets.- .NET 10 (LTS), C# 14, JetBrains Rider.
dotnet buildanddotnet testmust work from a fresh clone with no manual steps. No absolute local paths anywhere; the SQLite file lives under the user's home folder or next to the app. - Nullable warnings as errors on solution level is mandatory from the first commit (
Directory.Build.propswith<Nullable>enable</Nullable>and<TreatWarningsAsErrors>true</TreatWarningsAsErrors>). - Commit small and often, in English. A repository with three commits titled "final" tells the TA what they need to know.
Solution layout (names are recommendations; the separation is not)
icd0008.sln
Directory.Build.props nullable + warnings as errors for every project
MenuSystem/ A1 – class library, knows nothing about games
GameEngine/ A2 – domain: GameConfiguration, GameState, GameBrain, IMoveProvider,
repository interfaces (A3), AI (A5)
DAL.Json/ A3 – IConfigRepository / IGameRepository over JSON files
DAL.EF/ A4 – the same interfaces over EF Core + SQLite, AppDbContext, Migrations/
ConsoleUI/ A2 – console app: uses MenuSystem + GameEngine + DAL.*
WebApp/ A6 – ASP.NET Core Razor Pages: uses GameEngine + DAL.*
Tests/ A2 – xUnit: engine rules, repositories (A3/A4), AI (A5)
Dependency direction: ConsoleUI and WebApp depend on everything below them; DAL.* depend on GameEngine; GameEngine and MenuSystem depend on nothing of yours. GameEngine must never reference a UI, a DAL or Console.
Play modes: human vs human hot-seat (players take turns behind the same PC), human vs AI, AI vs AI — in console from A5, in web from A6.
Persistence: CRUD (create / list / load-continue / delete) for configurations and for saved games, over JSON files (A3) and an EF Core database (A4), behind the same interfaces; switching takes a couple of lines of code or one configuration value.
Tests: an xUnit project from A2 on. Game-rule tests from A2, repository contract tests from A4 (the same tests run against JSON and EF), AI tests from A5. Tests are graded at every defense.
Language: English for code, comments, README, commit messages and UI text.
A1 – Menu system class library (Weeks 1–3)
Goal. A reusable console menu library plus a small console application that demonstrates it. The library is the first building block of ConsoleUI and must work for any console app — it knows nothing about your game.
Requirements
- Separate class library project (
MenuSystem). No reference toGameEngineor anything game-specific, noConsole.ReadLinesprinkled in the calling code — the library owns the loop. - Unlimited depth of menu levels. Menus are built from menu items; a submenu is just a menu item whose action runs another menu.
- Mandatory items are added automatically by level: first level — Exit; second level — Exit and Return to previous; deeper levels — Exit, Return to previous and Return to main. The caller does not add these by hand.
- Every item has a shortcut (hot key), a title and an action. Actions are delegates (
Func<string>or an equivalent that returns a result the menu can react to). Titles can be updated after the menu is built (e.g.Persistence: JSON→Persistence: DB). - Duplicate shortcuts are rejected when the menu is built, including clashes with the mandatory items. Reserved shortcuts (for Exit etc.) are documented.
- Item selection is either typed input with validation (unknown shortcut → message, ask again) or a cursor-based "console GUI" with arrow keys. Both is a bonus.
- Return to main from a deep menu unwinds every level in between without re-running their actions. Exit exits from any depth.
- The demo console app shows at least three levels of nesting and one item whose title changes based on state.
Deliverables: MenuSystem project, demo console app, git history from Week 1, README with the mandatory contents.
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| Menu behaviour | 50 | Depth, mandatory items per level, correct unwinding, updateable titles, validation or cursor navigation |
| Demo app | 15 | Shows every feature; is not the game |
| Code quality | 20 | Nullable-as-errors on, no game references, clear public API, naming, no dead code |
| Git + README | 15 | Small commits from Week 1, README complete, TAs added |
At the defense you will be asked to add a new submenu live, to explain how Return to main works through several levels, and why the library must not depend on the game.
Common mistakes: hard-coding the mandatory items into every menu by hand; a menu that can only be exited from the top level; shortcuts compared case-sensitively so x and X differ; the library printing the game board.
A2 – Console game: configuration, board, game brain, hot-seat (Weeks 3–5)
Goal. Your assigned game is playable in the console, human vs human, with its mandatory extensions, driven by the A1 menu. This is the load-bearing assignment of the console phase — everything after it only adds persistence and AI around the engine.
Requirements
GameEngineclass library with a clear split:GameConfiguration(immutable record),GameState(everything needed to continue a game: board, whose turn, move history, configuration, id, timestamp),GameBrain(rules: legal moves,MakeMovewith validation, win detection, draw detection, turn handling). NoConsolein the engine.- Both mandatory extensions of your game implemented and reachable from the configuration.
- Configuration UI: choose a preset, create a custom configuration, edit and delete custom ones (in-memory until A3). Validation with meaningful messages — impossible combinations are rejected before a game starts.
- Board UI in console: draws any legal configuration (sizes, walls, grid, graph points…), shows whose turn it is, highlights the last move, shows the result at game end. Simple animation (piece dropping, flip sequence, blinking mill) is a bonus, clarity is mandatory.
- Hot-seat play: two humans take turns at the same keyboard. Illegal input never crashes the game and never skips a turn.
- Every kind of move your game has is playable (Tic-Tac-Two: place, move grid, move piece; Nine Men's Morris: place, move, fly, capture; Reversi: pass when required).
- Unit tests in
Tests: win detection in every direction and across the extension (cylinder edge, grid boundary, wall, overline, mill on the graph), illegal moves rejected, draw detected, turn switching. Build boards from a string picture in tests so they stay readable.
Deliverables: GameEngine, ConsoleUI, Tests, README updated (how to play, what is implemented).
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| Rules + mandatory extensions | 35 | Correct for any configuration; both extensions change behaviour visibly |
| Configuration UI + validation | 15 | Presets, custom configs, meaningful validation |
| Board UI + hot-seat flow | 20 | Any size draws correctly, last move highlighted, result shown, no crashes on bad input |
| Unit tests | 15 | Cover win/draw/illegal moves and each extension; run green with dotnet test |
| Code quality | 15 | Engine free of UI, small methods, naming, nullable-safe |
At the defense the TA will pick a preset you did not demo, play a few moves, try an illegal move, then ask you to trace one win check through the code and to run the tests.
Common mistakes: win detection that only works for the classic size; GameBrain drawing the board; the board as EGamePiece[,] (JSON cannot serialise it — use jagged arrays now, not in A3); turn stored in the UI instead of the state.
A3 – JSON persistence and CRUD (Weeks 4–5)
Goal. Configurations and game states can be saved, listed, loaded/continued and deleted as JSON text files — behind repository interfaces that A4 will implement a second time.
Requirements
- Interfaces
IConfigRepositoryandIGameRepository(list / get / save / delete) defined inGameEngine(or a shared library), not in the DAL. DAL.Jsonproject implementing both withSystem.Text.Json. Newtonsoft.Json is not allowed.- Files live in a user directory (
Environment.SpecialFolder.UserProfile+ an app folder), never in the working directory; the folder is created on first use. - Saved games carry an id, a name, the configuration and everything needed to continue (board, whose turn, move history, timestamps). Loading a game and continuing it is indistinguishable from never having stopped.
- Presets are seeded into the config repository on first run. Deleting a preset is either impossible or recreates it on next start — your choice, documented.
- The console app: save at any point, list saved games with name/date/game, continue, delete; the same for configurations. Saving after every move (autosave) is recommended and makes A6 cross-play trivial.
- Round-trip tests: save → load gives an equal state (including the extension fields); listing shows what was saved; delete removes it.
Deliverables: DAL.Json, interfaces in the shared library, saves visible in the user folder, tests.
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| Configuration CRUD | 30 | Presets seeded, custom configs persisted, validation still applies |
| Game state CRUD | 40 | Save / list / continue / delete work from the menu; continued game is exact |
| Interface-based design | 15 | Interfaces in the engine, ConsoleUI talks to interfaces only |
| Tests + code quality | 15 | Round-trip tests, shared JsonSerializerOptions, enums as strings, no [,] |
Common mistakes: saving the board but not whose turn or the configuration; file names with characters that are illegal on another OS; Directory.GetCurrentDirectory() as the save location; catching every exception and silently continuing with an empty list.
A4 – EF Core persistence + interface-based repository (Weeks 6–8)
Goal. The same CRUD on an EF Core database (SQLite), with migrations. Switching between JSON files and the database takes a couple of lines of code or one configuration value. Repositories arrive through Dependency Injection.
Requirements
DAL.EFproject:AppDbContext, entities (Configuration,SavedGame— store the state as a JSON column, a normalised move table, or both), migrations folder in git, SQLite provider. The database file lives under the user's home folder (same rule as the JSON files).ConfigRepositoryEfandGameRepositoryEfimplement the same interfaces with the same behaviour as the JSON versions (same list order, same "not found" behaviour, same upsert-on-save semantics).- Ids stay stable across implementations: a game saved in JSON and one saved in the DB have the same shape and the same
Guid; the JSON serialisation of the state is the same code. - The
ConsoleUIchooses the implementation fromappsettings.json(e.g."Persistence": "Json"or"Db") or a one-line change in the composition root — and nothing else changes. Registration goes throughMicrosoft.Extensions.DependencyInjection. - Migrations are applied automatically at startup (
Database.Migrate()) — a fresh clone must run without manualdotnet efcommands. - Contract tests: the A3 repository tests are parameterised (
[Theory]+[MemberData]) and run against both implementations. The EF variant may use a temporary SQLite file or in-memory SQLite.
Deliverables: DAL.EF with Migrations/, DI registration in ConsoleUI, contract tests, README updated (how to switch persistence).
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| EF model + migrations + SQLite | 30 | Entities, relationship Configuration → SavedGame, migrations in git, auto-migrate |
| EF repository implementation | 30 | Same behaviour as JSON, no tracking bugs, SaveChanges per operation |
| One-line / config switch | 20 | Switching persistence changes nothing in the UI code; DI registration |
| Contract tests on both implementations | 10 | The same test class runs green against JSON and EF |
| Code quality | 10 | Nullable-safe entities, no SQL Server/localdb leftovers, connection string not hard-coded to your laptop |
At the defense: switch the persistence live, show a game saved in JSON and one in the DB, open the SQLite file in Rider, explain what a migration is and why the interfaces live in the engine.
Common mistakes: an EnsureCreated() instead of migrations; the DbContext registered as singleton; the JSON and EF versions listing games in different orders; Include forgotten so the configuration name is null in the list.
A5 – AI opponent (Weeks 8–10)
Goal. A computer opponent based on minimax with alpha-beta pruning and an evaluation function for your game, with at least three difficulty levels, playable human vs AI and AI vs AI in the console, without freezing the UI.
Requirements
IMoveProvider(or equivalent) abstraction: the game loop asks the current player's provider for a move — a human provider reads the console, an AI provider searches. The loop is the same for all three play modes.- Minimax with alpha-beta pruning over your engine's
GetLegalMoves/MakeMove/ win detection. Terminal states reuse the engine's win and draw detection — no second rule implementation inside the AI. - Depth cutoff with an evaluation function specific to your game (open lines / windows, mobility, corners, mills, grid control … see lecture 10.1). A pure win/loss/draw utility with no heuristic does not count.
- At least three difficulty levels that differ in a way the player can feel (depth, time budget, evaluation noise, random-move mixing). Level names and what they do are in the README.
- Time budget: the AI answers within roughly 5 seconds per move at the highest level on a laptop and never blocks the console from redrawing — use a
CancellationToken/time budget (iterative deepening recommended, lecture 10.2). A search that runs unbounded on a 15×15 board fails this point. - AI vs AI: the game plays itself with a short pause between moves; the user can stop it.
- AI tests: takes an immediate win when available, blocks an immediate loss, only produces legal moves, is deterministic with a seeded
Random. Add one test per extension where it matters (e.g. the AI sees a win across the cylinder edge). - Bonus: move ordering, transposition table, opening rules, difficulty that adapts to the board size.
Deliverables: AI in GameEngine (or a separate library referenced by both UIs), tests, README section with the levels and a few measured timings (depth reached in one second on your laptop, per preset).
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| Minimax | 25 | Correct search over the engine, terminal handling, root move choice |
| Alpha-beta | 15 | Correct pruning (same move as plain minimax, far fewer nodes) |
| Evaluation function | 20 | Game-specific, explained, covers the extensions |
| Difficulty levels | 10 | ≥ 3, distinguishable, documented |
| Human vs AI + AI vs AI + responsive UI | 15 | Both modes from the menu, time budget respected, board redraws |
| AI tests | 10 | Win/block/legal/deterministic tests green |
| Code quality | 5 | No duplicated rules, no UI in the AI, deep-copied search state |
At the defense: play against the hardest level on the largest preset; explain one pruned branch on paper; show what your evaluation function rewards; run the AI tests.
Common mistakes: mutating the real game state during search (the board changes while the human is thinking); a Random created inside the loop; depth counted in moves of one player only; an evaluation function copied from Connect Four for a game that is not Connect Four.
A6 – Razor Pages web app (Weeks 11–15)
Goal. The same game as an ASP.NET Core Razor Pages web application that reuses GameEngine and DAL.*: configuration CRUD, unlimited parallel games, all play modes, two players in different browsers, cross-play with the console.
Requirements
WebAppproject referencingGameEngine,DAL.JsonandDAL.EF. No game logic in the web project — no second win check, no second move validation.PageModels callGameBrainand the repositories, nothing else.- Persistence through the same interfaces and the same DI registrations as the console app, switchable with the same configuration value. Default is the database, pointing at the same SQLite file as the console app.
- Configuration pages: list, create, edit, delete (scaffolding is fine as a start; validation must match the engine's).
- Games: list (with game, configuration, players, last move time), create from a configuration choosing player types (human/AI) and, for AI, the difficulty; continue; delete.
- Unlimited parallel games — every game has its own URL (
/Games/Play/{id}); thousands of games do not interfere. - Two players in different browsers/tabs: each game has two player links (or a username / a per-game password — your choice, documented). A player can only move when it is their turn; anybody else sees a read-only board. The waiting player sees the opponent's move without pressing F5 (meta refresh, a small fetch poll or htmx — one of them).
- All play modes: human vs human across browsers, human vs AI (the AI answers within the same time budget as in console), AI vs AI (step button or auto-advance).
- Cross-play: a game saved in the console appears in the web list and can be continued there; a game played in the web can be continued in the console. Same ids, same JSON format, same database.
- ASP.NET Core Identity is not required. Per-player secret links, a name in a cookie or a per-game password are all acceptable "DIY auth". Identity is a bonus, not a requirement.
- Server-side validation of every input (bad ids, moves out of turn, illegal moves) with a friendly error, not a stack trace.
Deliverables: WebApp, README with run instructions (dotnet run --project WebApp), the AI usage log, the d3 tag.
Grading (0–100)
| Part | Points | What earns the points |
|---|---|---|
| Runs on reused libraries | 25 | Zero duplicated game logic; same DI registrations; same SQLite file |
| Configuration CRUD in web | 10 | Presets and custom configs, validation |
| Parallel games: create / join / list | 20 | Own URL per game, list with useful columns, thousands of games do not interfere |
| All play modes in web | 20 | Two browsers, human vs AI, AI vs AI, waiting player updates |
| JSON / DB switch in web | 10 | One config value, both work |
| Code quality + UX | 15 | Thin PageModels, partials for board/status, readable board for any configuration, friendly errors |
Common mistakes: game state kept in a static dictionary or the session instead of the repository; a board rendered only for the classic size; the AI move computed in the GET handler so every refresh makes another move; TempData used as the game state; the console and web apps pointing at two different SQLite files.
D3 – full demo (30% of D3)
At D3 you defend A6 and demonstrate the whole solution. The demo is graded separately (0–100, weighted 30% of the 40 D3 points) so that the integrated result counts, not only the last assignment.
- Fresh clone →
dotnet build→dotnet test— green. - Console: create a game from a preset and from a custom configuration, play human vs human, save, exit.
- Web: list games, continue the game saved from console, play human vs human in two browser windows (two different player links).
- Show the JSON ↔ DB switch (couple of lines or a config value); a JSON-saved console game loads in web.
- Human vs AI and AI vs AI in both console and web, with difficulty selection; the AI answers within its time budget.
- At least one of your mandatory custom-rule extensions demonstrated live (a win across the cylinder edge, a wall in Reversi, flying in Nine Men's Morris, an overline that does not win, a grid move …).
- Show the tests, the migrations, the repository interfaces and the DI registration.
| Part | Points |
|---|---|
| Cross-play console ↔ web | 30 |
| All play modes in both UIs | 20 |
| Presets + extensions shown live | 15 |
dotnet test green from a fresh clone | 15 |
| README + AI usage log + git history | 20 |
No slides — show the running application and the code. Be prepared for the TA to ask for a scenario you did not plan.
FAQ
Can I use a different game? No. Five games, assigned by student code, so that TAs can calibrate and so that nobody picks tic-tac-toe.
Can I work with others? Yes — discuss, pair up, review each other's code. Each student keeps an own repository and defends alone; you must be able to explain every line without help.
Can I use AI tools? Yes, encouraged. Keep the AI usage log in the README. At the defense you explain the code, not the tool.
My game engine API differs from the lecture names. Fine. Names in the lectures (GameBrain, IMoveProvider, IGameRepository …) are examples; the separation they express is the requirement.
Do I need Docker, a VPS, CI/CD? No. Everything runs on your laptop. A Dockerfile for the web app is a bonus.
What if my code does not compile at the defense? Fall back to your tagged commit, or take the one-time 10-minute hotfix window. If neither produces a running application, that assignment scores 0 at that defense. Tag before you leave home.
Where are the detailed rules? In the Extended Syllabus: grading formulas, retake policy, defense logistics, rubric.