85 Commits

Author SHA1 Message Date
Anduin Xue e1ff2b84bc Update dependencies and optimize chess move computation
Upgraded various package dependencies in both test and main projects to their latest stable versions. Simplified the chess move computation logic by replacing custom depth handling with a streamlined `go depth` command for improved clarity and maintainability.
2025-01-01 15:19:47 +00:00
Anduin Xue ed70c58800 Bump runtime version from 8.0 to 9.0. 2025-01-01 14:01:42 +00:00
Anduin Xue 93211af255 Bump .NET SDK version from 8.0 to 9.0. 2025-01-01 13:56:47 +00:00
Anduin Xue 767073c4dc Bump .NET version from 8 to 9. 2025-01-01 13:55:25 +00:00
Anduin Xue 496b34cdcc Happy new year 2025. 2025-01-01 13:45:07 +00:00
Anduin Xue fd8665e6ad Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!100
2024-12-12 06:00:44 +00:00
Nuget Ninja fd8e983830 Auto csproj fix and update by bot. 2024-12-12 05:01:08 +00:00
Anduin Xue abd23b9035 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!99
2024-12-09 06:01:12 +00:00
Nuget Ninja 7b740027fb Auto csproj fix and update by bot. 2024-12-09 05:01:13 +00:00
Anduin Xue cd7c80d3e1 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!98
2024-12-07 06:00:16 +00:00
Nuget Ninja a9faa5227f Auto csproj fix and update by bot. 2024-12-07 05:01:27 +00:00
Anduin Xue 985a58c58a Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!97
2024-12-06 06:01:02 +00:00
Nuget Ninja 6e26f87ba7 Auto csproj fix and update by bot. 2024-12-06 05:00:58 +00:00
Anduin Xue 253d19ae81 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!96
2024-12-05 06:00:16 +00:00
Nuget Ninja 71ed23acec Auto csproj fix and update by bot. 2024-12-05 05:00:55 +00:00
Anduin Xue d037012c01 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!95
2024-12-04 07:00:02 +00:00
Nuget Ninja d19f5e67a3 Auto csproj fix and update by bot. 2024-12-04 05:01:17 +00:00
Anduin Xue fbfe1efcb2 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!94
2024-12-01 06:00:21 +00:00
Nuget Ninja 1f3a96d8c8 Auto csproj fix and update by bot. 2024-12-01 05:00:58 +00:00
Anduin Xue fa1267aaf1 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!93
2024-11-20 07:01:03 +00:00
Nuget Ninja d4f4743d64 Auto csproj fix and update by bot. 2024-11-20 05:01:23 +00:00
Anduin Xue 58f8e2b519 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!92
2024-11-13 10:11:38 +00:00
Nuget Ninja 5da1f879f2 Auto csproj fix and update by bot. 2024-11-13 10:06:39 +00:00
Anduin Xue ea5f2d4134 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!91
2024-11-13 08:42:23 +00:00
Nuget Ninja 4665be0640 Auto csproj fix and update by bot. 2024-11-13 08:32:41 +00:00
Anduin Xue 34b58a94a5 Update package versions and clean code imports
Updated various package references to their latest versions in the project and test files. Additionally, removed unnecessary `Aiursoft.AiurObserver.Extensions` imports from several controller files to clean up the code.
2024-11-13 05:10:49 +00:00
Anduin Xue c5cff05e9c Handle ConnectionAbortedException in controllers
Add specific handling for ConnectionAbortedException in ChatController, GamesController, and ChallengesController to explicitly manage cases where the client closes the connection, ensuring graceful exception handling and improved code clarity.
2024-11-12 16:08:10 +00:00
Anduin Xue 9689db40a5 Merge remote-tracking branch 'origin/master' 2024-11-12 16:06:24 +00:00
Anduin Xue fe3b04415c Add pusher.Connected check before closing pusher.
This ensures that the pusher is only closed when it is connected, preventing unnecessary operations and potential errors. The change has been applied across ChatController, GamesController, and ChallengesController.
2024-11-12 16:06:21 +00:00
Anduin Xue fad74fd7fb Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!89
2024-11-12 06:01:13 +00:00
Nuget Ninja 01dd076655 Auto csproj fix and update by bot. 2024-11-12 05:01:32 +00:00
Anduin Xue 5063390b6d Add in-memory caching for Player and Challenge models
Replaced manual in-memory data management with LruMemoryStore for Player and Challenge models. Updated relevant methods for challenge handling to utilize the new caching mechanism for better performance and maintainability. Added Aiursoft.InMemoryKvDb package to the project.
2024-11-11 13:20:52 +00:00
Anduin Xue 69138a0080 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!88
2024-11-07 06:02:18 +00:00
Nuget Ninja 6a0bb29422 Auto csproj fix and update by bot. 2024-11-07 05:00:57 +00:00
Anduin Xue f39e6542d0 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!87
2024-11-06 08:26:30 +00:00
Nuget Ninja 46d3ad4802 Auto csproj fix and update by bot. 2024-11-06 05:01:07 +00:00
Anduin Xue 74a70fda59 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!86
2024-11-02 07:27:51 +00:00
Nuget Ninja 27f4c38239 Auto csproj fix and update by bot. 2024-11-02 05:01:00 +00:00
Anduin Xue 8dd1bd331c Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!85
2024-10-29 06:00:45 +00:00
Nuget Ninja 5e21ada905 Auto csproj fix and update by bot. 2024-10-29 05:00:45 +00:00
Anduin Xue 786fdfe0b1 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!84
2024-10-26 06:01:32 +00:00
Nuget Ninja 3ede22cac6 Auto csproj fix and update by bot. 2024-10-26 05:00:53 +00:00
Anduin Xue baf659be35 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!83
2024-10-22 06:00:49 +00:00
Nuget Ninja 87b1d9b7b6 Auto csproj fix and update by bot. 2024-10-22 05:01:02 +00:00
Anduin Xue fa92a7aa2f Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!82
2024-10-13 06:02:32 +00:00
Nuget Ninja 588c4d69df Auto csproj fix and update by bot. 2024-10-13 05:00:52 +00:00
Anduin Xue 95d8cb09e0 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!81
2024-10-10 06:02:34 +00:00
Nuget Ninja c8e3d7ca6e Auto csproj fix and update by bot. 2024-10-10 05:01:00 +00:00
Anduin Xue 0f9f933171 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!80
2024-10-07 06:01:30 +00:00
Nuget Ninja cc119912a9 Auto csproj fix and update by bot. 2024-10-07 05:00:47 +00:00
Anduin Xue 880c122db4 Add package-lock.json and simplify ChessEngine move selection
Added package-lock.json to track exact versions of dependencies. Simplified the logic in ChessEngine to always use the best move, removing randomness based on difficulty.
2024-10-07 01:59:52 +00:00
Anduin Xue b7f3082f68 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!79
2024-10-05 06:02:21 +00:00
Nuget Ninja b61e1a836b Auto csproj fix and update by bot. 2024-10-05 05:00:59 +00:00
Anduin Xue df2be89ae6 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!78
2024-09-14 06:00:51 +00:00
Nuget Ninja 0438f85b7f Auto csproj fix and update by bot. 2024-09-14 05:00:59 +00:00
Anduin Xue 2832388996 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!77
2024-09-13 06:01:54 +00:00
Nuget Ninja 709702ca5e Auto csproj fix and update by bot. 2024-09-13 05:00:56 +00:00
Anduin Xue 5775a5345c Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!76
2024-09-08 06:00:36 +00:00
Nuget Ninja 02c9c08717 Auto csproj fix and update by bot. 2024-09-08 05:01:04 +00:00
Anduin Xue 4633b16069 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!75
2024-08-22 06:01:06 +00:00
Nuget Ninja a8ce3f606c Auto csproj fix and update by bot. 2024-08-22 05:01:06 +00:00
Anduin Xue b8182baf12 Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!74
2024-08-20 06:00:23 +00:00
Nuget Ninja f3090cd855 Auto csproj fix and update by bot. 2024-08-20 05:00:46 +00:00
Anduin Xue ad977ed74f Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!73
2024-08-07 06:00:44 +00:00
Nuget Ninja 4405b0da39 Auto csproj fix and update by bot. 2024-08-07 05:01:13 +00:00
Anduin Xue 916792bbb7 Show verbose log for npm install for easier debugging. 2024-08-01 12:32:28 +00:00
Anduin Xue 09c703af7e Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!72
2024-07-31 06:01:06 +00:00
Nuget Ninja dc2680d124 Auto csproj fix and update by bot. 2024-07-31 05:01:00 +00:00
Anduin Xue 603ee417db Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!71
2024-07-18 06:00:39 +00:00
Nuget Ninja 88d35442f4 Auto csproj fix and update by bot. 2024-07-18 05:01:22 +00:00
Anduin Xue d8d0a44a79 Merge branch 'master' of ssh://gitlab.aiursoft.cn:2202/aiursoft/chessserver 2024-07-16 06:08:16 +00:00
Anduin Xue 378da184e0 Use Aiursoft's own npm registry. 2024-07-16 06:08:15 +00:00
Anduin Xue 61a2275a7d Merge branch 'users/nugetninja/evergreen' into 'master'
Auto dependencies upgrade by bot.

