├── frontend └── app │ ├── README.md │ ├── .prettierrc │ ├── __setups__ │ └── canvas.js │ ├── .env.production │ ├── .env │ ├── src │ ├── vite-env.d.ts │ ├── domain │ │ ├── Theme.ts │ │ ├── validUsernames.ts │ │ ├── GameWinner.ts │ │ ├── CodeExample.ts │ │ ├── GameState.ts │ │ ├── LinterLint.ts │ │ ├── HexagonalTileProps.tsx │ │ ├── User.ts │ │ ├── StatusResponse.ts │ │ ├── LobbyStatus.ts │ │ └── Lobby.ts │ ├── vars.css │ ├── components │ │ ├── jsonDisplay │ │ │ ├── JsonDisplay.module.css │ │ │ ├── JsonDisplay.tsx │ │ │ └── JsonDisplay.test.tsx │ │ ├── canvasVisu │ │ │ ├── CanvasVisu.css │ │ │ └── CanvasVisuProps.ts │ │ ├── footer │ │ │ ├── Footer.css │ │ │ └── Footer.tsx │ │ ├── hexagonalBoardBackground │ │ │ └── HexagonalBoardBackground.css │ │ ├── loadingSpinner │ │ │ ├── LoadingSpinner.module.css │ │ │ └── LoadingSpinner.tsx │ │ ├── three │ │ │ ├── Torus.tsx │ │ │ ├── Text.tsx │ │ │ ├── signature.tsx │ │ │ └── Electron.tsx │ │ ├── tempHelpersForTestingManually │ │ │ └── RemoveBeforeProdMvpUserTester.tsx │ │ ├── requireLogout │ │ │ ├── RequireLogout.tsx │ │ │ └── RequireLogout.test.tsx │ │ ├── ui │ │ │ ├── textarea.tsx │ │ │ ├── toaster.tsx │ │ │ ├── separator.tsx │ │ │ ├── button.tsx │ │ │ ├── input.tsx │ │ │ ├── buttonVariants.ts │ │ │ ├── ThemeProvider.tsx │ │ │ ├── tabs.tsx │ │ │ └── card.tsx │ │ ├── requireUser.tsx │ │ │ ├── RequireUser.tsx │ │ │ └── RequireUser.test.tsx │ │ ├── header │ │ │ ├── Header.css │ │ │ └── Header.tsx │ │ ├── ProgramInput │ │ │ ├── ProgramInput.test.tsx │ │ │ └── ProgramInput.tsx │ │ ├── confirmActionDialog │ │ │ └── ConfirmActionDialog.tsx │ │ ├── CodeExampleCard │ │ │ ├── CodeExampleCard.tsx │ │ │ └── CodeExampleCard.test.tsx │ │ └── LobbySelection │ │ │ └── LobbySelection.tsx │ ├── consts.ts │ ├── lib │ │ ├── DefaultTileProps.ts │ │ ├── usePageVisibility.ts │ │ └── CodeExamples.ts │ ├── pages │ │ ├── waitingForResult │ │ │ └── WaitingForResult.module.css │ │ ├── waitingForOpponent │ │ │ └── WaitingForOpponent.module.css │ │ ├── playerSelection │ │ │ └── PlayerSelection.module.css │ │ ├── ErrorPage.tsx │ │ ├── canvasGameVisuPage │ │ │ └── canvasGameVisu.css │ │ ├── basePage │ │ │ └── BasePage.module.css │ │ └── landingPage │ │ │ └── LandingPage.test.tsx │ ├── hooks │ │ └── useTheme.ts │ ├── services │ │ ├── lobbyContext │ │ │ ├── LobbyContextHelpers.ts │ │ │ └── LobbyContext.tsx │ │ ├── userContext │ │ │ ├── UserContextHelpers.ts │ │ │ └── UserContext.tsx │ │ └── rest │ │ │ ├── RestService.ts │ │ │ └── LobbyRest.test.ts │ ├── TestFactories.ts │ └── index.css │ ├── postcss.config.js │ ├── babel.config.cjs │ ├── tsconfig.json │ ├── .gitignore │ ├── index.html │ ├── components.json │ ├── tsconfig.node.json │ ├── public │ ├── copy.svg │ └── vite.svg │ ├── vite.config.ts │ ├── tsconfig.app.json │ ├── taskfile.yaml │ ├── eslint.config.js │ ├── tailwind.config.js │ └── package.json ├── backend ├── api │ ├── src │ │ ├── test │ │ │ ├── resources │ │ │ │ └── .gitkeep │ │ │ └── kotlin │ │ │ │ └── software │ │ │ │ └── shonk │ │ │ │ ├── interpreter │ │ │ │ ├── domain │ │ │ │ │ └── .gitkeep │ │ │ │ ├── adapters │ │ │ │ │ ├── outgoing │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ └── incoming │ │ │ │ │ │ └── .gitkeep │ │ │ │ └── application │ │ │ │ │ └── service │ │ │ │ │ └── GetCompilationErrorsServiceTest.kt │ │ │ │ └── lobby │ │ │ │ ├── adapters │ │ │ │ └── outgoing │ │ │ │ │ └── .gitkeep │ │ │ │ └── application │ │ │ │ └── service │ │ │ │ └── ShorkServiceTest.kt │ │ └── main │ │ │ ├── kotlin │ │ │ └── software │ │ │ │ └── shonk │ │ │ │ ├── shared │ │ │ │ └── .gitkeep │ │ │ │ ├── interpreter │ │ │ │ ├── adapters │ │ │ │ │ ├── outgoing │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ └── incoming │ │ │ │ │ │ └── GetCompilationErrorsController.kt │ │ │ │ ├── application │ │ │ │ │ ├── port │ │ │ │ │ │ ├── outgoing │ │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ │ └── incoming │ │ │ │ │ │ │ └── GetCompilationErrorsQuery.kt │ │ │ │ │ └── service │ │ │ │ │ │ └── GetCompilationErrorsService.kt │ │ │ │ └── domain │ │ │ │ │ └── CompileError.kt │ │ │ │ └── lobby │ │ │ │ ├── domain │ │ │ │ ├── V0Result.kt │ │ │ │ ├── GameResult.kt │ │ │ │ ├── Winner.kt │ │ │ │ ├── V0Winner.kt │ │ │ │ ├── exceptions │ │ │ │ │ ├── LobbyNotFoundException.kt │ │ │ │ │ ├── LobbyAlreadyCompletedException.kt │ │ │ │ │ ├── PlayerNotInLobbyException.kt │ │ │ │ │ ├── PlayerAlreadyJoinedException.kt │ │ │ │ │ └── NoCodeForPlayerException.kt │ │ │ │ ├── GameState.kt │ │ │ │ ├── V0Status.kt │ │ │ │ ├── Status.kt │ │ │ │ ├── LobbyStatus.kt │ │ │ │ ├── LobbyId.kt │ │ │ │ ├── PlayerNameString.kt │ │ │ │ ├── RoundInformation.kt │ │ │ │ ├── Lobby.kt │ │ │ │ └── InterpreterSettings.kt │ │ │ │ ├── application │ │ │ │ ├── port │ │ │ │ │ ├── outgoing │ │ │ │ │ │ ├── DeleteLobbyPort.kt │ │ │ │ │ │ ├── SaveLobbyPort.kt │ │ │ │ │ │ └── LoadLobbyPort.kt │ │ │ │ │ └── incoming │ │ │ │ │ │ ├── GetAllLobbiesQuery.kt │ │ │ │ │ │ ├── JoinLobbyUseCase.kt │ │ │ │ │ │ ├── CreateLobbyUseCase.kt │ │ │ │ │ │ ├── AddProgramToLobbyUseCase.kt │ │ │ │ │ │ ├── SetLobbySettingsUseCase.kt │ │ │ │ │ │ ├── GetLobbyStatusQuery.kt │ │ │ │ │ │ ├── GetProgramFromPlayerInLobbyQuery.kt │ │ │ │ │ │ └── GetLobbySettingsQuery.kt │ │ │ │ └── service │ │ │ │ │ ├── GetAllLobbiesService.kt │ │ │ │ │ ├── GetLobbyStatusService.kt │ │ │ │ │ ├── SetLobbySettingsService.kt │ │ │ │ │ ├── CreateLobbyService.kt │ │ │ │ │ ├── JoinLobbyService.kt │ │ │ │ │ ├── GetLobbySettingsService.kt │ │ │ │ │ ├── AddProgramToLobbyService.kt │ │ │ │ │ └── GetProgramFromPlayerInLobbyService.kt │ │ │ │ └── adapters │ │ │ │ ├── incoming │ │ │ │ ├── createLobby │ │ │ │ │ └── CreateLobbyCommand.kt │ │ │ │ ├── getLobbySettings │ │ │ │ │ └── GetLobbySettingsCommand.kt │ │ │ │ ├── setLobbySettings │ │ │ │ │ └── SetLobbySettingsCommand.kt │ │ │ │ ├── joinLobby │ │ │ │ │ └── JoinLobbyCommand.kt │ │ │ │ ├── addProgramToLobby │ │ │ │ │ └── AddProgramToLobbyCommand.kt │ │ │ │ ├── getProgramFromPlayerInLobby │ │ │ │ │ └── GetProgramFromPlayerInLobbyCommand.kt │ │ │ │ ├── getLobbyStatus │ │ │ │ │ └── GetLobbyStatusCommand.kt │ │ │ │ └── getAllLobbies │ │ │ │ │ └── GetAllLobbiesController.kt │ │ │ │ └── outgoing │ │ │ │ └── MemoryLobbyManager.kt │ │ │ └── resources │ │ │ ├── static │ │ │ ├── inter-greek.woff2 │ │ │ ├── inter-latin.woff2 │ │ │ ├── mono-greek.woff2 │ │ │ ├── mono-latin.woff2 │ │ │ ├── mono-cyrillic.woff2 │ │ │ ├── inter-cyrillic.woff2 │ │ │ ├── inter-greek-ext.woff2 │ │ │ ├── inter-latin-ext.woff2 │ │ │ ├── inter-vietnamese.woff2 │ │ │ ├── mono-latin-ext.woff2 │ │ │ ├── mono-vietnamese.woff2 │ │ │ ├── inter-cyrillic-ext.woff2 │ │ │ └── mono-cyrillic-ext.woff2 │ │ │ └── openapi │ │ │ ├── v0 │ │ │ └── scalar.html │ │ │ └── v1 │ │ │ └── scalar.html │ ├── exampleRequests │ │ ├── statusv0.http │ │ ├── getCompilationErrors.http │ │ ├── openapiv0.http │ │ ├── openapiv1.http │ │ └── lobbyStuffV1.http │ ├── settings.gradle.kts │ ├── gradle.properties │ └── README.md ├── shork │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── .gitkeep │ │ │ └── kotlin │ │ │ │ ├── internal │ │ │ │ ├── ICloneable.kt │ │ │ │ ├── memory │ │ │ │ │ ├── ResolvedAddresses.kt │ │ │ │ │ └── ICore.kt │ │ │ │ ├── error │ │ │ │ │ ├── TokenizerError.kt │ │ │ │ │ ├── AbstractCompilerError.kt │ │ │ │ │ └── ParserError.kt │ │ │ │ ├── statistics │ │ │ │ │ ├── RoundInformation.kt │ │ │ │ │ └── IGameDataCollector.kt │ │ │ │ ├── GameStatus.kt │ │ │ │ ├── addressing │ │ │ │ │ ├── Modifier.kt │ │ │ │ │ └── AddressMode.kt │ │ │ │ ├── process │ │ │ │ │ ├── AbstractProcess.kt │ │ │ │ │ └── Process.kt │ │ │ │ ├── AbstractInternalShork.kt │ │ │ │ ├── compiler │ │ │ │ │ ├── Compiler.kt │ │ │ │ │ └── Token.kt │ │ │ │ ├── instruction │ │ │ │ │ ├── Ldp.kt │ │ │ │ │ ├── Stp.kt │ │ │ │ │ ├── Mul.kt │ │ │ │ │ ├── Sub.kt │ │ │ │ │ ├── Spl.kt │ │ │ │ │ ├── Div.kt │ │ │ │ │ ├── Mod.kt │ │ │ │ │ ├── Nop.kt │ │ │ │ │ ├── Add.kt │ │ │ │ │ ├── Dat.kt │ │ │ │ │ ├── Jmp.kt │ │ │ │ │ ├── Jmn.kt │ │ │ │ │ └── Jmz.kt │ │ │ │ ├── program │ │ │ │ │ ├── Program.kt │ │ │ │ │ └── AbstractProgram.kt │ │ │ │ ├── InternalShork.kt │ │ │ │ ├── settings │ │ │ │ │ └── InternalSettings.kt │ │ │ │ └── util │ │ │ │ │ └── CircularQueue.kt │ │ │ │ ├── GameResult.kt │ │ │ │ ├── IShork.kt │ │ │ │ └── MockShork.kt │ │ └── test │ │ │ ├── resources │ │ │ └── .gitkeep │ │ │ └── kotlin │ │ │ ├── TestSettings.kt │ │ │ ├── mocks │ │ │ ├── MockGameDataCollector.kt │ │ │ ├── MockInstruction.kt │ │ │ └── KillProgramInstruction.kt │ │ │ ├── TestUtilities.kt │ │ │ └── compiler │ │ │ └── CompilerE2E.kt │ └── build.gradle.kts ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── settings.gradle.kts ├── build.gradle.kts ├── .gitignore └── taskfile.yaml ├── .gitignore ├── e2e ├── taskfile.yaml ├── .gitignore ├── package.json └── playwright.config.ts ├── .git-authors ├── scripts ├── deployment │ ├── flask-deployment.service │ └── requirements.txt ├── commit_msg_linter.py ├── run_gradle.py └── test_commit_msg_linter.py ├── .github ├── ISSUE_TEMPLATE │ ├── bug.md │ └── default-story.md └── workflows │ ├── image-retention-policy.yaml │ └── deployment-cleanup.yml ├── misc ├── entrypoint.sh └── nginx.conf ├── Containerfile ├── .pre-commit-config.yaml ├── taskfile.yaml └── gamedata.md /frontend/app/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/api/src/test/resources/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/shork/src/main/resources/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/shork/src/test/resources/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ 3 | .task 4 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/shared/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | useTabs: true, 3 | } 4 | -------------------------------------------------------------------------------- /frontend/app/__setups__/canvas.js: -------------------------------------------------------------------------------- 1 | import "vitest-canvas-mock"; -------------------------------------------------------------------------------- /frontend/app/.env.production: -------------------------------------------------------------------------------- 1 | VITE_REACT_APP_BACKEND_URL=/api 2 | -------------------------------------------------------------------------------- /backend/api/src/test/kotlin/software/shonk/interpreter/domain/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/app/.env: -------------------------------------------------------------------------------- 1 | VITE_REACT_APP_BACKEND_URL=http://localhost:8080/api -------------------------------------------------------------------------------- /frontend/app/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/interpreter/adapters/outgoing/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /backend/api/src/test/kotlin/software/shonk/interpreter/adapters/outgoing/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /frontend/app/src/domain/Theme.ts: -------------------------------------------------------------------------------- 1 | export type Theme = "dark" | "light" | "system"; 2 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/interpreter/application/port/outgoing/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /e2e/taskfile.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | tasks: 4 | test: 5 | cmds: 6 | - npm run test -------------------------------------------------------------------------------- /frontend/app/src/domain/validUsernames.ts: -------------------------------------------------------------------------------- 1 | export type ValidUsernames = "playerA" | "playerB"; 2 | -------------------------------------------------------------------------------- /backend/api/exampleRequests/statusv0.http: -------------------------------------------------------------------------------- 1 | ### 2 | GET http://localhost:8080/api/v0/status 3 | 4 | ### -------------------------------------------------------------------------------- /frontend/app/src/vars.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --HEADER-HEIGHT: 75px; 3 | --FOOTER-HEIGHT: 100px; 4 | } 5 | -------------------------------------------------------------------------------- /frontend/app/src/domain/GameWinner.ts: -------------------------------------------------------------------------------- 1 | export enum GameWinner { 2 | A, 3 | B, 4 | UNDECIDED, 5 | } 6 | -------------------------------------------------------------------------------- /backend/api/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "backend" 2 | 3 | include(":api") 4 | include(":shork") 5 | -------------------------------------------------------------------------------- /backend/api/src/test/kotlin/software/shonk/lobby/adapters/outgoing/.gitkeep: -------------------------------------------------------------------------------- 1 | todo: 2 | test memory lobby manager -------------------------------------------------------------------------------- /e2e/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | /test-results/ 3 | /playwright-report/ 4 | /blob-report/ 5 | /playwright/.cache/ 6 | -------------------------------------------------------------------------------- /backend/api/src/test/kotlin/software/shonk/interpreter/adapters/incoming/.gitkeep: -------------------------------------------------------------------------------- 1 | on Controller IT split, this receives one -------------------------------------------------------------------------------- /frontend/app/postcss.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /backend/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /frontend/app/src/domain/CodeExample.ts: -------------------------------------------------------------------------------- 1 | export interface CodeExample { 2 | title: string; 3 | shortDescription: string; 4 | code: string; 5 | } 6 | -------------------------------------------------------------------------------- /frontend/app/src/domain/GameState.ts: -------------------------------------------------------------------------------- 1 | export enum GameState { 2 | NOT_STARTED = "NOT_STARTED", 3 | RUNNING = "RUNNING", 4 | FINISHED = "FINISHED", 5 | } 6 | -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-greek.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-greek.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-latin.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-greek.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-greek.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-latin.woff2 -------------------------------------------------------------------------------- /frontend/app/src/domain/LinterLint.ts: -------------------------------------------------------------------------------- 1 | export interface Linterlint { 2 | line: number; 3 | message: string; 4 | columnStart: number; 5 | columnEnd: number; 6 | } 7 | -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-cyrillic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-cyrillic.woff2 -------------------------------------------------------------------------------- /backend/api/gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | ktorVersion=2.3.12 3 | kotlinVersion=2.0.20 4 | koinVersion=4.0.0 5 | mockkVersion=1.13.13 6 | logbackVersion=1.5.12 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-cyrillic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-cyrillic.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-greek-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-greek-ext.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-latin-ext.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-vietnamese.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-vietnamese.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-latin-ext.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-vietnamese.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-vietnamese.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/inter-cyrillic-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/inter-cyrillic-ext.woff2 -------------------------------------------------------------------------------- /backend/api/src/main/resources/static/mono-cyrillic-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shonk-software/corewar/HEAD/backend/api/src/main/resources/static/mono-cyrillic-ext.woff2 -------------------------------------------------------------------------------- /frontend/app/src/components/jsonDisplay/JsonDisplay.module.css: -------------------------------------------------------------------------------- 1 | .jsonDisplayContainer { 2 | width: 400px; 3 | height: 500px; 4 | border: 1px solid white; 5 | 6 | overflow: scroll; 7 | } 8 | -------------------------------------------------------------------------------- /frontend/app/src/components/canvasVisu/CanvasVisu.css: -------------------------------------------------------------------------------- 1 | #canvasContainer { 2 | width: 100%; 3 | height: 100%; 4 | 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | } 9 | -------------------------------------------------------------------------------- /frontend/app/src/consts.ts: -------------------------------------------------------------------------------- 1 | export const BASE_POLLING_INTERVAL_MS = 1000; 2 | 3 | //this global variable should be removed once the max players depend on the lobby 4 | export const MAX_PLAYERS_PER_LOBBY = 2; 5 | -------------------------------------------------------------------------------- /frontend/app/babel.config.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@babel/preset-env', 4 | ['@babel/preset-react', {runtime: 'automatic'}], 5 | '@babel/preset-typescript', 6 | ], 7 | }; -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/V0Result.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable data class V0Result(val winner: V0Winner) 6 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/GameResult.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable data class GameResult(val winner: Winner) 6 | -------------------------------------------------------------------------------- /backend/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" 3 | } 4 | 5 | rootProject.name = "backend" 6 | 7 | include("api") 8 | include("shork") 9 | include("testing") 10 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/outgoing/DeleteLobbyPort.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.outgoing 2 | 3 | interface DeleteLobbyPort { 4 | fun deleteLobby(lobbyId: Long): Result 5 | } 6 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/Winner.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | enum class Winner { 7 | A, 8 | B, 9 | DRAW, 10 | } 11 | -------------------------------------------------------------------------------- /frontend/app/src/lib/DefaultTileProps.ts: -------------------------------------------------------------------------------- 1 | export const defaultTileProps = { 2 | fill: "#000000", 3 | isDimmed: false, 4 | stroke: "#808080", 5 | strokeWidth: "1", 6 | identifier: "", 7 | textContent: "", 8 | textColor: "#FFFFFF", 9 | }; 10 | -------------------------------------------------------------------------------- /backend/api/exampleRequests/getCompilationErrors.http: -------------------------------------------------------------------------------- 1 | ### 2 | # Submit code for player A, will run until the end of the game 3 | POST http://localhost:8080/api/v1/redcode/compile/errors 4 | Content-Type: application/json 5 | 6 | { 7 | "code": "mov 0, 1" 8 | } -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/V0Winner.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | enum class V0Winner { 7 | A, 8 | B, 9 | UNDECIDED, 10 | } 11 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/exceptions/LobbyNotFoundException.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain.exceptions 2 | 3 | class LobbyNotFoundException(val lobbyId: Long) : 4 | NoSuchElementException("Lobby with id $lobbyId not found!") 5 | -------------------------------------------------------------------------------- /frontend/app/src/components/footer/Footer.css: -------------------------------------------------------------------------------- 1 | @import "../../vars.css"; 2 | 3 | footer { 4 | height: var(--FOOTER-HEIGHT); 5 | width: 100%; 6 | 7 | display: flex; 8 | flex-direction: row; 9 | justify-content: center; 10 | align-items: center; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/src/domain/HexagonalTileProps.tsx: -------------------------------------------------------------------------------- 1 | export interface HexagonalTileProps { 2 | fill: string; 3 | isDimmed: boolean; 4 | stroke: string; 5 | strokeWidth: string; 6 | identifier: string; 7 | textContent: string; 8 | textColor: string; 9 | } 10 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/ICloneable.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal 2 | 3 | /** Interface for cloneable objects. */ 4 | internal interface ICloneable { 5 | /** Clones the object, creating a deep copy. */ 6 | fun deepCopy(): T 7 | } 8 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/GameState.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | enum class GameState { 7 | NOT_STARTED, 8 | RUNNING, 9 | FINISHED, 10 | } 11 | -------------------------------------------------------------------------------- /.git-authors: -------------------------------------------------------------------------------- 1 | authors: 2 | sa: Say 3 | nt: nikkitschierske 4 | ms: Cr1spyB4con 5 | ab: stinerthelion 6 | email_addresses: 7 | sa: sailsman@tutanota.com 8 | nt: nikki@schnelle.dev 9 | ms: maximschlaht@gmail.com 10 | ab: abdel.ab1997@gmail.com 11 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/exceptions/LobbyAlreadyCompletedException.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain.exceptions 2 | 3 | class LobbyAlreadyCompletedException(val lobbyId: Long) : 4 | Exception("Lobby with id $lobbyId has already completed!") 5 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/memory/ResolvedAddresses.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.memory 2 | 3 | internal class ResolvedAddresses( 4 | val aFieldRead: Int, 5 | val aFieldWrite: Int, 6 | val bFieldRead: Int, 7 | val bFieldWrite: Int, 8 | ) 9 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/outgoing/SaveLobbyPort.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.outgoing 2 | 3 | import software.shonk.lobby.domain.Lobby 4 | 5 | interface SaveLobbyPort { 6 | fun saveLobby(lobby: Lobby): Result 7 | } 8 | -------------------------------------------------------------------------------- /frontend/app/src/components/hexagonalBoardBackground/HexagonalBoardBackground.css: -------------------------------------------------------------------------------- 1 | .background-animation { 2 | position: fixed; 3 | z-index: -1; 4 | top: -500px; 5 | left: -500px; 6 | height: auto; 7 | width: auto; 8 | opacity: 0.2; 9 | 10 | transform: rotateZ(15deg); 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/src/pages/waitingForResult/WaitingForResult.module.css: -------------------------------------------------------------------------------- 1 | #waitingForResultHeadline { 2 | width: fit-content; 3 | margin-top: 50px; 4 | } 5 | 6 | #loadingSpinnerContainer { 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | height: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /backend/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Oct 14 13:54:40 CEST 2024 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /frontend/app/src/pages/waitingForOpponent/WaitingForOpponent.module.css: -------------------------------------------------------------------------------- 1 | #waitingForOpponentHeadline { 2 | width: fit-content; 3 | margin-top: 50px; 4 | } 5 | 6 | #loadingSpinnerContainer { 7 | display: flex; 8 | justify-content: center; 9 | align-items: center; 10 | height: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ], 7 | "compilerOptions": { 8 | "baseUrl": ".", 9 | "paths": { 10 | "@/*": ["./src/*"] 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /backend/api/exampleRequests/openapiv0.http: -------------------------------------------------------------------------------- 1 | ### 2 | GET http://localhost:8080/api/v0/docs/scalar.html 3 | 4 | ### 5 | GET http://localhost:8080/resources/scalar.js 6 | 7 | ### 8 | GET http://localhost:8080/api/v0/docs/openapi.yaml 9 | 10 | ### 11 | GET http://localhost:8080/api/v0/docs 12 | 13 | ### -------------------------------------------------------------------------------- /backend/api/exampleRequests/openapiv1.http: -------------------------------------------------------------------------------- 1 | ### 2 | GET http://localhost:8080/api/v1/docs/scalar.html 3 | 4 | ### 5 | GET http://localhost:8080/resources/scalar.js 6 | 7 | ### 8 | GET http://localhost:8080/api/v1/docs/openapi.yaml 9 | 10 | ### 11 | GET http://localhost:8080/api/v1/docs 12 | 13 | ### -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/GetAllLobbiesQuery.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.domain.LobbyStatus 4 | 5 | interface GetAllLobbiesQuery { 6 | 7 | fun getAllLobbies(): Result> 8 | } 9 | -------------------------------------------------------------------------------- /scripts/deployment/flask-deployment.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Flask Deployment API 3 | After=network.target 4 | 5 | [Service] 6 | ExecStart=/usr/bin/env gunicorn --bind 0.0.0.0:5000 --timeout 120 --workers 3 deployment:app 7 | Restart=always 8 | 9 | [Install] 10 | WantedBy=default.target 11 | 12 | -------------------------------------------------------------------------------- /frontend/app/src/domain/User.ts: -------------------------------------------------------------------------------- 1 | import { ValidUsernames } from "./validUsernames.ts"; 2 | 3 | export class User { 4 | public name: string; 5 | public colorHex: string; 6 | 7 | constructor(name: ValidUsernames, colorHex: string) { 8 | this.name = name; 9 | this.colorHex = colorHex; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/src/components/loadingSpinner/LoadingSpinner.module.css: -------------------------------------------------------------------------------- 1 | @keyframes rotateSpinner { 2 | 0% { 3 | transform: rotate(0deg); 4 | } 5 | 100% { 6 | transform: rotate(360deg); 7 | } 8 | } 9 | 10 | .loadingSpinner { 11 | animation: rotateSpinner 2s linear infinite; 12 | transform-origin: center; 13 | } 14 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/error/TokenizerError.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.error 2 | 3 | internal class TokenizerError 4 | internal constructor(message: String, lineNumber: Int, charIndexStart: Int, charIndexEnd: Int) : 5 | AbstractCompilerError(message, lineNumber, charIndexStart, charIndexEnd) 6 | -------------------------------------------------------------------------------- /frontend/app/src/pages/playerSelection/PlayerSelection.module.css: -------------------------------------------------------------------------------- 1 | .player-icon { 2 | width: 31rem; 3 | height: 31rem; 4 | transition: transform 300ms; 5 | } 6 | 7 | .player-icon-disabled { 8 | filter: grayscale(100%); 9 | cursor: not-allowed; 10 | } 11 | 12 | .player-icon:hover { 13 | transform: scale(1.1); 14 | } 15 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/JoinLobbyUseCase.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.joinLobby.JoinLobbyCommand 4 | 5 | interface JoinLobbyUseCase { 6 | fun joinLobby(joinLobbyCommand: JoinLobbyCommand): Result 7 | } 8 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/interpreter/domain/CompileError.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class CompileError( 7 | val line: Int, 8 | val message: String, 9 | val columnStart: Int, 10 | val columnEnd: Int, 11 | ) 12 | -------------------------------------------------------------------------------- /frontend/app/src/domain/StatusResponse.ts: -------------------------------------------------------------------------------- 1 | import { GameState } from "@/domain/GameState.ts"; 2 | import { GameWinner } from "@/domain/GameWinner.ts"; 3 | 4 | export interface StatusResponse { 5 | playerASubmitted: boolean; 6 | playerBSubmitted: boolean; 7 | gameState: GameState; 8 | result: { 9 | winner: GameWinner; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Default bug report template 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Current behavior and impact: 11 | ... 12 | 13 | Steps to reproduce: 14 | 1. ... 15 | 2. ... 16 | 17 | Expected behavior: 18 | ... 19 | 20 | Acceptance Criteria: 21 | - [x] ... 22 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/interpreter/application/port/incoming/GetCompilationErrorsQuery.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.application.port.incoming 2 | 3 | import software.shonk.interpreter.domain.CompileError 4 | 5 | interface GetCompilationErrorsQuery { 6 | 7 | fun getCompilationErrors(code: String): List 8 | } 9 | -------------------------------------------------------------------------------- /frontend/app/src/components/footer/Footer.tsx: -------------------------------------------------------------------------------- 1 | import "./Footer.css"; 2 | 3 | function Footer() { 4 | return ( 5 |
6 |
7 |

