dao-game / commit
Starting experimenting with multiplayer.
.vscode/launch.json | 2 +- package-lock.json | 686 ++++------------------------------------------------ package.json | 3 +- public/index.html | 82 +++---- public/online.html | 66 +++++ readme.md | 5 + src/game.ts | 261 ++++++++++++++------ src/peering.ts | 51 ++++ src/piano.ts | 36 +++ src/types.ts | 8 +- 10 files changed, 433 insertions(+), 767 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index b9fd332..1b3c68b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "name": "Launch Chrome against localhost", "url": "http://localhost:3000/", "webRoot": "${workspaceFolder}/src", - "preLaunchTask": "task: npm: start" + // "preLaunchTask": "task: npm: start" } ] } \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index bb7d6c6..edb445e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,642 +1,8 @@ { "name": "dao-game", "version": "1.0.0", - "lockfileVersion": 2, + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "name": "dao-game", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "esbuild": "^0.14.25" - }, - "devDependencies": { - "@types/node": "^17.0.21", - "rimraf": "^3.0.2", - "ts-node": "^10.6.0", - "typescript": "^4.6.2" - } - }, - "node_modules/@cspotcode/source-map-consumer": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz", - "integrity": "sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==", - "dev": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz", - "integrity": "sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-consumer": "0.8.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", - "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", - "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", - "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, - "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/esbuild": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.25.tgz", - "integrity": "sha512-4JHEIOMNFvK09ziiL+iVmldIhLbn49V4NAVo888tcGFKedEZY/Y8YapfStJ6zSE23tzYPKxqKwQBnQoIO0BI/Q==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "esbuild-android-64": "0.14.25", - "esbuild-android-arm64": "0.14.25", - "esbuild-darwin-64": "0.14.25", - "esbuild-darwin-arm64": "0.14.25", - "esbuild-freebsd-64": "0.14.25", - "esbuild-freebsd-arm64": "0.14.25", - "esbuild-linux-32": "0.14.25", - "esbuild-linux-64": "0.14.25", - "esbuild-linux-arm": "0.14.25", - "esbuild-linux-arm64": "0.14.25", - "esbuild-linux-mips64le": "0.14.25", - "esbuild-linux-ppc64le": "0.14.25", - "esbuild-linux-riscv64": "0.14.25", - "esbuild-linux-s390x": "0.14.25", - "esbuild-netbsd-64": "0.14.25", - "esbuild-openbsd-64": "0.14.25", - "esbuild-sunos-64": "0.14.25", - "esbuild-windows-32": "0.14.25", - "esbuild-windows-64": "0.14.25", - "esbuild-windows-arm64": "0.14.25" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.25.tgz", - "integrity": "sha512-L5vCUk7TzFbBnoESNoXjU3x9+/+7TDIE/1mTfy/erAfvZAqC+S3sp/Qa9wkypFMcFvN9FzvESkTlpeQDolREtQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.25.tgz", - "integrity": "sha512-4jv5xPjM/qNm27T5j3ZEck0PvjgQtoMHnz4FzwF5zNP56PvY2CT0WStcAIl6jNlsuDdN63rk2HRBIsO6xFbcFw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.25.tgz", - "integrity": "sha512-TGp8tuudIxOyWd1+8aYPxQmC1ZQyvij/AfNBa35RubixD0zJ1vkKHVAzo0Zao1zcG6pNqiSyzfPto8vmg0s7oA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.25.tgz", - "integrity": "sha512-oTcDgdm0MDVEmw2DWu8BV68pYuImpFgvWREPErBZmNA4MYKGuBRaCiJqq6jZmBR1x+3y1DWCjez+5uLtuAm6mw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.25.tgz", - "integrity": "sha512-ueAqbnMZ8arnuLH8tHwTCQYeptnHOUV7vA6px6j4zjjQwDx7TdP7kACPf3TLZLdJQ3CAD1XCvQ2sPhX+8tacvQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.25.tgz", - "integrity": "sha512-+ZVWud2HKh+Ob6k/qiJWjBtUg4KmJGGmbvEXXW1SNKS7hW7HU+Zq2ZCcE1akFxOPkVB+EhOty/sSek30tkCYug==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.25.tgz", - "integrity": "sha512-3OP/lwV3kCzEz45tobH9nj+uE4ubhGsfx+tn0L26WAGtUbmmcRpqy7XRG/qK7h1mClZ+eguIANcQntYMdYklfw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.25.tgz", - "integrity": "sha512-+aKHdHZmX9qwVlQmu5xYXh7GsBFf4TWrePgeJTalhXHOG7NNuUwoHmketGiZEoNsWyyqwH9rE5BC+iwcLY30Ug==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.25.tgz", - "integrity": "sha512-aTLcE2VBoLydL943REcAcgnDi3bHtmULSXWLbjtBdtykRatJVSxKMjK9YlBXUZC4/YcNQfH7AxwVeQr9fNxPhw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.25.tgz", - "integrity": "sha512-UxfenPx/wSZx55gScCImPtXekvZQLI2GW3qe5dtlmU7luiqhp5GWPzGeQEbD3yN3xg/pHc671m5bma5Ns7lBHw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.25.tgz", - "integrity": "sha512-wLWYyqVfYx9Ur6eU5RT92yJVsaBGi5RdkoWqRHOqcJ38Kn60QMlcghsKeWfe9jcYut8LangYZ98xO1LxIoSXrQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.25.tgz", - "integrity": "sha512-0dR6Csl6Zas3g4p9ULckEl8Mo8IInJh33VCJ3eaV1hj9+MHGdmDOakYMN8MZP9/5nl+NU/0ygpd14cWgy8uqRw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.25.tgz", - "integrity": "sha512-J4d20HDmTrgvhR0bdkDhvvJGaikH3LzXQnNaseo8rcw9Yqby9A90gKUmWpfwqLVNRILvNnAmKLfBjCKU9ajg8w==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.25.tgz", - "integrity": "sha512-YI2d5V6nTE73ZnhEKQD7MtsPs1EtUZJ3obS21oxQxGbbRw1G+PtJKjNyur+3t6nzHP9oTg6GHQ3S3hOLLmbDIQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.25.tgz", - "integrity": "sha512-TKIVgNWLUOkr+Exrye70XTEE1lJjdQXdM4tAXRzfHE9iBA7LXWcNtVIuSnphTqpanPzTDFarF0yqq4kpbC6miA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.25.tgz", - "integrity": "sha512-QgFJ37A15D7NIXBTYEqz29+uw3nNBOIyog+3kFidANn6kjw0GHZ0lEYQn+cwjyzu94WobR+fes7cTl/ZYlHb1A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.25.tgz", - "integrity": "sha512-rmWfjUItYIVlqr5EnTH1+GCxXiBOC42WBZ3w++qh7n2cS9Xo0lO5pGSG2N+huOU2fX5L+6YUuJ78/vOYvefeFw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.25.tgz", - "integrity": "sha512-HGAxVUofl3iUIz9W10Y9XKtD0bNsK9fBXv1D55N/ljNvkrAYcGB8YCm0v7DjlwtyS6ws3dkdQyXadbxkbzaKOA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.25.tgz", - "integrity": "sha512-TirEohRkfWU9hXLgoDxzhMQD1g8I2mOqvdQF2RS9E/wbkORTAqJHyh7wqGRCQAwNzdNXdg3JAyhQ9/177AadWA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.25", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.25.tgz", - "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/ts-node": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", - "integrity": "sha512-CJen6+dfOXolxudBQXnVjRVvYTmTWbyz7cn+xq2XTsvnaXbHqr4gXSCNbS2Jj8yTZMuGwUoBESLaOkLascVVvg==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "0.7.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.0", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz", - "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - } - }, "dependencies": { "@cspotcode/source-map-consumer": { "version": "0.8.0", @@ -882,6 +248,11 @@ "integrity": "sha512-4ype9ERiI45rSh+R8qUoBtaj6kJvUOI7oVLhKqPEpcF4Pa5PpT3hm/mXAyotJHREkHpM87PAJcA442mLnbtlNA==", "optional": true }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -948,6 +319,29 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "peerjs": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/peerjs/-/peerjs-1.3.2.tgz", + "integrity": "sha512-+PHfmsC7QGUU8Ye3OLi6tKQZGPCNy7QatUVNw4JtE8alkguF3+DdO5W0bzepqP2OtE9FqH/ltXt37qyvHw2CqA==", + "requires": { + "@types/node": "^10.14.33", + "eventemitter3": "^3.1.2", + "peerjs-js-binarypack": "1.0.1", + "webrtc-adapter": "^7.7.1" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + } + } + }, + "peerjs-js-binarypack": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/peerjs-js-binarypack/-/peerjs-js-binarypack-1.0.1.tgz", + "integrity": "sha512-N6aeia3NhdpV7kiGxJV5xQiZZCVEEVjRz2T2C6UZQiBkHWHzUv/oWA4myQLcwBwO8LUoR1KWW5oStvwVesmfCg==" + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -957,6 +351,19 @@ "glob": "^7.1.3" } }, + "rtcpeerconnection-shim": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz", + "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==", + "requires": { + "sdp": "^2.6.0" + } + }, + "sdp": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz", + "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==" + }, "ts-node": { "version": "10.6.0", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.6.0.tgz", @@ -990,6 +397,15 @@ "integrity": "sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==", "dev": true }, + "webrtc-adapter": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.7.1.tgz", + "integrity": "sha512-TbrbBmiQBL9n0/5bvDdORc6ZfRY/Z7JnEj+EYOD1ghseZdpJ+nF2yx14k3LgQKc7JZnG7HAcL+zHnY25So9d7A==", + "requires": { + "rtcpeerconnection-shim": "^1.2.15", + "sdp": "^2.12.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 7569d29..e9cc180 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ }, "homepage": "https://gitlab.com/fuzzy-rp/dao-game#readme", "dependencies": { - "esbuild": "^0.14.25" + "esbuild": "^0.14.25", + "peerjs": "^1.3.2" }, "devDependencies": { "@types/node": "^17.0.21", diff --git a/public/index.html b/public/index.html index 033ea5a..ae1c898 100644 --- a/public/index.html +++ b/public/index.html @@ -1,57 +1,36 @@ <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="utf-8"> + <meta charset="utf-8" /> <title>Dao Game</title> - <meta name="viewport" - content="width=device-width, initial-scale=1"> - <link rel="icon" - href="yin-yang.svg" - type="image/svg+xml"> - <link rel="stylesheet" - href="styles.css" /> - <script defer - src="bundle.js"></script> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="icon" href="yin-yang.svg" type="image/svg+xml" /> + <link rel="stylesheet" href="styles.css" /> + <script defer src="bundle.js"></script> </head> <body> - <div class="invisible"> - <p class='piece red-piece' - id='default-red-piece'></p> - <p class='piece blue-piece' - id='default-blue-piece'></p> + <p class="piece red-piece" id="default-red-piece"></p> + <p class="piece blue-piece" id="default-blue-piece"></p> </div> <main> - <div class="controls"> - - <span class="red-turn-text"> - Red's turn! - </span> + <span class="red-turn-text"> Red's turn! </span> <span class="divider">|</span> - <span class="blue-turn-text"> - Blue's turn - </span> + <span class="blue-turn-text"> Blue's turn </span> </div> - <table id="table"> - </table> + <table id="table"></table> <div class="controls"> - <button type="button" - class="button" - id="undo-button"> + <button type="button" class="button" id="undo-button"> Undo </button> - <span class="divider">|</span> - <button type="button" - class="button" - id="reset-button"> + <button type="button" class="button" id="reset-button"> Reset </button> </div> @@ -60,36 +39,35 @@ <div class="title"> <p> - Board game <a href='https://en.wikipedia.org/wiki/Dao_(game)' - target='_blank' - rel="noopener">Dao</a>. + Board game + <a + href="https://en.wikipedia.org/wiki/Dao_(game)" + target="_blank" + rel="noopener" + >Dao</a + >. </p> </div> <div class="info"> - The game consists of only one simple rule and three ways - to - win. Pieces move in a straight line, including - diagonally, - as far as possible with no jumps. The three ways to win - are - arranging your pieces in a straight line on the board - (not - diagonally), occupying the four corners, or forming a - 2x2 - square anywhere on the board. + The game consists of only one simple rule and three ways to win. + Pieces move in a straight line, including diagonally, as far as + possible with no jumps. The three ways to win are arranging your + pieces in a straight line on the board (not diagonally), occupying + the four corners, or forming a 2x2 square anywhere on the board. </div> <hr /> <div class="info"> <p> Here is the - <a href='https://gitlab.com/fuzzy-rp/dao-game' - target="_blank" - rel="noopener">source - code</a> + <a + href="https://gitlab.com/fuzzy-rp/dao-game" + target="_blank" + rel="noopener" + >source code</a + > </p> </div> </body> - </html> diff --git a/public/online.html b/public/online.html new file mode 100644 index 0000000..1d4f8ac --- /dev/null +++ b/public/online.html @@ -0,0 +1,66 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8" /> + <title>Dao Game</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <link rel="icon" href="yin-yang.svg" type="image/svg+xml" /> + <link rel="stylesheet" href="styles.css" /> + <script> + window.daoIsOnline = true; + </script> + <script defer src="bundle.js"></script> + </head> + + <body> + <div class="invisible"> + <p class="piece red-piece" id="default-red-piece"></p> + <p class="piece blue-piece" id="default-blue-piece"></p> + </div> + <main> + <div class="controls"> + <span class="red-turn-text"> Red's turn! </span> + + <span class="divider">|</span> + + <span class="blue-turn-text"> Blue's turn </span> + </div> + + <table id="table"></table> + </main> + <hr /> + + <div class="title"> + <p> + Board game + <a + href="https://en.wikipedia.org/wiki/Dao_(game)" + target="_blank" + rel="noopener" + >Dao</a + >. + </p> + </div> + + <div class="info"> + The game consists of only one simple rule and three ways to win. + Pieces move in a straight line, including diagonally, as far as + possible with no jumps. The three ways to win are arranging your + pieces in a straight line on the board (not diagonally), occupying + the four corners, or forming a 2x2 square anywhere on the board. + </div> + <hr /> + + <div class="info"> + <p> + Here is the + <a + href="https://gitlab.com/fuzzy-rp/dao-game" + target="_blank" + rel="noopener" + >source code</a + > + </p> + </div> + </body> +</html> diff --git a/readme.md b/readme.md index a5af0f1..17faa1b 100644 --- a/readme.md +++ b/readme.md @@ -4,6 +4,11 @@ 1. `npm run start` +## Debugging + +1. `npm run start` +2. Run `Launch Chrome against localhost` debug task in VSCode + ## Gitlab Pages [Location](https://fuzzy-rp.gitlab.io/dao-game/) diff --git a/src/game.ts b/src/game.ts index 60fa73c..19371a7 100644 --- a/src/game.ts +++ b/src/game.ts @@ -1,44 +1,59 @@ -import { Coord, GameBoard, ListenerManager, Move } from './types' +import { PeerComm } from "./peering"; +import { Coord, GameBoard, ListenerManager, Move } from "./types"; const constants = { - selectedPieceClassName: 'selected-piece', - selectedPlayerTextClassName: 'selected-player-text', - activePlayerPieceClassName: 'active-player-piece', - possibleMoveClassName: 'possible-move', -} + selectedPieceClassName: "selected-piece", + selectedPlayerTextClassName: "selected-player-text", + activePlayerPieceClassName: "active-player-piece", + possibleMoveClassName: "possible-move", +}; const gameBoard = new GameBoard(); const listenerManager: ListenerManager = new ListenerManager(); -const player: { isRedTurn: boolean, selectedPieceId: number | undefined, moveHistory: Move[] } = { +const player: { + isPlayerRed: boolean; + isRedTurn: boolean; + selectedPieceId: number | undefined; + moveHistory: Move[]; +} = { + isPlayerRed: false, isRedTurn: false, selectedPieceId: undefined, moveHistory: [], -} +}; // DOM references const dom = { - defaultRedPiece: document.getElementById('default-red-piece'), - defaultBluePiece: document.getElementById('default-blue-piece'), + defaultRedPiece: document.getElementById("default-red-piece"), + defaultBluePiece: document.getElementById("default-blue-piece"), cells: () => Array.from(document.querySelectorAll("td")), - allPieces: () => Array.from(document.querySelectorAll('.piece')), - playerPieces: (isRedTurn: boolean) => isRedTurn ? - Array.from(document.querySelectorAll('.red-piece:not(#default-red-piece')) : - Array.from(document.querySelectorAll('.blue-piece:not(#default-blue-piece')), + allPieces: () => Array.from(document.querySelectorAll(".piece")), + playerPieces: (isRedTurn: boolean) => + isRedTurn + ? Array.from( + document.querySelectorAll(".red-piece:not(#default-red-piece") + ) + : Array.from( + document.querySelectorAll( + ".blue-piece:not(#default-blue-piece" + ) + ), redTurnText: () => Array.from(document.querySelectorAll(".red-turn-text")), - blueTurnText: () => Array.from(document.querySelectorAll(".blue-turn-text")), - resetButton: document.getElementById('reset-button') as HTMLInputElement, - undoButton: document.getElementById('undo-button') as HTMLInputElement, -} + blueTurnText: () => + Array.from(document.querySelectorAll(".blue-turn-text")), + resetButton: document.getElementById("reset-button") as HTMLInputElement, + undoButton: document.getElementById("undo-button") as HTMLInputElement, +}; const resetBoard = () => { // resetCells - dom.cells().forEach(cell => { + dom.cells().forEach((cell) => { cell.classList.remove(constants.possibleMoveClassName); }); // reset pieces - dom.allPieces().forEach(piece => { + dom.allPieces().forEach((piece) => { if (piece.classList.contains(constants.activePlayerPieceClassName)) { piece.classList.toggle(constants.activePlayerPieceClassName); } @@ -64,16 +79,27 @@ const movePiece = async (sourceIndex: number, destIndex: number) => { dom.cells()[destIndex].appendChild(destPiece); // start animations - const destAnimation = dom.cells()[destIndex].animate([{ opacity: 0 }, { opacity: 1 }], { duration: 1000, iterations: 1 }) - const sourceAnimation = piece.animate([{ - opacity: 1, - width: '45px', - height: '45px' - }, { - opacity: 0, - width: '5px', - height: '5px' - },], { duration: 1000, iterations: 1 }); + const destAnimation = dom + .cells() + [destIndex].animate([{ opacity: 0 }, { opacity: 1 }], { + duration: 1000, + iterations: 1, + }); + const sourceAnimation = piece.animate( + [ + { + opacity: 1, + width: "45px", + height: "45px", + }, + { + opacity: 0, + width: "5px", + height: "5px", + }, + ], + { duration: 1000, iterations: 1 } + ); // await animations await Promise.all([sourceAnimation.finished, destAnimation.finished]); @@ -88,17 +114,29 @@ const movePiece = async (sourceIndex: number, destIndex: number) => { const nextMove = () => { const setActivePlayerPieces = () => { const selectPiece = (event: Event) => { - const getAllowedMoveIndicesForIndex = (boardIndex: number): number[] => { - const getFarthestCoord = (startCoord: Coord, direction: Coord): Coord => { + const getAllowedMoveIndicesForIndex = ( + boardIndex: number + ): number[] => { + const getFarthestCoord = ( + startCoord: Coord, + direction: Coord + ): Coord => { let farthestPos = undefined; let testPos = startCoord; while (true) { - const pos = new Coord(testPos.row + direction.row, testPos.col + direction.col); + const pos = new Coord( + testPos.row + direction.row, + testPos.col + direction.col + ); const index = gameBoard.coordToBoardIndex(pos); const withinBounds = - pos.row >= 0 && pos.row < gameBoard.rows && - pos.col >= 0 && pos.col < gameBoard.cols; - const isOccupied = Number.isInteger(gameBoard.board[index]); + pos.row >= 0 && + pos.row < gameBoard.rows && + pos.col >= 0 && + pos.col < gameBoard.cols; + const isOccupied = Number.isInteger( + gameBoard.board[index] + ); if (isOccupied || !withinBounds) { break; } else { @@ -112,18 +150,24 @@ const nextMove = () => { const coord = gameBoard.boardIndexToCoord(boardIndex); const farthestCoords = Coord.allDirections - .map(direction => getFarthestCoord(coord, direction)) - .filter(farCoord => farCoord !== undefined); + .map((direction) => getFarthestCoord(coord, direction)) + .filter((farCoord) => farCoord !== undefined); - const farthestIndices = farthestCoords.map(c => gameBoard.coordToBoardIndex(c)); + const farthestIndices = farthestCoords.map((c) => + gameBoard.coordToBoardIndex(c) + ); return farthestIndices; }; const previousSelectedPieceId = player.selectedPieceId; if (previousSelectedPieceId !== undefined) { - const previousPiece = document.getElementById(previousSelectedPieceId.toString()); - previousPiece.classList.remove(constants.selectedPieceClassName); - dom.cells().forEach(cell => { + const previousPiece = document.getElementById( + previousSelectedPieceId.toString() + ); + previousPiece.classList.remove( + constants.selectedPieceClassName + ); + dom.cells().forEach((cell) => { cell.classList.remove(constants.possibleMoveClassName); }); } @@ -140,10 +184,15 @@ const nextMove = () => { // 1. blink // 2. complete the move const pieceIndex = gameBoard.board.indexOf(pieceId); - const allowedMoveIndices = getAllowedMoveIndicesForIndex(pieceIndex); - allowedMoveIndices.forEach(i => { + const allowedMoveIndices = + getAllowedMoveIndicesForIndex(pieceIndex); + allowedMoveIndices.forEach((i) => { const cell = dom.cells()[i]; - listenerManager.addListener(cell, 'click', async () => await makeMove(i)); + listenerManager.addListener( + cell, + "click", + async () => await makeMove(i) + ); cell.classList.add(constants.possibleMoveClassName); }); }; @@ -158,19 +207,23 @@ const nextMove = () => { checkForWin(); nextMove(); - } + }; // mark active pieces const playerPieces = dom.playerPieces(player.isRedTurn); - playerPieces.forEach(pp => { + playerPieces.forEach((pp) => { pp.classList.add(constants.activePlayerPieceClassName); - listenerManager.addListener(pp, 'click', selectPiece); + listenerManager.addListener(pp, "click", selectPiece); }); }; // reset text - dom.redTurnText().forEach(t => t.classList.remove(constants.selectedPlayerTextClassName)); - dom.blueTurnText().forEach(t => t.classList.remove(constants.selectedPlayerTextClassName)); + dom.redTurnText().forEach((t) => + t.classList.remove(constants.selectedPlayerTextClassName) + ); + dom.blueTurnText().forEach((t) => + t.classList.remove(constants.selectedPlayerTextClassName) + ); // changePlayer // 1. flip flag @@ -178,11 +231,14 @@ const nextMove = () => { // 3. set click callbacks if (player.isRedTurn) { player.isRedTurn = false; - dom.blueTurnText().forEach(t => t.classList.add(constants.selectedPlayerTextClassName)); - } - else { + dom.blueTurnText().forEach((t) => + t.classList.add(constants.selectedPlayerTextClassName) + ); + } else { player.isRedTurn = true; - dom.redTurnText().forEach(t => t.classList.add(constants.selectedPlayerTextClassName)); + dom.redTurnText().forEach((t) => + t.classList.add(constants.selectedPlayerTextClassName) + ); } if (player.moveHistory.length === 0) { @@ -201,7 +257,7 @@ const nextMove = () => { const checkForWin = () => { const elementsToCoords = (elements: Element[]): Coord[] => { const elementsToBoardIndexes = (elements: Element[]): number[] => { - const indices = elements.map(pp => { + const indices = elements.map((pp) => { const pieceId = Number.parseInt(pp.id); const pieceIndex = gameBoard.board.indexOf(pieceId); return pieceIndex; @@ -210,20 +266,22 @@ const checkForWin = () => { }; const indices = elementsToBoardIndexes(elements); - const coords = indices.map(pieceIndex => gameBoard.boardIndexToCoord(pieceIndex)); + const coords = indices.map((pieceIndex) => + gameBoard.boardIndexToCoord(pieceIndex) + ); return coords; }; const doCoordsFormSquare = (coords: Coord[]): boolean => { - const allRows = coords.map(c => c.row); - const allCols = coords.map(c => c.col); + const allRows = coords.map((c) => c.row); + const allCols = coords.map((c) => c.col); const min = new Coord(Math.min(...allRows), Math.min(...allCols)); const max = new Coord(Math.max(...allRows), Math.max(...allCols)); const diff = max.sub(min); - const isSquare = (diff.row === 1 && diff.col === 1); + const isSquare = diff.row === 1 && diff.col === 1; return isSquare; }; - const playerCoords = elementsToCoords(dom.playerPieces(player.isRedTurn)) + const playerCoords = elementsToCoords(dom.playerPieces(player.isRedTurn)); const otherCoords = elementsToCoords(dom.playerPieces(!player.isRedTurn)); const squareCoords: Coord[] = [ new Coord(0, 0), @@ -241,12 +299,14 @@ const checkForWin = () => { // 1. on three sides of an opponent const firstPiece = playerCoords[0]; - const allInRow = playerCoords.every(pc => pc.row === firstPiece.row) - const allInCol = playerCoords.every(pc => pc.col === firstPiece.col) - const allInCorners = playerCoords.every(pc => squareCoords.findIndex(sc => pc.equals(sc)) >= 0); + const allInRow = playerCoords.every((pc) => pc.row === firstPiece.row); + const allInCol = playerCoords.every((pc) => pc.col === firstPiece.col); + const allInCorners = playerCoords.every( + (pc) => squareCoords.findIndex((sc) => pc.equals(sc)) >= 0 + ); const allInSquare = doCoordsFormSquare(playerCoords); - const winnerName = player.isRedTurn ? 'Red' : 'Blue'; + const winnerName = player.isRedTurn ? "Red" : "Blue"; let winningMessage = undefined; if (allInRow) { winningMessage = `${winnerName} wins by forming a row`; @@ -270,14 +330,14 @@ const checkForWin = () => { const init = () => { // create board and pieces let isWhite = true; - const table = document.getElementById('table'); + const table = document.getElementById("table"); for (let r = 0; r < gameBoard.rows; r++) { - const tr = document.createElement('tr'); + const tr = document.createElement("tr"); table.appendChild(tr); for (let c = 0; c < gameBoard.cols; c++) { - const td = document.createElement('td'); + const td = document.createElement("td"); tr.appendChild(td); - td.className = isWhite ? 'white' : 'black'; + td.className = isWhite ? "white" : "black"; isWhite = !isWhite; } isWhite = !isWhite; @@ -285,8 +345,12 @@ const init = () => { gameBoard.board.forEach((value, index) => { if (value !== null) { const isRed = value < 4; - const defaultPiece = isRed ? dom.defaultRedPiece : dom.defaultBluePiece; - const newPiece = defaultPiece.cloneNode(true) as HTMLParagraphElement; + const defaultPiece = isRed + ? dom.defaultRedPiece + : dom.defaultBluePiece; + const newPiece = defaultPiece.cloneNode( + true + ) as HTMLParagraphElement; newPiece.id = value.toString(); dom.cells()[index].appendChild(newPiece); } @@ -294,7 +358,7 @@ const init = () => { // hook up buttons let blockActions = false; - dom.resetButton.addEventListener('click', () => { + dom.resetButton.addEventListener("click", () => { if (blockActions) { return; } @@ -303,12 +367,12 @@ const init = () => { } blockActions = true; - if (confirm('Reset?')) { + if (confirm("Reset?")) { window.location.reload(); } blockActions = false; }); - dom.undoButton.addEventListener('click', async () => { + dom.undoButton.addEventListener("click", async () => { if (blockActions) { return; } @@ -329,5 +393,52 @@ const init = () => { }; // start! -init(); -nextMove(); \ No newline at end of file +const playGame = () => { + init(); + nextMove(); +}; + +// const isOnlineGame = (window as any).daoIsOnline; +// if (isOnlineGame) { +// const receiver = (data) => +// const peer = new PeerComm() +// } else { +// playGame(); + +// } + +playGame(); + +function delay(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +const doStuff = async () => { + const peer = new PeerComm((data) => { + console.log(`TO: ${peer.id})`); + console.log(`FROM: ?)`); + console.log(`DATA: ${data}`); + }); + prompt('Self id:', peer.id); + const otherId = prompt('Peer id to connect to:', ''); + if (!otherId) { + while (!peer.isConnected) { + await delay(500); + } + } else { + peer.connect(otherId); + } + + alert('Connected!'); + alert('Starting messaging server'); + alert('Respond with empty text to stop'); + + while (true) { + const message = prompt('Message to send:', ''); + if (!message) { + break; + } + peer.send(message); + delay(1000); + } +} +// doStuff(); diff --git a/src/peering.ts b/src/peering.ts new file mode 100644 index 0000000..ed11a3f --- /dev/null +++ b/src/peering.ts @@ -0,0 +1,51 @@ +import Peer from "peerjs"; + +const daoPeerIdKey = "dao-game-peer-id"; +export class PeerComm<T> { + public constructor(receiver: (data: T) => void) { + this.receiver = receiver; + + // const peerId = localStorage.getItem(daoPeerIdKey) ?? `dao-game-peer-id-${Date.now()}`; + const peerId = `dao-game-peer-id-${Date.now()}`; + const peer = new Peer(peerId); + // localStorage.setItem(daoPeerIdKey, peerId); + this.id = peerId; + this.peer = peer; + + peer.on('connection', (connection) => { + connection.on('data', data => { + receiver(JSON.parse(data)); + }); + connection.on('open', () => { + connection.send('hello'); + this.conn = connection; + }) + }); + } + + public get isConnected() { + return this.conn !== null; + } + public connect(otherPeerId: string): void { + if (this.conn !== null) { + throw "Already connected"; + } + const conn = this.peer.connect(otherPeerId); + conn.on('open', () => { + conn.send('hi'); + this.conn = conn; + }); + } + + public readonly id: string; + public receiver: (data: T) => void; + public send(data: T): void { + if (!this.isConnected) { + throw "Not connected"; + } + this.conn.send(JSON.stringify(data)); + } + + private peer: Peer; + private conn: Peer.DataConnection | null = null; +} diff --git a/src/piano.ts b/src/piano.ts new file mode 100644 index 0000000..d9072ec --- /dev/null +++ b/src/piano.ts @@ -0,0 +1,36 @@ +import { PeerComm } from "./peering"; +import { Move } from "./types"; + +export interface Game { + moveHistory: Move[]; + isRedTurn: boolean; + isLocalRed: boolean; + isMoveLegal: (sourceIndex: number, destIndex: number) => boolean; + requestMove: () => ((sourceIndex: number, destIndex: number) => void); +} +enum State { + Starting, + RedTurn, + BlueTurn +} +interface PeerData { + senderId: string; + receiverId: string; + redId: string; + state: State; + move: Move | null; +} + +export class Piano { + public game: Game; + private peerComm: PeerComm<PeerData>; + private receiver: (data: PeerData) => void; + public constructor(game: Game) { + this.game = game; + this.receiver = (data: PeerData) => { + const isGameStarting = game.moveHistory.length === 0; + const isLocalRed = data.redId === this.peerComm.id; + }; + this.peerComm = new PeerComm<PeerData>(this.receiver) + } +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 9ba103b..18cf62d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -38,11 +38,13 @@ export class Coord { } export class Move { - public sourceIndex: number; - public destIndex: number; - constructor(sourceIndex: number, destIndex: number) { + public readonly sourceIndex: number; + public readonly destIndex: number; + public readonly isPieceRed: boolean; + constructor(isPieceRed: boolean, sourceIndex: number, destIndex: number) { this.sourceIndex = sourceIndex; this.destIndex = destIndex; + this.isPieceRed = isPieceRed; } }