See merge request aiursoft/chessserver!70
2024-07-08 06:01:19 +00:00
Nuget Ninja 48128e9e08 Auto csproj fix and update by bot. 2024-07-08 05:01:03 +00:00
Anduin Xue 3ab22373ff Fix a typo with Dockerfile AS. 2024-07-07 14:31:34 +00:00
Anduin Xue 7d32de3d12 Replace as to AS to unify dockerfile grammar. 2024-07-07 14:25:17 +00:00
Anduin Xue 4d6033f73f Update difficulty handling in ChessEngine
The difficulty handling logic has been modified to better determine when to use the best move in the ChessEngine class. A new method called ShouldUseBestMove(int difficulty) has been added to provide a probabilistic approach towards choosing the best move based on the provided difficulty level.
2024-07-06 09:18:18 +00:00
xuef e780e7af7e Use new alpha. 2024-07-06 05:05:20 +00:00
dvorak chen 489c532128 Merge branch 'master' into 'master'
refactor: play sound when moved

See merge request aiursoft/chessserver!69
2024-07-06 04:43:22 +00:00
dvorakchen 554e5918e8 refactor: play sound when moved 2024-07-06 12:36:48 +08:00
dvorak chen 2bb7a1e4be Merge branch 'master' into 'master'
feat: play sound while piece moved

See merge request aiursoft/chessserver!68
2024-07-05 14:26:14 +00:00
dvorakchen 3dee08b268 feat: play sound while piece moved 2024-07-05 22:24:15 +08:00
dvorak chen bbdb775ee0 Merge branch 'master' into 'master'
feat: red highlight in check