8 | No sharks were harmed during the creation of this site. 9 |

10 |
11 |
12 | ); 13 | } 14 | 15 | export default Footer; 16 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/CreateLobbyUseCase.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.createLobby.CreateLobbyCommand 4 | 5 | interface CreateLobbyUseCase { 6 | fun createLobby(createLobbyCommand: CreateLobbyCommand): Result 7 | } 8 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/V0Status.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class V0Status( 7 | val playerASubmitted: Boolean, 8 | val playerBSubmitted: Boolean, 9 | val gameState: GameState, 10 | val result: V0Result, 11 | ) 12 | -------------------------------------------------------------------------------- /frontend/app/src/pages/ErrorPage.tsx: -------------------------------------------------------------------------------- 1 | import { useRouteError } from "react-router-dom"; 2 | 3 | export default function ErrorPage() { 4 | const error = useRouteError(); 5 | console.error(error); 6 | 7 | return ( 8 |
9 |

Oops!

10 |

Sorry, an unexpected error has occurred.

11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/adapters/incoming/createLobby/CreateLobbyCommand.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.adapters.incoming.createLobby 2 | 3 | import software.shonk.lobby.domain.PlayerNameString 4 | 5 | data class CreateLobbyCommand(val playerName: PlayerNameString) { 6 | 7 | constructor(playerName: String?) : this(PlayerNameString.from(playerName)) 8 | } 9 | -------------------------------------------------------------------------------- /backend/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | kotlin("jvm") version "2.0.20" 3 | } 4 | 5 | group = "software.shonk" 6 | version = "1.0-SNAPSHOT" 7 | 8 | repositories { 9 | mavenCentral() 10 | } 11 | 12 | dependencies { 13 | testImplementation(kotlin("test")) 14 | } 15 | 16 | tasks.test { 17 | useJUnitPlatform() 18 | } 19 | kotlin { 20 | jvmToolchain(21) 21 | } 22 | -------------------------------------------------------------------------------- /frontend/app/src/components/canvasVisu/CanvasVisuProps.ts: -------------------------------------------------------------------------------- 1 | import { HexagonalTileProps } from "@/domain/HexagonalTileProps.tsx"; 2 | 3 | export interface CanvasVisuProps { 4 | defaultTileProps: HexagonalTileProps; 5 | canvasWidth: number; 6 | canvasHeight: number; 7 | hex_count: number; 8 | scale_factor_for_space_between_hexes: number; 9 | cornerRadius: number; 10 | } 11 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/exceptions/PlayerNotInLobbyException.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain.exceptions 2 | 3 | import software.shonk.lobby.domain.PlayerNameString 4 | 5 | class PlayerNotInLobbyException(playerNameString: PlayerNameString, val lobbyId: Long) : 6 | Exception("Player ${playerNameString.getName()} has not joined lobby $lobbyId yet") 7 | -------------------------------------------------------------------------------- /frontend/app/src/components/loadingSpinner/LoadingSpinner.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./LoadingSpinner.module.css"; 2 | 3 | function LoadingSpinner() { 4 | return ( 5 | Loading spinner 12 | ); 13 | } 14 | 15 | export default LoadingSpinner; 16 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/AddProgramToLobbyUseCase.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.addProgramToLobby.AddProgramToLobbyCommand 4 | 5 | interface AddProgramToLobbyUseCase { 6 | fun addProgramToLobby(addProgramToLobbyCommand: AddProgramToLobbyCommand): Result 7 | } 8 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/SetLobbySettingsUseCase.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.setLobbySettings.SetLobbySettingsCommand 4 | 5 | interface SetLobbySettingsUseCase { 6 | 7 | fun setLobbySettings(setLobbySettingsCommand: SetLobbySettingsCommand): Result 8 | } 9 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/exceptions/PlayerAlreadyJoinedException.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain.exceptions 2 | 3 | import software.shonk.lobby.domain.PlayerNameString 4 | 5 | class PlayerAlreadyJoinedLobbyException(playerNameString: PlayerNameString, val lobbyId: Long) : 6 | Exception("Player ${playerNameString.getName()} already joined lobby $lobbyId") 7 | -------------------------------------------------------------------------------- /e2e/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "e2e", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "npx playwright test --reporter=line --workers=1" 7 | }, 8 | "keywords": [], 9 | "author": "", 10 | "license": "ISC", 11 | "description": "", 12 | "devDependencies": { 13 | "@playwright/test": "^1.48.0", 14 | "@types/node": "^22.7.5" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/outgoing/LoadLobbyPort.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.outgoing 2 | 3 | import software.shonk.lobby.domain.Lobby 4 | import software.shonk.lobby.domain.LobbyStatus 5 | 6 | interface LoadLobbyPort { 7 | fun getLobby(lobbyId: Long): Result 8 | 9 | fun getAllLobbies(): Result> 10 | } 11 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/Status.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | @Serializable 6 | data class Status( 7 | val playerASubmitted: Boolean, 8 | val playerBSubmitted: Boolean, 9 | val gameState: GameState, 10 | val result: GameResult, 11 | var visualizationData: List, 12 | ) 13 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/GameResult.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter 2 | 3 | import software.shonk.interpreter.internal.statistics.RoundInformation 4 | 5 | data class GameResult(val outcome: GameOutcome, val roundInformation: List) 6 | 7 | data class GameOutcome(val player: String?, val kind: OutcomeKind) 8 | 9 | enum class OutcomeKind { 10 | WIN, 11 | DRAW, 12 | } 13 | -------------------------------------------------------------------------------- /frontend/app/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | *.tsbuildinfo 16 | 17 | # Editor directories and files 18 | .vscode/* 19 | !.vscode/extensions.json 20 | .idea 21 | .DS_Store 22 | *.suo 23 | *.ntvs* 24 | *.njsproj 25 | *.sln 26 | *.sw? 27 | -------------------------------------------------------------------------------- /frontend/app/src/components/jsonDisplay/JsonDisplay.tsx: -------------------------------------------------------------------------------- 1 | import styles from "./JsonDisplay.module.css"; 2 | 3 | // expects object, will convert to string on its own 4 | function JsonDisplay({ json }: { json: unknown }) { 5 | return ( 6 |
7 |
{JSON.stringify(json, null, 2)}
8 |
9 | ); 10 | } 11 | 12 | export default JsonDisplay; 13 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/exceptions/NoCodeForPlayerException.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain.exceptions 2 | 3 | import software.shonk.lobby.domain.PlayerNameString 4 | 5 | class NoCodeForPlayerException(playerNameString: PlayerNameString, val lobbyId: Long) : 6 | Exception( 7 | "Player ${playerNameString.getName()} has not submitted any code in lobby $lobbyId yet" 8 | ) 9 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/error/AbstractCompilerError.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.error 2 | 3 | abstract class AbstractCompilerError 4 | internal constructor( 5 | val message: String, 6 | val lineNumber: Int, 7 | val lineCharIndexStart: Int, 8 | val lineCharIndexEnd: Int, 9 | ) { 10 | override fun toString(): String { 11 | return message 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/adapters/incoming/getLobbySettings/GetLobbySettingsCommand.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.adapters.incoming.getLobbySettings 2 | 3 | import software.shonk.lobby.domain.LobbyId 4 | 5 | data class GetLobbySettingsCommand(val lobbyId: LobbyId) { 6 | 7 | constructor(lobbyId: String?) : this(LobbyId(lobbyId)) 8 | 9 | constructor(lobbyId: Long) : this(LobbyId(lobbyId)) 10 | } 11 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/GetLobbyStatusQuery.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.getLobbyStatus.GetLobbyStatusCommand 4 | import software.shonk.lobby.domain.Status 5 | 6 | interface GetLobbyStatusQuery { 7 | 8 | fun getLobbyStatus(getLobbyStatusCommand: GetLobbyStatusCommand): Result 9 | } 10 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/LobbyStatus.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | import kotlinx.serialization.Serializable 4 | 5 | // todo lobby itself should only contain metadata in the future and not the visu data and live game 6 | // data and stuff. once we do that, this can be removed 7 | @Serializable 8 | data class LobbyStatus(val id: Long, val playersJoined: List, val gameState: String) 9 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/error/ParserError.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.error 2 | 3 | import software.shonk.interpreter.internal.compiler.Token 4 | 5 | internal class ParserError 6 | internal constructor( 7 | message: String, 8 | line: Int, 9 | columnStart: Int, 10 | columnEnd: Int, 11 | internal val token: Token?, 12 | ) : AbstractCompilerError(message, line, columnStart, columnEnd) 13 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/statistics/RoundInformation.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.statistics 2 | 3 | data class RoundInformation( 4 | val playerId: String, 5 | val programCounterBefore: Int, 6 | val programCounterAfter: Int, 7 | val programCountersOfOtherProcesses: List, 8 | val memoryReads: List, 9 | val memoryWrites: List, 10 | val processDied: Boolean, 11 | ) 12 | -------------------------------------------------------------------------------- /frontend/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | COREWAR 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /scripts/deployment/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.8.2 2 | click==8.1.7 3 | Deprecated==1.2.14 4 | Flask==3.0.3 5 | Flask-Limiter==3.8.0 6 | gunicorn==23.0.0 7 | importlib_resources==6.4.5 8 | itsdangerous==2.2.0 9 | Jinja2==3.1.6 10 | limits==3.13.0 11 | markdown-it-py==3.0.0 12 | MarkupSafe==3.0.2 13 | mdurl==0.1.2 14 | ordered-set==4.1.0 15 | packaging==24.1 16 | Pygments==2.18.0 17 | rich==13.9.3 18 | typing_extensions==4.12.2 19 | Werkzeug==3.0.6 20 | wrapt==1.16.0 21 | -------------------------------------------------------------------------------- /frontend/app/src/components/three/Torus.tsx: -------------------------------------------------------------------------------- 1 | function Torus({ 2 | torusProps, 3 | rotation, 4 | }: { 5 | torusProps: unknown; 6 | rotation: [number, number, number]; 7 | }) { 8 | return ( 9 | <> 10 | 11 | { 12 | // eslint-disable-next-line 13 | // @ts-ignore 14 | 15 | } 16 | 17 | 18 | 19 | ); 20 | } 21 | 22 | export default Torus; 23 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/GetProgramFromPlayerInLobbyQuery.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.getProgramFromPlayerInLobby.GetProgramFromPlayerInLobbyCommand 4 | 5 | interface GetProgramFromPlayerInLobbyQuery { 6 | fun getProgramFromPlayerInLobby( 7 | getProgramFromPlayerInLobbyCommand: GetProgramFromPlayerInLobbyCommand 8 | ): Result 9 | } 10 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/port/incoming/GetLobbySettingsQuery.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.port.incoming 2 | 3 | import software.shonk.lobby.adapters.incoming.getLobbySettings.GetLobbySettingsCommand 4 | import software.shonk.lobby.domain.InterpreterSettings 5 | 6 | interface GetLobbySettingsQuery { 7 | 8 | fun getLobbySettings( 9 | getLobbySettingsCommand: GetLobbySettingsCommand 10 | ): Result 11 | } 12 | -------------------------------------------------------------------------------- /backend/api/README.md: -------------------------------------------------------------------------------- 1 | # Corewar API 2 | 3 | Lorem ipsum... 4 | 5 | ## Local setup 6 | - configured to use gradle 8.10 and jvm 22 7 | -> Get yourself a matching jdk 8 | // Todo: write step-by-step guide 9 | 10 | Hit localhost:8080/api with GET for a basic hello world. 11 | 12 | ## Stuff 13 | - The controllers should not do any direct validation. This should be delegated to the constructors of the commands! 14 | - Avoid mocks wherever possible and instead rely on simple in-memory adapters and fakes. 15 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/GameStatus.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal 2 | 3 | import software.shonk.interpreter.internal.program.AbstractProgram 4 | 5 | internal sealed class GameStatus { 6 | data object NOT_STARTED : GameStatus() 7 | 8 | data class FINISHED(val state: FinishedState) : GameStatus() 9 | } 10 | 11 | internal sealed class FinishedState { 12 | data class WINNER(val winner: AbstractProgram) : FinishedState() 13 | 14 | data object DRAW : FinishedState() 15 | } 16 | -------------------------------------------------------------------------------- /frontend/app/components.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://ui.shadcn.com/schema.json", 3 | "style": "default", 4 | "rsc": false, 5 | "tsx": true, 6 | "tailwind": { 7 | "config": "tailwind.config.js", 8 | "css": "src/index.css", 9 | "baseColor": "gray", 10 | "cssVariables": true, 11 | "prefix": "" 12 | }, 13 | "aliases": { 14 | "components": "@/components", 15 | "utils": "@/lib/utils", 16 | "ui": "@/components/ui", 17 | "lib": "@/lib", 18 | "hooks": "@/hooks" 19 | } 20 | } -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/addressing/Modifier.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.addressing 2 | 3 | internal enum class Modifier { 4 | A, 5 | B, 6 | AB, 7 | BA, 8 | F, 9 | X, 10 | I; 11 | 12 | override fun toString(): String { 13 | return when (this) { 14 | A -> "A" 15 | B -> "B" 16 | AB -> "AB" 17 | BA -> "BA" 18 | F -> "F" 19 | X -> "X" 20 | I -> "I" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/default-story.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Default Story 3 | about: Default template to aid story creation 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | As $STAKEHOLDER 11 | 12 | I want $FEATURE / We need $XYZ 13 | 14 | Because $REASON 15 | 16 | NOTES: 17 | - Note 1 18 | - Note 2 19 | 20 | BLOCKERS: 21 | - [ ] #123 22 | - [ ] #456 23 | 24 | Acceptance Criteria: 25 | - [ ] Criteria 1 26 | - [ ] Criteria 2 27 | - [ ] The code is fully tested or a good explanation given why it should not or cannot be tested 28 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/application/service/GetAllLobbiesService.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.application.service 2 | 3 | import software.shonk.lobby.application.port.incoming.GetAllLobbiesQuery 4 | import software.shonk.lobby.application.port.outgoing.LoadLobbyPort 5 | import software.shonk.lobby.domain.LobbyStatus 6 | 7 | class GetAllLobbiesService(val loadLobbyPort: LoadLobbyPort) : GetAllLobbiesQuery { 8 | override fun getAllLobbies(): Result> { 9 | return loadLobbyPort.getAllLobbies() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.github/workflows/image-retention-policy.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | schedule: 4 | - cron: "5 0 * * *" # every day 5 | 6 | jobs: 7 | clean: 8 | runs-on: ubuntu-latest 9 | name: Delete old test images 10 | steps: 11 | - uses: snok/container-retention-policy@v3.0.0 12 | with: 13 | account: snok 14 | token: ${{ secrets.PAT }} 15 | image-names: "container-retention-policy" 16 | image-tags: "!latest" 17 | keep-n-most-recent: 5 18 | cut-off: 1w 19 | dry-run: true 20 | -------------------------------------------------------------------------------- /backend/api/src/main/resources/openapi/v0/scalar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Scalar API Reference 5 | 6 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /backend/api/src/main/resources/openapi/v1/scalar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Scalar API Reference 5 | 6 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/domain/LobbyId.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.domain 2 | 3 | data class LobbyId(val id: Long) { 4 | init { 5 | require(id >= 0) { "The Lobby id must be non-negative." } 6 | } 7 | 8 | constructor(id: String?) : this(from(id)) 9 | 10 | companion object { 11 | fun from(lobbyIdString: String?): Long { 12 | return lobbyIdString?.toLongOrNull()?.takeIf { it >= 0 } 13 | ?: throw IllegalArgumentException("Failed to parse Lobby id: $lobbyIdString") 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /frontend/app/src/lib/usePageVisibility.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | 3 | export function usePageVisibility() { 4 | const [isPageVisible, setIsPageVisible] = useState(!document.hidden); 5 | 6 | useEffect(() => { 7 | const handleVisibilityChange = () => { 8 | setIsPageVisible(!document.hidden); 9 | }; 10 | 11 | document.addEventListener("visibilitychange", handleVisibilityChange); 12 | 13 | return () => { 14 | document.removeEventListener("visibilitychange", handleVisibilityChange); 15 | }; 16 | }, []); 17 | 18 | return isPageVisible; 19 | } 20 | -------------------------------------------------------------------------------- /frontend/app/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/adapters/incoming/setLobbySettings/SetLobbySettingsCommand.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.adapters.incoming.setLobbySettings 2 | 3 | import software.shonk.lobby.domain.InterpreterSettings 4 | import software.shonk.lobby.domain.LobbyId 5 | 6 | data class SetLobbySettingsCommand(val lobbyId: LobbyId, val settings: InterpreterSettings) { 7 | 8 | constructor(lobbyId: String?, settings: InterpreterSettings) : this(LobbyId(lobbyId), settings) 9 | 10 | constructor(lobbyId: Long, settings: InterpreterSettings) : this(LobbyId(lobbyId), settings) 11 | } 12 | -------------------------------------------------------------------------------- /frontend/app/src/domain/LobbyStatus.ts: -------------------------------------------------------------------------------- 1 | import { GameState } from "./GameState"; 2 | 3 | export interface LobbyStatus { 4 | playerASubmitted: boolean; 5 | playerBSubmitted: boolean; 6 | gameState: GameState; 7 | result: { 8 | winner: "A" | "B" | "DRAW"; 9 | }; 10 | visualizationData: LogicalVisuStep[]; 11 | } 12 | 13 | export interface LogicalVisuStep { 14 | playerId: "playerA" | "playerB"; 15 | programCounterBefore: number; 16 | programCounterAfter: number; 17 | programCountersOfOtherProcesses: number[]; 18 | memoryReads: number[]; 19 | memoryWrites: number[]; 20 | processDied: boolean; 21 | } 22 | -------------------------------------------------------------------------------- /frontend/app/src/components/tempHelpersForTestingManually/RemoveBeforeProdMvpUserTester.tsx: -------------------------------------------------------------------------------- 1 | import { useDispatchUser } from "@/services/userContext/UserContextHelpers.ts"; 2 | 3 | function RemoveBeforeProdMvpUserTester() { 4 | const dispatch = useDispatchUser(); 5 | 6 | function switchToPlayerB(): void { 7 | if (dispatch) { 8 | dispatch({ 9 | type: "setPlayerB", 10 | user: null, 11 | }); 12 | } 13 | } 14 | 15 | return ( 16 | 23 | ); 24 | } 25 | 26 | export default RemoveBeforeProdMvpUserTester; 27 | -------------------------------------------------------------------------------- /frontend/app/src/hooks/useTheme.ts: -------------------------------------------------------------------------------- 1 | import { Theme } from "@/domain/Theme"; 2 | import { createContext, useContext } from "react"; 3 | 4 | type ThemeProviderState = { 5 | theme: Theme; 6 | setTheme: (theme: Theme) => void; 7 | }; 8 | 9 | const initialState: ThemeProviderState = { 10 | theme: "system", 11 | setTheme: () => null, 12 | }; 13 | 14 | export const ThemeProviderContext = 15 | createContext(initialState); 16 | 17 | export const useTheme = () => { 18 | const context = useContext(ThemeProviderContext); 19 | 20 | if (context === undefined) 21 | throw new Error("useTheme must be used within a ThemeProvider"); 22 | 23 | return context; 24 | }; 25 | -------------------------------------------------------------------------------- /backend/api/src/main/kotlin/software/shonk/lobby/adapters/incoming/joinLobby/JoinLobbyCommand.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.lobby.adapters.incoming.joinLobby 2 | 3 | import software.shonk.lobby.domain.LobbyId 4 | import software.shonk.lobby.domain.PlayerNameString 5 | 6 | data class JoinLobbyCommand(val lobbyId: LobbyId, val playerName: PlayerNameString) { 7 | constructor( 8 | lobbyIdString: String?, 9 | playerName: String?, 10 | ) : this(LobbyId(lobbyIdString), PlayerNameString.from(playerName)) 11 | 12 | constructor( 13 | lobbyIdString: Long, 14 | playerName: String?, 15 | ) : this(LobbyId(lobbyIdString), PlayerNameString.from(playerName)) 16 | } 17 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/process/AbstractProcess.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.process 2 | 3 | import software.shonk.interpreter.internal.program.AbstractProgram 4 | 5 | internal abstract class AbstractProcess(val program: AbstractProgram, var programCounter: Int) { 6 | /** 7 | * This flag is used to prevent the program counter from being incremented and gets reset at the 8 | * end of the tick 9 | */ 10 | var dontIncrementProgramCounter: Boolean = false 11 | 12 | /** 13 | * This function will be called once on every turn and executes the next instruction in the 14 | * process 15 | */ 16 | abstract fun tick() 17 | } 18 | -------------------------------------------------------------------------------- /frontend/app/src/components/three/Text.tsx: -------------------------------------------------------------------------------- 1 | import roboto from "../../assets/Roboto Mono_Regular.json"; 2 | import { Center, Text3D } from "@react-three/drei"; 3 | import { ReactNode } from "react"; 4 | 5 | function Text({ children }: { children: ReactNode }) { 6 | return ( 7 | 8 |
9 | 20 | {children} 21 | 22 | 23 |
24 |
25 | ); 26 | } 27 | 28 | export default Text; 29 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/memory/ICore.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.memory 2 | 3 | import software.shonk.interpreter.internal.instruction.AbstractInstruction 4 | 5 | /** The interface for the memory core */ 6 | internal interface ICore { 7 | /** Loads the instruction at the given address */ 8 | fun loadAbsolute(address: Int): AbstractInstruction 9 | 10 | /** Writes an instruction to the given address */ 11 | fun storeAbsolute(address: Int, instruction: AbstractInstruction) 12 | 13 | /** 14 | * Resolves both the a-field and the b-field addresses, respecting the read and write distance 15 | * for each 16 | */ 17 | fun resolveFields(sourceAddress: Int): ResolvedAddresses 18 | } 19 | -------------------------------------------------------------------------------- /frontend/app/public/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /frontend/app/vite.config.ts: -------------------------------------------------------------------------------- 1 | import path from "path" 2 | import { defineConfig } from 'vitest/config' 3 | import react from '@vitejs/plugin-react' 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react()], 8 | resolve: { 9 | alias: { 10 | "@": path.resolve(__dirname, "./src"), 11 | }, 12 | }, 13 | test: { 14 | environment: 'jsdom', 15 | globals: true, 16 | setupFiles: [ 17 | "./__setups__/canvas.js" 18 | ], 19 | deps: { 20 | optimizer: { 21 | web: { 22 | include: ['vitest-canvas-mock'] 23 | } 24 | } 25 | }, 26 | environmentOptions: { 27 | jsdom: { 28 | resources: 'usable', 29 | }, 30 | }, 31 | } 32 | }) 33 | -------------------------------------------------------------------------------- /backend/shork/src/main/kotlin/internal/process/Process.kt: -------------------------------------------------------------------------------- 1 | package software.shonk.interpreter.internal.process 2 | 3 | import software.shonk.interpreter.internal.program.AbstractProgram 4 | 5 | internal class Process(program: AbstractProgram, programCounter: Int) : 6 | AbstractProcess(program, programCounter) { 7 | override fun tick() { 8 | val instruction = this.program.shork.memoryCore.loadAbsolute(programCounter) 9 | val resolvedAddresses = this.program.shork.memoryCore.resolveFields(programCounter) 10 | instruction.execute(this, resolvedAddresses) 11 | if (!this.dontIncrementProgramCounter) { 12 | this.programCounter++ 13 | } 14 | 15 | this.dontIncrementProgramCounter = false 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /frontend/app/src/components/requireLogout/RequireLogout.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | useDispatchUser, 3 | useUser, 4 | } from "@/services/userContext/UserContextHelpers"; 5 | import { ReactNode, useEffect } from "react"; 6 | 7 | interface RequireUserProps { 8 | blocked: boolean; 9 | children: ReactNode; 10 | } 11 | 12 | export function RequireLogout({ 13 | blocked, 14 | children, 15 | }: Readonly) { 16 | const user = useUser(); 17 | const dispatcher = useDispatchUser(); 18 | 19 | useEffect(handleUserChanges, [blocked, dispatcher, user]); 20 | 21 | function handleUserChanges() { 22 | if (user && dispatcher && !blocked) { 23 | dispatcher({ 24 | type: "logout", 25 | user: null, 26 | }); 27 | } 28 | } 29 | 30 | return <>{children}; 31 | } 32 | -------------------------------------------------------------------------------- /backend/.gitignore: -------------------------------------------------------------------------------- 1 | **/.gradle 2 | **/build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### IntelliJ IDEA ### 8 | .idea/modules.xml 9 | .idea/jarRepositories.xml 10 | .idea/compiler.xml 11 | .idea/libraries/ 12 | *.iws 13 | *.iml 14 | *.ipr 15 | out/ 16 | !**/src/main/**/out/ 17 | !**/src/test/**/out/ 18 | 19 | ### Kotlin ### 20 | .kotlin 21 | 22 | ### Eclipse ### 23 | .apt_generated 24 | .classpath 25 | .factorypath 26 | .project 27 | .settings 28 | .springBeans 29 | .sts4-cache 30 | bin/ 31 | !**/src/main/**/bin/ 32 | !**/src/test/**/bin/ 33 | 34 | ### NetBeans ### 35 | /nbproject/private/ 36 | /nbbuild/ 37 | /dist/ 38 | /nbdist/ 39 | /.nb-gradle/ 40 | 41 | ### VS Code ### 42 | .vscode/ 43 | 44 | ### Mac OS ### 45 | .DS_Store 46 | -------------------------------------------------------------------------------- /frontend/app/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "baseUrl": ".", 23 | "paths": { 24 | "@/*": [ 25 | "./src/*" 26 | ] 27 | } 28 | }, 29 | "include": ["src"] 30 | } 31 | -------------------------------------------------------------------------------- /frontend/app/src/services/lobbyContext/LobbyContextHelpers.ts: -------------------------------------------------------------------------------- 1 | import { Lobby } from "@/domain/Lobby.ts"; 2 | import { useContext } from "react"; 3 | import { 4 | LobbyContext, 5 | LobbyDispatchContext, 6 | } from "@/services/lobbyContext/LobbyContext.tsx"; 7 | 8 | export function useLobby() { 9 | return useContext(LobbyContext); 10 | } 11 | 12 | export function useDispatchLobby() { 13 | return useContext(LobbyDispatchContext); 14 | } 15 | 16 | export function lobbyReducer( 17 | _lobby: Lobby | null, 18 | action: { type: string; lobby: Lobby | null }, 19 | ) { 20 | switch (action.type) { 21 | case "join": { 22 | return action.lobby; 23 | } 24 | case "leave": { 25 | return null; 26 | } 27 | default: { 28 | throw Error("Unknown action: " + action.type); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /scripts/commit_msg_linter.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | 4 | 5 | def test(commit_msg: str) -> bool: 6 | # Define the regex pattern 7 | pattern = r"^\[\#\d+(, \#\d+)*\] \w.*" 8 | 9 | return bool(re.match(pattern, commit_msg)) 10 | 11 | 12 | if __name__ == "__main__": 13 | commit_msg_file = sys.argv[1] 14 | print(sys.argv) 15 | print() 16 | print(sys.stdin.read().strip()) 17 | with open(commit_msg_file, "r") as file: 18 | commit_msg = file.read().strip() 19 | 20 | print(commit_msg) 21 | 22 | if not test(commit_msg): 23 | print("Commit message does not meet the required format.") 24 | print("Allowed formats:") 25 | print("[#123] message") 26 | print("[#123,#456] message") 27 | print("[#123, #456] message") 28 | sys.exit(1) 29 | -------------------------------------------------------------------------------- /scripts/run_gradle.py: -------------------------------------------------------------------------------- 1 | # Change into the backend directory and run gradle for Unix and Windows inside the backend directory. 2 | 3 | import os 4 | import sys 5 | import subprocess 6 | 7 | 8 | def run_gradle(): 9 | args = sys.argv 10 | if len(args) < 2: 11 | print("Usage: python run_gradle.py ") 12 | sys.exit(1) 13 | 14 | os.chdir("backend") 15 | 16 | task = args[1] 17 | gradle = "./gradlew" if os.name == "posix" else ".\gradlew.bat" 18 | if not os.path.exists(gradle): 19 | print("gradlew not found") 20 | sys.exit(1) 21 | 22 | cmd = [gradle, task] 23 | print("Running gradle task: " + task) 24 | try: 25 | subprocess.run(cmd, check=True) 26 | except Exception: 27 | sys.exit(1) 28 | 29 | 30 | if __name__ == "__main__": 31 | run_gradle() 32 | -------------------------------------------------------------------------------- /frontend/app/taskfile.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | 3 | tasks: 4 | setup: 5 | cmds: 6 | - npm ci 7 | run: 8 | cmds: 9 | - npm run dev 10 | build: 11 | sources: 12 | - src/** 13 | - package**.json 14 | - tsconfig.json 15 | - public/** 16 | - .env** 17 | - index.html 18 | generates: 19 | - dist/** 20 | cmds: 21 | - task: setup 22 | - task: lint 23 | - task: test 24 | - task: format-check 25 | - npm run build 26 | test: 27 | cmds: 28 | - npm run test run 29 | lint: 30 | cmds: 31 | - npm run lint 32 | format: 33 | cmds: 34 | - npx prettier --write src 35 | format-check: 36 | cmds: 37 | - npx prettier --check src 38 | clean: 39 | cmds: 40 | - rm -rf node_modules 41 | - rm -rf dist 42 | -------------------------------------------------------------------------------- /frontend/app/src/components/ui/textarea.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | import { cn } from "@/lib/utils"; 4 | 5 | export type TextareaProps = React.TextareaHTMLAttributes; 6 | 7 | const Textarea = React.forwardRef( 8 | ({ className, ...props }, ref) => { 9 | return ( 10 |