See merge request aiursoft/chessserver!66
2024-07-04 11:34:47 +00:00
dvorakchen ef2d7b6c10 Merge branch 'master' of https://gitlab.aiursoft.cn/dvorak/chessserver
Merge master
2024-07-04 19:30:56 +08:00
dvorakchen 9d6da46f4e feat: red highlight in check 2024-07-04 19:30:26 +08:00
24 changed files with 561 additions and 160 deletions
-3
View File
@@ -1,8 +1,6 @@
.vs/
.idea/
lib
*.lock.json
package-lock.json
*.user
*.min.css
*.min.js
@@ -12,7 +10,6 @@ dist/
node_modules/
Properties/
npm-debug.log
yarn.lock
bundle.js
appsettings.Production.json
appsettings.Development.json
+5 -1
View File
@@ -13,6 +13,9 @@ before_script:
- 'echo "Hostname: $(hostname)"'
- 'dotnet --info'
variables:
GIT_CLONE_PATH: '$CI_BUILDS_DIR/$CI_PROJECT_NAME/$CI_PIPELINE_ID'
restore:
stage: build
script:
@@ -30,7 +33,8 @@ lint:
needs:
- build
script:
- jb inspectcode ./*.sln --output=analyze_output.xml --build -f=xml
# 3 times retry because sometimes the first time will fail
- jb inspectcode ./*.sln --output=analyze_output.xml --build -f=xml || jb inspectcode ./*.sln --output=analyze_output.xml --build -f=xml || jb inspectcode ./*.sln --output=analyze_output.xml --build -f=xml
# Remove the warning of UnusedAutoPropertyAccessor InconsistentNaming
- sed -i '/InconsistentNaming/d' analyze_output.xml
- sed -i '/AssignNullToNotNullAttribute/d' analyze_output.xml # This is because jetbrains is not smart enough to understand the nullability of C# 8.0
+60
View File
@@ -0,0 +1,60 @@
# Aiursoft Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
We are committed to creating a positive and inclusive environment where all participants feel respected and valued.
## Our Principles
To ensure that the software we develop aligns with the Aiursoft Principles and serves all users equally well, we uphold the following:
1. **Offline Functionality**
Any compiled artifacts of the software must be capable of performing their full functions without requiring an internet connection.
2. **Local Compilation in Aiursoft**
The source code of the software must be capable of being compiled locally within Aiursoft's infrastructure without requiring an internet connection.
3. **Third-Party Local Compilation**
The source code of the software must be capable of being compiled locally by third-party developers with an internet connection.
These principles ensure the softwares reliability, accessibility, and functionality across varied environments and user conditions.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies within all project spaces, and it also applies in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [anduin@aiursoft.com]. All complaints will be reviewed and investigated promptly and fairly. Maintainers are obligated to respect the privacy and security of the reporter of any incident.
## Acknowledgement
This Code of Conduct is adapted from the Contributor Covenant, version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
By participating in this project, you agree to uphold this Code of Conduct and to adhere to the principles and standards we strive to maintain for a respectful, inclusive, and productive community.
+4 -4
View File
@@ -3,17 +3,17 @@ ARG PROJ_NAME="Aiursoft.ChessServer"
# ============================
# Prepare NPM Environment
FROM hub.aiursoft.cn/node:21-alpine as npm-env
FROM hub.aiursoft.cn/node:21-alpine AS npm-env
ARG CSPROJ_PATH
WORKDIR /src
COPY . .
# NPM Build at PGK_JSON_PATH
RUN npm install --prefix "${CSPROJ_PATH}wwwroot"
RUN npm install --prefix "${CSPROJ_PATH}wwwroot" --loglevel verbose
# ============================
# Prepare Building Environment
FROM hub.aiursoft.cn/mcr.microsoft.com/dotnet/sdk:8.0 as build-env
FROM hub.aiursoft.cn/mcr.microsoft.com/dotnet/sdk:9.0 AS build-env
ARG CSPROJ_PATH
ARG PROJ_NAME
WORKDIR /src
@@ -25,7 +25,7 @@ RUN cp -r ${CSPROJ_PATH}/wwwroot/* /app/wwwroot
# ============================
# Prepare Runtime Environment
FROM hub.aiursoft.cn/mcr.microsoft.com/dotnet/aspnet:8.0
FROM hub.aiursoft.cn/mcr.microsoft.com/dotnet/aspnet:9.0
ARG PROJ_NAME
WORKDIR /app
COPY --from=build-env /app .
+41 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2024 Aiursoft
Copyright (c) 2025 Aiursoft
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -19,3 +19,43 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# Developer Certificate of Origin
In addition to the permissions and conditions stated above, the maintenance and development of the Software shall adhere to the following Aiursoft Principles:
1. Any compiled artifacts of the Software must be capable of performing their full functions without requiring an internet connection.
2. The source code of the Software must be capable of being compiled locally within Aiursoft's infrastructure without requiring an internet connection.
3. The source code of the Software must be capable of being compiled locally by third-party developers with an internet connection.
# Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
# Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
# Our Responsibilities
Maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
# Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+1 -1
View File
@@ -37,7 +37,7 @@ It will install the app as a systemd service, and start it automatically. Binary
Requirements about how to run
1. Install [.NET 8 SDK](http://dot.net/) and [Node.js](https://nodejs.org/).
1. Install [.NET 9 SDK](http://dot.net/) and [Node.js](https://nodejs.org/).
2. Execute `npm install` at `wwwroot` folder to install the dependencies.
3. Execute `dotnet run` to run the app.
4. Use your browser to view [http://localhost:5000](http://localhost:5000).
+1 -1
View File
@@ -31,7 +31,7 @@ install()
wwwrootPath=$(dirname "/tmp/repo/$proj_path")/wwwroot
if [ -d "$wwwrootPath" ]; then
echo "Found wwwroot folder $wwwrootPath, will install node modules."
sudo npm install --prefix "$wwwrootPath" -force
sudo npm install --prefix "$wwwrootPath" -force --loglevel verbose
fi
# Publish the app
+2
View File
@@ -8,6 +8,8 @@ files:
contentUri: https://gitlab.aiursoft.cn/aiursoft/tracer/-/raw/master/.gitlab-ci.yml
- name: LICENSE
contentUri: https://gitlab.aiursoft.cn/aiursoft/tracer/-/raw/master/LICENSE
- name: CODE_OF_CONDUCT.md
contentUri: https://gitlab.aiursoft.cn/aiursoft/tracer/-/raw/master/CODE_OF_CONDUCT.md
- name: ninja.yaml
contentUri: https://gitlab.aiursoft.cn/aiursoft/tracer/-/raw/master/ninja.yaml
- name: nuget.config
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<AssemblyName>Aiursoft.ChessServer</AssemblyName>
<RootNamespace>Aiursoft.ChessServer</RootNamespace>
<IsTestProject>false</IsTestProject>
@@ -10,11 +10,12 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aiursoft.AiurObserver.Extensions" Version="8.0.2" />
<PackageReference Include="Aiursoft.AiurObserver.WebSocket.Server" Version="8.0.2" />
<PackageReference Include="Aiursoft.Scanner" Version="8.0.1" />
<PackageReference Include="Aiursoft.WebTools" Version="8.0.21" />
<PackageReference Include="Gera.Chess" Version="1.1.0" />
<PackageReference Include="LynxChess.Lynx.Internal" Version="1.5.1" />
<PackageReference Include="Aiursoft.AiurObserver.Extensions" Version="9.0.0" />
<PackageReference Include="Aiursoft.AiurObserver.WebSocket.Server" Version="9.0.0" />
<PackageReference Include="Aiursoft.InMemoryKvDb" Version="1.0.7" />
<PackageReference Include="Aiursoft.Scanner" Version="9.0.1" />
<PackageReference Include="Aiursoft.WebTools" Version="9.0.0" />
<PackageReference Include="Gera.Chess" Version="1.1.1" />
<PackageReference Include="LynxChess.Lynx" Version="1.8.0" />
</ItemGroup>
</Project>
@@ -1,5 +1,5 @@
using System.ComponentModel.DataAnnotations;
using Aiursoft.AiurObserver.Extensions;
using Aiursoft.AiurObserver;
using Aiursoft.AiurObserver.WebSocket.Server;
using Aiursoft.ChessServer.Attributes;
using Aiursoft.ChessServer.Data;
@@ -7,6 +7,7 @@ using Aiursoft.ChessServer.Models;
using Aiursoft.ChessServer.Models.ViewModels;
using Aiursoft.CSTools.Services;
using Aiursoft.WebTools.Attributes;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Mvc;
namespace Aiursoft.ChessServer.Controllers;
@@ -157,10 +158,17 @@ public class ChallengesController (
{
// Ignore. This happens when the client closes the connection.
}
catch (ConnectionAbortedException)
{
// Ignore. This happens when the client closes the connection.
}
finally
{
await pusher.Close(HttpContext.RequestAborted);
outSub.Unsubscribe();
if (pusher.Connected)
{
await pusher.Close(HttpContext.RequestAborted);
}
}
}
}
@@ -1,11 +1,11 @@
using System.Text.Json;
using Aiursoft.AiurObserver;
using Aiursoft.AiurObserver.Extensions;
using Aiursoft.AiurObserver.WebSocket.Server;
using Aiursoft.ChessServer.Attributes;
using Aiursoft.ChessServer.Data;
using Aiursoft.ChessServer.Models;
using Aiursoft.WebTools.Attributes;
using Microsoft.AspNetCore.Connections;
using Microsoft.AspNetCore.Mvc;
namespace Aiursoft.ChessServer.Controllers;
@@ -50,11 +50,18 @@ public class ChatController(InMemoryDatabase database) : ControllerBase
{
// Ignore. This happens when the client closes the connection.
}
catch (ConnectionAbortedException)
{
// Ignore. This happens when the client closes the connection.
}
finally
{
await pusher.Close(HttpContext.RequestAborted);
outSub.Unsubscribe();
inSub.Unsubscribe();
if (pusher.Connected)
{
await pusher.Close(HttpContext.RequestAborted);
}
}
}
}
@@ -3,9 +3,9 @@ using Aiursoft.AiurObserver.WebSocket.Server;
using Aiursoft.ChessServer.Data;
using Aiursoft.ChessServer.Models.ViewModels;
using Microsoft.AspNetCore.Mvc;
using Aiursoft.AiurObserver.Extensions;
using Aiursoft.ChessServer.Attributes;
using Aiursoft.WebTools.Attributes;
using Microsoft.AspNetCore.Connections;
namespace Aiursoft.ChessServer.Controllers;
@@ -88,11 +88,18 @@ public class GamesController(InMemoryDatabase database) : Controller
{
// Ignore. This happens when the client closes the connection.
}
catch (ConnectionAbortedException)
{
// Ignore. This happens when the client closes the connection.
}
finally
{
await pusher.Close(HttpContext.RequestAborted);
outSub.Unsubscribe();
inSub.Unsubscribe();
if (pusher.Connected)
{
await pusher.Close(HttpContext.RequestAborted);
}
}
}
@@ -4,7 +4,6 @@ using Aiursoft.ChessServer.Data;
using Aiursoft.ChessServer.Models;
using Aiursoft.CSTools.Services;
using Microsoft.AspNetCore.Mvc;
using Aiursoft.AiurObserver.Extensions;
using Aiursoft.ChessServer.Services;
using Chess;
@@ -52,6 +51,10 @@ public class PveController(
var webSocketSchema = HttpContext.Request.Scheme == "https" ? "wss" : "ws";
var webSocketEndpoint =
$"{webSocketSchema}://{HttpContext.Request.Host}/games/{challengeId}.ws?playerId={computerId}";
// TODO: Refactor required. Currently, PVE, the computer is also a WebSocket client connecting to localhost.
// This is not a good practice. The computer should be a WebSocket server that listens to the game's WebSocket.
// Because currently, if the user dropped, the computer will not know and will keep calculating the best move.
var client = await webSocketEndpoint.ConnectAsWebSocketServer();
subscription = client.Subscribe(async fen =>
{
@@ -1,55 +1,41 @@
using Aiursoft.Scanner.Abstractions;
using System.Collections.Concurrent;
using Aiursoft.ChessServer.Models;
using Aiursoft.InMemoryKvDb.AutoCreate;
using Aiursoft.InMemoryKvDb.ManualCreate;
namespace Aiursoft.ChessServer.Data;
public class InMemoryDatabase : ISingletonDependency
// ReSharper disable once ClassNeverInstantiated.Global
public class InMemoryDatabase(
LruMemoryStore<Player, Guid> playersDb,
LruMemoryStoreManualCreated<Challenge, int> challenges) : ISingletonDependency
{
private ConcurrentDictionary<Guid, Player> Players { get; } = new();
private ConcurrentDictionary<int, Challenge> Challenges { get; } = new();
private IEnumerable<KeyValuePair<int, Challenge>> OpenChallenges =>
Challenges.Where(t => t.Value is not AcceptedChallenge);
challenges.GetAllWithKeys().Where(t => t.Value is not AcceptedChallenge);
private IEnumerable<KeyValuePair<int, Challenge>> OnGoingChallenges =>
Challenges.Where(t => t.Value is AcceptedChallenge);
challenges.GetAllWithKeys().Where(t => t.Value is AcceptedChallenge);
public Player GetOrAddPlayer(Guid id)
{
lock (Players)
{
return Players.GetOrAdd(id, _ => new Player(id)
{
NickName = "Anonymous " + new Random().Next(1000, 9999)
});
}
return playersDb.GetOrAdd(id);
}
public IReadOnlyCollection<KeyValuePair<int, Challenge>> GetPublicOpenChallenges()
{
lock (Challenges)
{
return OpenChallenges
.Where(t => t.Value.Permission == ChallengePermission.Public)
.ToArray();
}
}
public IReadOnlyCollection<KeyValuePair<int, Challenge>> GetOnGoingOpenChallenges()
{
lock (Challenges)
{
return OnGoingChallenges
.Where(t => t.Value.Permission == ChallengePermission.Public)
.ToArray();
}
}
public int? GetMyOpenChallenge(Guid playerId)
{
lock (Challenges)
{
if (OpenChallenges.All(t => t.Value.Creator.Id != playerId))
{
@@ -60,14 +46,10 @@ public class InMemoryDatabase : ISingletonDependency
.FirstOrDefault(t => t.Value.Creator.Id == playerId)
.Key;
}
}
public Challenge? GetChallenge(int id)
{
lock (Challenges)
{
return Challenges.GetValueOrDefault(id);
}
return challenges.Get(id);
}
public AcceptedChallenge? GetAcceptedChallenge(int id)
@@ -78,9 +60,7 @@ public class InMemoryDatabase : ISingletonDependency
public async Task PatchChallengeAsAcceptedAsync(int id, Guid accepter)
{
lock (Challenges)
{
var challenge = Challenges.GetValueOrDefault(id);
var challenge = challenges.Get(id);
if (challenge == null)
{
throw new InvalidOperationException("Challenge not found!");
@@ -103,14 +83,11 @@ public class InMemoryDatabase : ISingletonDependency
permission: challenge.Permission,
challengeChangedChannel: challenge.ChallengeChangedChannel);
Challenges[id] = newChallenge;
}
await Challenges.GetValueOrDefault(id)!.ChallengeChangedChannel.BroadcastAsync("game-started");
challenges.AddToCache(id, newChallenge);
await challenges.Get(id)!.ChallengeChangedChannel.BroadcastAsync("game-started");
}
public int? GetFirstPublicChallengeKey()
{
lock (Challenges)
{
if (OpenChallenges.All(t => t.Value.Permission != ChallengePermission.Public))
{
@@ -121,25 +98,14 @@ public class InMemoryDatabase : ISingletonDependency
.FirstOrDefault(t => t.Value.Permission == ChallengePermission.Public)
.Key;
}
}
public void DeleteChallenge(int id)
{
lock (Challenges)
{
Challenges.TryRemove(id, out _);
}
challenges.Remove(id);
}
public void CreateChallenge(int id, Challenge challenge)
{
lock (Challenges)
{
var result = Challenges.TryAdd(id, challenge);
if (!result)
{
throw new InvalidOperationException("Challenge already exists!");
}
}
challenges.AddToCache(id, challenge);
}
}
@@ -10,7 +10,7 @@ public class ChessEngine
public ChessEngine()
{
var channel = Channel.CreateUnbounded<string>(new UnboundedChannelOptions
var channel = Channel.CreateUnbounded<object>(new UnboundedChannelOptions
{
SingleReader = true,
SingleWriter = true
@@ -39,19 +39,8 @@ public class ChessEngine
_engine.AdjustPosition($"position fen {fen}");
var positionClone = new Position(_engine.Game.CurrentPosition);
var depth = difficulty - 1;
var result = _engine.IDDFS(depth, 10);
_engine.Game.ResetCurrentPositionToBeforeSearchState();
if (difficulty > 4)
{
// If difficulty is higher than 5, we should use the best move
return result.BestMove.ToEPDString(positionClone);
}
else
{
// Randomly choose one of the moves
return result.Moves[new Random().Next(result.Moves.Count)].ToEPDString(positionClone);
}
return _engine.BestMove(new($"go depth {difficulty}"))
.BestMove
.ToEPDString(positionClone);
}
}
+9
View File
@@ -1,6 +1,8 @@
using System.Reflection;
using Aiursoft.ChessServer.Middlewares;
using Aiursoft.ChessServer.Models;
using Aiursoft.ChessServer.Services;
using Aiursoft.InMemoryKvDb;
using Aiursoft.Scanner;
using Aiursoft.WebTools.Abstractions.Models;
@@ -12,6 +14,13 @@ public class Startup : IWebStartup
{
services.AddLibraryDependencies();
services.AddLruMemoryStore<Player, Guid>(
id => new Player(id) { NickName = "Anonymous " + new Random().Next(1000, 9999) },
maxCachedItemsCount: 1024);
services.AddLruMemoryStoreManualCreate<Challenge, int>(
maxCachedItemsCount: 256);
services.AddTransient<ChessEngine>();
services
@@ -3,6 +3,7 @@
<div id="board" style="width: 100%" class="w-100"></div>
<p id="status" class="text-center text-wrap text-primary mt-3"></p>
<p id="role" class="text-center text-wrap text-secondary mt-1"></p>
<audio src="/sounds/chess_piece_move.mp3" id="pieceMoveSound" loop></audio>
<script type="module">
import ChessBuilder from "/scripts/chessboard/chessboard.js";
@@ -13,7 +14,8 @@
var playerColor = await getPlayerColor(@Model.GameId);
var statusControl = document.getElementById("status");
var roleControl = document.getElementById("role");
let anduinChessBoard = new ChessBuilder(playerColor, statusControl, roleControl).default();
const soundControl = document.getElementById('pieceMoveSound');
let anduinChessBoard = new ChessBuilder(playerColor, statusControl, roleControl, soundControl).default();
anduinChessBoard.run(playerId, @Model.GameId);
document.body.addEventListener('pointerdown', (e) => {
+1
View File
@@ -0,0 +1 @@
registry=https://npm.aiursoft.cn
+150
View File
@@ -0,0 +1,150 @@
{
"name": "wwwroot",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "wwwroot",
"version": "1.0.0",
"license": "MIT",
"dependencies": {
"@aiursoft/autodark.js": "^1.2.0",
"@chrisoakman/chessboardjs": "^1.0.0",
"@fortawesome/fontawesome-free": "^6.5.1",
"chess.js": "^1.0.0-beta.6",
"clipboard": "^2.0.11",
"jquery-validation": "^1.19.5",
"jquery-validation-unobtrusive": "^3.2.12"
}
},
"node_modules/@aiursoft/autodark.js": {
"version": "1.2.0",
"resolved": "https://npm.aiursoft.cn/@aiursoft/autodark.js/-/autodark.js-1.2.0.tgz",
"integrity": "sha512-3EZh7AaT2ns2DGq24HMcNxAjSVSST49t/tZhR2MV0pxrwYgb+1SCk6zj9qv4TJB1bAixM0K/5nsH0YazZzfvng==",
"license": "MIT",
"dependencies": {
"bootstrap": "^4.6.2"
}
},
"node_modules/@chrisoakman/chessboardjs": {
"version": "1.0.0",
"resolved": "https://npm.aiursoft.cn/@chrisoakman/chessboardjs/-/chessboardjs-1.0.0.tgz",
"integrity": "sha512-JHXHoQwwc86xW3F0YIdFcEWLnPldee5mHkqwJbOTeDh5gvNmYXyBj6AkeecDkj2WtORF959yaWYlpyZHUl3LCQ==",
"license": "MIT",
"dependencies": {
"jquery": ">=3.4.1"
}
},
"node_modules/@fortawesome/fontawesome-free": {
"version": "6.6.0",
"resolved": "https://npm.aiursoft.cn/@fortawesome/fontawesome-free/-/fontawesome-free-6.6.0.tgz",
"integrity": "sha512-60G28ke/sXdtS9KZCpZSHHkCbdsOGEhIUGlwq6yhY74UpTiToIh8np7A8yphhM4BWsvNFtIvLpi4co+h9Mr9Ow==",
"license": "(CC-BY-4.0 AND OFL-1.1 AND MIT)",
"engines": {
"node": ">=6"
}
},
"node_modules/bootstrap": {
"version": "4.6.2",
"resolved": "https://npm.aiursoft.cn/bootstrap/-/bootstrap-4.6.2.tgz",
"integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"jquery": "1.9.1 - 3",
"popper.js": "^1.16.1"
}
},
"node_modules/chess.js": {
"version": "1.0.0-beta.8",
"resolved": "https://npm.aiursoft.cn/chess.js/-/chess.js-1.0.0-beta.8.tgz",
"integrity": "sha512-UngzUMXmexcQaQA/UEJuJj5vatEy34awYMD5YMOp/FW3HM7lqspp7ymYs5JAmquDq0WROtURRfSffoa/vrCCyw==",
"license": "BSD-2-Clause"
},
"node_modules/clipboard": {
"version": "2.0.11",
"resolved": "https://npm.aiursoft.cn/clipboard/-/clipboard-2.0.11.tgz",
"integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
"license": "MIT",
"dependencies": {
"good-listener": "^1.2.2",
"select": "^1.1.2",
"tiny-emitter": "^2.0.0"
}
},
"node_modules/delegate": {
"version": "3.2.0",
"resolved": "https://npm.aiursoft.cn/delegate/-/delegate-3.2.0.tgz",
"integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
"license": "MIT"
},
"node_modules/good-listener": {
"version": "1.2.2",
"resolved": "https://npm.aiursoft.cn/good-listener/-/good-listener-1.2.2.tgz",
"integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
"license": "MIT",
"dependencies": {
"delegate": "^3.1.2"
}
},
"node_modules/jquery": {
"version": "3.7.1",
"resolved": "https://npm.aiursoft.cn/jquery/-/jquery-3.7.1.tgz",
"integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==",
"license": "MIT"
},
"node_modules/jquery-validation": {
"version": "1.21.0",
"resolved": "https://npm.aiursoft.cn/jquery-validation/-/jquery-validation-1.21.0.tgz",
"integrity": "sha512-xNot0rlUIgu7duMcQ5qb6MGkGL/Z1PQaRJQoZAURW9+a/2PGOUxY36o/WyNeP2T9R6jvWB8Z9lUVvvQWI/Zs5w==",
"license": "MIT",
"peerDependencies": {
"jquery": "^1.7 || ^2.0 || ^3.1"
}
},
"node_modules/jquery-validation-unobtrusive": {
"version": "3.2.12",
"resolved": "https://npm.aiursoft.cn/jquery-validation-unobtrusive/-/jquery-validation-unobtrusive-3.2.12.tgz",
"integrity": "sha512-kPixGhVcuat7vZXngGFfSIksy4VlzZcHyRgnBIZdsfVneCU+D5sITC8T8dD/9c9K/Q+qkMlgp7ufJHz93nKSuQ==",
"license": "https://aka.ms/jqueryunobtrusivelicense",
"dependencies": {
"jquery": "^3.5.1",
"jquery-validation": ">=1.16"
}
},
"node_modules/popper.js": {
"version": "1.16.1",
"resolved": "https://npm.aiursoft.cn/popper.js/-/popper.js-1.16.1.tgz",
"integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
"deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/select": {
"version": "1.1.2",
"resolved": "https://npm.aiursoft.cn/select/-/select-1.1.2.tgz",
"integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==",
"license": "MIT"
},
"node_modules/tiny-emitter": {
"version": "2.1.0",
"resolved": "https://npm.aiursoft.cn/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
"integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==",
"license": "MIT"
}
}
}
@@ -1,11 +1,19 @@
import { Chess } from "../../node_modules/chess.js/dist/esm/chess.js";
import {
initSoundForMobile,
initSoundForPC,
playSoundForPC,
playSoundForMobile,
} from "./sound.js";
import {
buildOnDragStart,
buildOnDrop,
buildOnSnapEnd,
buildOnChange,
WHITE_ABBREVIATION,
BLACK_ABBREVIATION,
WHITE,
BLACK,
findMove,
} from "./defaultConfig.js";
@@ -20,7 +28,7 @@ import {
* @param {HTMLElement} statusControl status control element
* @param {HTMLElement} roleControl role control element
*/
function ChessBuilder(color, statusControl, roleControl) {
function ChessBuilder(color, statusControl, roleControl, soundControl) {
this.onDragStart = undefined;
this.onDrop = undefined;
this.onSnapEnd = undefined;
@@ -34,8 +42,10 @@ function ChessBuilder(color, statusControl, roleControl) {
anduinChessBoard.config.onDragStart = buildOnDragStart(anduinChessBoard);
anduinChessBoard.config.onDrop = buildOnDrop(anduinChessBoard);
anduinChessBoard.config.onSnapEnd = buildOnSnapEnd(anduinChessBoard);
anduinChessBoard.config.onChange = buildOnChange(anduinChessBoard);
anduinChessBoard.statusControl = statusControl;
anduinChessBoard.roleControl = roleControl;
anduinChessBoard.soundControl = soundControl;
return anduinChessBoard;
};
@@ -48,7 +58,11 @@ function AnduinChessBoard(color) {
this.socket = null;
this.statusControl = null;
this.roleControl = null;
this.soundControl = null;
this.lastMovePair = [null, null];
this.isWhiteCheck = false;
this.isBlackCheck = false;
this.statusText = "";
this.config = {
orientation: this.color === BLACK_ABBREVIATION ? "black" : "white",
@@ -60,7 +74,28 @@ function AnduinChessBoard(color) {
onSnapEnd: null,
};
this.renderTrack = () => {
this._initSound = () => {
if (/Mobile/.test(navigator.userAgent)) {
initSoundForMobile.bind(this)(this);
this._playSound = playSoundForMobile.bind(this);
} else {
initSoundForPC.bind(this)(this);
this._playSound = playSoundForPC.bind(this);
}
};
this._playSound = () => {};
/**
* render some styles, like highlight, red light
*/
this.render = () => {
this._renderTrack();
this._renderCheck();
this._renderStatusText();
};
this._renderTrack = () => {
if (this.lastMovePair[0] !== null && this.lastMovePair[1] !== null) {
let allSquares = Array.from(
document.querySelectorAll(`#board [data-square]`)
@@ -84,6 +119,37 @@ function AnduinChessBoard(color) {
}
};
this._renderCheck = () => {
let checkedPosition = null;
if (this.isWhiteCheck) {
checkedPosition = this._getKingPosition(WHITE_ABBREVIATION);
} else if (this.isBlackCheck) {
checkedPosition = this._getKingPosition(BLACK_ABBREVIATION);
}
document.querySelectorAll("#board [data-square]").forEach((p) => {
p.style.backgroundImage = "";
});
if (checkedPosition !== null) {
document.querySelector(
`#board [data-square=${checkedPosition}]`
).style.backgroundImage = "radial-gradient(circle, red 5%, transparent)";
}
};
this._renderStatusText = () => {
this.statusControl.innerHTML = this.statusText;
};
this._getKingPosition = (bOrW) => {
let pieces = []
.concat(...this.game.board())
.filter((p) => p !== null && p.type === "k" && p.color === bOrW)
.map((p) => p.square);
return pieces.length > 0 ? pieces[0] : null;
};
this.run = (player, gameId) => {
this.roleControl.innerHTML = `You are ${
this.color === WHITE_ABBREVIATION
@@ -93,6 +159,8 @@ function AnduinChessBoard(color) {
: "Spectator"
} player.`;
this._initSound();
const completeInit = (fen) => {
this.config.position = fen;
@@ -105,7 +173,7 @@ function AnduinChessBoard(color) {
this.board = ChessBoard("board", this.config);
this.socket.onmessage = (event) => {
this.refresh(event.data);
this._refresh(event.data);
};
this.socket.onclose = () => {
setTimeout(() => {
@@ -113,7 +181,7 @@ function AnduinChessBoard(color) {
}, 1000);
};
this.refresh(fen);
this._refresh(fen);
};
fetch(`/games/${gameId}.fen`)
@@ -121,39 +189,48 @@ function AnduinChessBoard(color) {
.then(completeInit);
};
this.refresh = (newFEN) => {
this._refresh = (newFEN) => {
if (this.game !== null) {
let [position1, position2] = findMove(this.game.fen(), newFEN);
this.lastMovePair = [position1, position2];
this.renderTrack();
}
this.game = new Chess(newFEN);
this.board.position(newFEN);
console.log(`Got fen ${newFEN}. refreshing board...`);
this.updateStatusText();
this._updateStatus();
this.render();
};
this.updateStatusText = () => {
let status;
let moveColor = "White";
this._updateStatus = () => {
let moveColor = WHITE;
if (this.game.turn() === BLACK_ABBREVIATION) {
moveColor = "Black";
moveColor = BLACK;
}
this.isWhiteCheck = null;
this.isBlackCheck = null;
this.statusText = `${moveColor} to move`;
if (this.game.isCheck()) {
this.isWhiteCheck = moveColor === WHITE;
this.isBlackCheck = moveColor === BLACK;
this.statusText += `, ${moveColor} is in check`;
}
if (this.game.isCheckmate()) {
status = `Game over, ${moveColor} is in checkmate, and winner is ${
this.isWhiteCheck = moveColor === WHITE;
this.isBlackCheck = moveColor === BLACK;
this.statusText = `Game over, ${moveColor} is in checkmate, and winner is ${
this.game.turn() === WHITE_ABBREVIATION ? "Black" : "White"
}`;
} else if (this.game.isDraw()) {
status = "Game over, drawn position";
} else {
status = `${moveColor} to move`;
if (this.game.isCheck()) {
status += `, ${moveColor} is in check`;
}
if (this.game.isDraw()) {
this.statusText = "Game over, drawn position";
}
this.statusControl.innerHTML = status;
};
}
@@ -1,5 +1,7 @@
const WHITE_ABBREVIATION = "w";
const BLACK_ABBREVIATION = "b";
const WHITE = "White";
const BLACK = "Black";
const WHITE_SQUARE_GREY = "#a9a9a9";
const BLACK_SQUARE_GREY = "#696969";
@@ -65,7 +67,7 @@ function buildOnDragStart(globalParams) {
*
* # example:
* ```js
* let onDrop = onDrop({game, socket, lastMovePair, renderTrack});
* let onDrop = onDrop({game, socket, lastMovePair, render});
* ```
*
* @param {{game, socket}} globalParams
@@ -75,7 +77,7 @@ function buildOnDrop(globalParams) {
const realOnDrop = (source, target) => {
let game = globalParams.game;
let socket = globalParams.socket;
let renderTrack = globalParams.renderTrack;
let render = globalParams.render;
document.querySelectorAll("#board [data-square]").forEach((square) => {
square.style.backgroundColor = "";
@@ -93,7 +95,7 @@ function buildOnDrop(globalParams) {
if (source !== target) {
globalParams.lastMovePair = [source, target];
renderTrack();
render();
}
const lastMove = game.history({ verbose: true }).pop().san;
@@ -128,7 +130,13 @@ function buildOnSnapEnd(globalParams) {
return realOnSnapEnd;
}
function trackFEN() {}
function buildOnChange(globalParams) {
const onChange = (oldPos, newPos) => {
globalParams._playSound();
};
return onChange;
}
function parseFEN(fen) {
const parts = fen.split(" ")[0].split("/");
@@ -194,9 +202,12 @@ export {
buildOnDragStart,
buildOnDrop,
buildOnSnapEnd,
buildOnChange,
WHITE_ABBREVIATION,
BLACK_ABBREVIATION,
WHITE_SQUARE_GREY,
BLACK_SQUARE_GREY,
WHITE,
BLACK,
findMove,
};
@@ -0,0 +1,67 @@
const MINIMAL_BUT_NOT_MUTE = 0.0001;
function initSoundForPC() {
if (this.soundControl === null) {
return;
}
this.soundControl.volume = MINIMAL_BUT_NOT_MUTE;
const activeSound = () => {
if (this.soundControl.played.length === 0) {
this.soundControl.play();
} else {
document.body.removeEventListener("click", activeSound);
}
};
document.body.addEventListener("click", activeSound);
}
function initSoundForMobile() {
if (this.soundControl === null) {
return;
}
this.soundControl.muted = true;
const activeSound = () => {
if (this.soundControl.played.length === 0) {
this.soundControl.play();
} else {
document.body.removeEventListener("click", activeSound);
}
};
document.body.addEventListener("click", activeSound);
}
function playSoundForPC() {
const START = 0;
// 'this' should be points anduinChessBoard
if (this.soundControl !== null) {
this.soundControl.currentTime = START;
this.soundControl.volume = 1;
setTimeout(() => {
this.soundControl.volume = MINIMAL_BUT_NOT_MUTE;
}, 500);
}
}
function playSoundForMobile() {
// 'this' should be points anduinChessBoard
if (this.soundControl !== null) {
this.soundControl.currentTime = 0;
this.soundControl.muted = false;
setTimeout(() => {
this.soundControl.muted = true;
}, 500);
}
}
export {
initSoundForPC,
initSoundForMobile,
playSoundForPC,
playSoundForMobile,
};
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<RootNamespace>Aiursoft.ChessServer.Tests</RootNamespace>
<IsTestProject>true</IsTestProject>
<IsPackable>false</IsPackable>
@@ -9,15 +9,15 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.2">
<PackageReference Include="coverlet.collector" Version="6.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="JunitXml.TestLogger" Version="3.1.12" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.4.3" />
<PackageReference Include="MSTest.TestFramework" Version="3.4.3" />
<PackageReference Include="AngleSharp" Version="1.1.2" />
<PackageReference Include="JunitXml.TestLogger" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="MSTest.TestAdapter" Version="3.7.0" />
<PackageReference Include="MSTest.TestFramework" Version="3.7.0" />
<PackageReference Include="AngleSharp" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Aiursoft.ChessServer\Aiursoft.ChessServer.csproj" />