├── .gitignore
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── .vscode
├── launch.json
└── tasks.json
├── Chess.ConsoleUI
├── Chess.ConsoleUI.csproj
└── Program.cs
├── Chess.Domain
├── Api.fs
├── Chess.Domain.fsproj
├── Chess.fs
└── Validation.fs
├── Chess.FabUI.Android
├── Assets
│ └── AboutAssets.txt
├── Chess.FabUI.Android.fsproj
├── MainActivity.fs
├── Properties
│ ├── AndroidManifest.xml
│ └── AssemblyInfo.fs
├── Resources
│ ├── AboutResources.txt
│ ├── Resource.designer.cs
│ ├── layout
│ │ ├── Tabbar.axml
│ │ └── Toolbar.axml
│ ├── mipmap-anydpi-v26
│ │ ├── icon.xml
│ │ └── icon_round.xml
│ ├── mipmap-hdpi
│ │ ├── Icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-mdpi
│ │ ├── icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xhdpi
│ │ ├── Icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xxhdpi
│ │ ├── Icon.png
│ │ └── launcher_foreground.png
│ ├── mipmap-xxxhdpi
│ │ ├── Icon.png
│ │ └── launcher_foreground.png
│ └── values
│ │ ├── colors.xml
│ │ └── styles.xml
└── packages.config
├── Chess.FabUI.WPF
├── App.fs
├── Chess.FabUI.WPF.fsproj
├── Images
│ ├── pieces_black
│ │ ├── bishop.png
│ │ ├── king.png
│ │ ├── knight.png
│ │ ├── pawn.png
│ │ ├── queen.png
│ │ └── rook.png
│ └── pieces_white
│ │ ├── bishop.png
│ │ ├── king.png
│ │ ├── knight.png
│ │ ├── pawn.png
│ │ ├── queen.png
│ │ └── rook.png
├── Properties
│ └── AssemblyInfo.fs
└── app.config
├── Chess.FabUI.iOS
├── AppDelegate.fs
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── Icon1024.png
│ │ ├── Icon120.png
│ │ ├── Icon152.png
│ │ ├── Icon167.png
│ │ ├── Icon180.png
│ │ ├── Icon20.png
│ │ ├── Icon29.png
│ │ ├── Icon40.png
│ │ ├── Icon58.png
│ │ ├── Icon60.png
│ │ ├── Icon76.png
│ │ ├── Icon80.png
│ │ └── Icon87.png
├── Chess.FabUI.iOS.fsproj
├── Entitlements.plist
├── Info.plist
├── Properties
│ └── AssemblyInfo.fs
├── Resources
│ ├── Default-568h@2x.png
│ ├── Default-Portrait.png
│ ├── Default-Portrait@2x.png
│ ├── Default.png
│ ├── Default@2x.png
│ └── LaunchScreen.storyboard
└── packages.config
├── Chess.FabUI
├── Chess.FabUI.fs
└── Chess.FabUI.fsproj
├── Chess.WebUI
├── .editorconfig
├── .gitattributes
├── .gitignore
├── .paket
│ ├── Paket.Restore.targets
│ ├── paket.exe
│ ├── paket.exe.config
│ └── paket.targets
├── .vscode
│ └── tasks.json
├── Chess.WebUI.sln
├── NuGet.Config
├── README.md
├── RELEASE_NOTES.md
├── package-lock.json
├── package.json
├── paket.dependencies
├── paket.lock
├── public
│ ├── img
│ │ ├── favicon-16x16.png
│ │ └── favicon-32x32.png
│ └── index.html
├── sass
│ └── main.sass
├── src
│ ├── App.fs
│ ├── Chess.WebUI.fsproj
│ ├── Counter
│ │ ├── State.fs
│ │ ├── Types.fs
│ │ └── View.fs
│ ├── Global.fs
│ ├── Home
│ │ ├── State.fs
│ │ ├── Types.fs
│ │ └── View.fs
│ ├── Info
│ │ └── View.fs
│ ├── Navbar
│ │ └── View.fs
│ ├── State.fs
│ ├── Types.fs
│ └── paket.references
└── webpack.config.js
├── Chess.WpfUI
├── App.config
├── App.xaml
├── App.xaml.cs
├── Chess.WpfUI.csproj
├── Images
│ ├── pieces_black
│ │ ├── bishop.png
│ │ ├── king.png
│ │ ├── knight.png
│ │ ├── pawn.png
│ │ ├── queen.png
│ │ └── rook.png
│ └── pieces_white
│ │ ├── bishop.png
│ │ ├── king.png
│ │ ├── knight.png
│ │ ├── pawn.png
│ │ ├── queen.png
│ │ └── rook.png
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
└── packages.config
├── Chess.sln
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
--------------------------------------------------------------------------------
/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config"))
32 |
33 |
34 |
35 |
36 | $(SolutionDir).nuget
37 | packages.config
38 |
39 |
40 |
41 |
42 | $(NuGetToolsPath)\NuGet.exe
43 | @(PackageSource)
44 |
45 | "$(NuGetExePath)"
46 | mono --runtime=v4.0.30319 $(NuGetExePath)
47 |
48 | $(TargetDir.Trim('\\'))
49 |
50 | -RequireConsent
51 | -NonInteractive
52 |
53 | "$(SolutionDir.Trim('\\'))"
54 | "$(SolutionDir)"
55 |
56 |
57 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
58 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
59 |
60 |
61 |
62 | RestorePackages;
63 | $(BuildDependsOn);
64 |
65 |
66 |
67 |
68 | $(BuildDependsOn);
69 | BuildPackage;
70 |
71 |
72 |
73 |
74 |
75 |
76 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
98 |
100 |
101 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to find out which attributes exist for C# debugging
3 | // Use hover for the description of the existing attributes
4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": ".NET Core Launch (console)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/Chess.ConsoleUI/bin/Debug/netcoreapp2.0/Chess.ConsoleUI.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}/Chess.ConsoleUI",
16 | // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window
17 | "console": "internalConsole",
18 | "stopAtEntry": false,
19 | "internalConsoleOptions": "openOnSessionStart"
20 | },
21 | {
22 | "name": ".NET Core Attach",
23 | "type": "coreclr",
24 | "request": "attach",
25 | "processId": "${command:pickProcess}"
26 | }
27 | ,]
28 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/Chess.ConsoleUI/Chess.ConsoleUI.csproj"
11 | ],
12 | "problemMatcher": "$msCompile"
13 | }
14 | ]
15 | }
--------------------------------------------------------------------------------
/Chess.ConsoleUI/Chess.ConsoleUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | netcoreapp2.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Chess.ConsoleUI/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using static Chess.Domain.Api;
7 |
8 | namespace Chess.ConsoleUI
9 | {
10 | class Program
11 | {
12 |
13 | private static bool UseEmoji = false;
14 | static void Main(string[] args)
15 | {
16 | if (args.Length > 0 && args[0] == "-e")
17 | {
18 | UseEmoji = true;
19 | Console.OutputEncoding = Encoding.UTF8;
20 | }
21 |
22 | var api = new ChessApi();
23 | RenderGame(api);
24 | }
25 |
26 | static void RenderGame(ChessApi api)
27 | {
28 | /* The board:
29 |
30 | A B C D E F G H
31 | ─ ─ ─ ─ ─ ─ ─ ─
32 | 8 | r n b q k b n r
33 | 7 | p p p p p p p p
34 | 6 | . . . . . . . .
35 | 5 | . . . . . . . .
36 | 4 | . . . . . . . .
37 | 3 | . . . . . . . .
38 | 2 | P P P P P P P P
39 | 1 | R N B K Q B N R
40 | */
41 |
42 | Console.WriteLine();
43 | Console.WriteLine(" A B C D E F G H");
44 | Console.WriteLine(" ─ ─ ─ ─ ─ ─ ─ ─");
45 |
46 | var rows = new[] { "8", "7", "6", "5", "4", "3", "2", "1" };
47 | var cols = new[] { "A", "B", "C", "D", "E", "F", "G", "H" };
48 | var cells = api.Cells.ToDictionary(c => c.Coord);
49 |
50 | foreach (var row in rows)
51 | {
52 | Console.Write("{0} |", row);
53 |
54 | foreach (var col in cols)
55 | {
56 | var cell = cells[col + row];
57 | Console.Write(" {0}", RenderCell(cell));
58 | }
59 |
60 | Console.WriteLine();
61 | }
62 |
63 | Console.WriteLine();
64 | Console.WriteLine(api.Message);
65 |
66 | // TODO: Add game over state to the public facing api and handle here
67 |
68 | Console.WriteLine("Enter a move in the following format: A2 A3 (case insensitive)");
69 | Console.Write("> ");
70 |
71 | var moveText = Console.ReadLine();
72 | var move = new ParsedMove(moveText);
73 | if (move.IsValid)
74 | {
75 | try
76 | {
77 | api.Move(move.From, move.To);
78 | }
79 | catch (Exception)
80 | {
81 | }
82 | }
83 |
84 | Console.Clear();
85 | RenderGame(api);
86 | }
87 |
88 | private static Dictionary rankChars = new Dictionary
89 | {
90 | ["pawn"] = "p",
91 | ["rook"] = "r",
92 | ["knight"] = "n",
93 | ["bishop"] = "b",
94 | ["queen"] = "q",
95 | ["king"] = "k"
96 | };
97 | private static Dictionary rankEmojiBlack = new Dictionary
98 | {
99 | ["pawn"] = "♟",
100 | ["rook"] = "♜",
101 | ["knight"] = "♞",
102 | ["bishop"] = "♝",
103 | ["queen"] = "♛",
104 | ["king"] = "♚"
105 | };
106 | private static Dictionary rankEmojiWhite = new Dictionary
107 | {
108 | ["pawn"] = "♙",
109 | ["rook"] = "♖",
110 | ["knight"] = "♘",
111 | ["bishop"] = "♗",
112 | ["queen"] = "♕",
113 | ["king"] = "♔"
114 | };
115 |
116 | static string glyphForPiece(string rank, string color)
117 | {
118 | if (UseEmoji)
119 | {
120 | var glyphs = (color == "black") ? rankEmojiBlack : rankEmojiWhite;
121 | return glyphs[rank];
122 | }
123 | else
124 | {
125 | var glyph = rankChars[rank];
126 | return (color == "black") ? glyph.ToLower() : glyph.ToUpper();
127 | }
128 |
129 |
130 |
131 | }
132 |
133 | static string RenderCell(CellDTO cell)
134 | {
135 | switch (cell)
136 | {
137 | case CellDTO c when !c.IsOccupied:
138 | return ".";
139 |
140 | case CellDTO c when c.Color == "black" && c.Rank == "pawn":
141 | return glyphForPiece(c.Rank, c.Color);
142 | case CellDTO c when c.Color == "black" && c.Rank == "rook":
143 | return glyphForPiece(c.Rank, c.Color);
144 | case CellDTO c when c.Color == "black" && c.Rank == "knight":
145 | return glyphForPiece(c.Rank, c.Color);
146 | case CellDTO c when c.Color == "black" && c.Rank == "bishop":
147 | return glyphForPiece(c.Rank, c.Color);
148 | case CellDTO c when c.Color == "black" && c.Rank == "queen":
149 | return glyphForPiece(c.Rank, c.Color);
150 | case CellDTO c when c.Color == "black" && c.Rank == "king":
151 | return glyphForPiece(c.Rank, c.Color);
152 |
153 | case CellDTO c when c.Color == "white" && c.Rank == "pawn":
154 | return glyphForPiece(c.Rank, c.Color);
155 | case CellDTO c when c.Color == "white" && c.Rank == "rook":
156 | return glyphForPiece(c.Rank, c.Color);
157 | case CellDTO c when c.Color == "white" && c.Rank == "knight":
158 | return glyphForPiece(c.Rank, c.Color);
159 | case CellDTO c when c.Color == "white" && c.Rank == "bishop":
160 | return glyphForPiece(c.Rank, c.Color);
161 | case CellDTO c when c.Color == "white" && c.Rank == "queen":
162 | return glyphForPiece(c.Rank, c.Color);
163 | case CellDTO c when c.Color == "white" && c.Rank == "king":
164 | return glyphForPiece(c.Rank, c.Color);
165 |
166 | default:
167 | throw new Exception("Invalid piece.");
168 | }
169 | }
170 |
171 | class ParsedMove
172 | {
173 | public ParsedMove(string move)
174 | {
175 | var parts = (move ?? string.Empty).ToUpper().Split(new char[] { ',', ' ', '-' });
176 | if (parts.Length == 2)
177 | {
178 | IsValid = true;
179 | From = parts[0];
180 | To = parts[1];
181 | }
182 | else
183 | {
184 | IsValid = false;
185 | }
186 | }
187 |
188 | public string From { get; private set; }
189 | public string To { get; private set; }
190 | public bool IsValid { get; private set; }
191 | }
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/Chess.Domain/Api.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.Domain
2 |
3 | /// Facilitates interop when using the C# WPF UI.
4 | /// Not needed when using the Fabulous UI!
5 | module Api =
6 | open Chess.Domain.Entities
7 |
8 | type CellDTO = { Coord: string; IsOccupied: bool; Color: string; Rank: string }
9 |
10 | /// cellStr ex: "{ coord: "A1", piece { rank: "Bishop", color: "White" }
11 | let deserializeCoord (cellStr: string) : Cell =
12 | let colMap = List.zip ["A"; "B"; "C"; "D"; "E"; "F"; "G"; "H";] Column.List |> Map.ofList
13 | let rowMap = List.zip ["1"; "2"; "3"; "4"; "5"; "6"; "7"; "8";] Row.List |> Map.ofList
14 | match cellStr.ToCharArray() with
15 | | [| col; row |] -> { Col = colMap.[col.ToString()]; Row = rowMap.[row.ToString()] }
16 | | _ -> failwith "Invalid cell"
17 |
18 | let serializeCell cell =
19 | let colMap = List.zip Column.List ["A"; "B"; "C"; "D"; "E"; "F"; "G"; "H";] |> Map.ofList
20 | let rowMap = List.zip Row.List ["1"; "2"; "3"; "4"; "5"; "6"; "7"; "8";] |> Map.ofList
21 | colMap.[cell.Col] + rowMap.[cell.Row]
22 |
23 | let boardToCellsDto (board: Board) =
24 | let cell_piece_list = Map.toList board
25 | let cells = cell_piece_list |> List.map (fun (cell, piece) ->
26 | match piece with
27 | | Some (color,rank) ->
28 | {
29 | Coord = serializeCell cell
30 | IsOccupied = true
31 | Color = match color with | White -> "white" | Black -> "black"
32 | Rank = match rank with | Pawn _ -> "pawn" | Rook -> "rook" | Bishop -> "bishop" | King -> "king" | Queen -> "queen" | Knight -> "knight"
33 | }
34 | | None ->
35 | {
36 | Coord = serializeCell cell
37 | IsOccupied = false
38 | Color = null
39 | Rank = null
40 | })
41 | cells
42 |
43 | type ChessApi() =
44 |
45 | let mutable gameState = Implementation.initGame()
46 |
47 | member this.InitGame() = gameState <- Implementation.initGame()
48 |
49 | member this.Cells with get() = boardToCellsDto gameState.Board |> List.toArray
50 |
51 | member this.Message with get() = gameState.Message
52 |
53 | member this.Move(fromCell: string, toCell: string) =
54 | let cell1 = deserializeCoord fromCell
55 | let cell2 = deserializeCoord toCell
56 | gameState <- Implementation.move gameState { FromCell = cell1; ToCell = cell2 }
57 | ()
--------------------------------------------------------------------------------
/Chess.Domain/Chess.Domain.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Chess.Domain/Chess.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.Domain
2 |
3 | module Entities =
4 | type Color = | White | Black
5 | type HasMoved = | NotMoved | Moved
6 | type Rank = | Pawn of HasMoved | Rook | Bishop | Knight | Queen | King
7 | type Piece = Color * Rank
8 | type Column = | A | B | C | D | E | F | G | H
9 | with static member List = [A;B;C;D;E;F;G;H]
10 | type Row = | One | Two | Three | Four | Five | Six | Seven | Eight
11 | with static member List = [One; Two; Three; Four; Five; Six; Seven; Eight]
12 | type Cell = { Col: Column; Row: Row }
13 | type Board = Map
14 | type GameProgress = | InProgress | WhiteWins | BlackWins
15 | type GameState = { Board: Board; NextMove: Color; Message: string }
16 | type AttemptedMove = { FromCell: Cell; ToCell: Cell }
17 | type Move = { FromPiece: Piece; FromCell: Cell; ToCell: Cell }
18 |
19 | module Implementation =
20 | open Entities
21 |
22 | let initGame () =
23 | let blackPawn = Some (Black, Pawn NotMoved)
24 | let whitePawn = Some (White, Pawn NotMoved)
25 | let white rank = Some (White, rank)
26 | let black rank = Some (Black, rank)
27 |
28 | let createRow row pieces =
29 | let cells = Column.List |> List.map (fun col -> { Col = col; Row = row })
30 | List.zip cells pieces
31 |
32 | let board =
33 | Map ( (createRow Eight [black Rook; black Knight; black Bishop; black King; black Queen; black Bishop; black Knight; black Rook]) @
34 | (createRow Seven [blackPawn; blackPawn; blackPawn; blackPawn; blackPawn; blackPawn; blackPawn; blackPawn]) @
35 | (createRow Six [None; None; None; None; None; None; None; None]) @
36 | (createRow Five [None; None; None; None; None; None; None; None]) @
37 | (createRow Four [None; None; None; None; None; None; None; None]) @
38 | (createRow Three [None; None; None; None; None; None; None; None]) @
39 | (createRow Two [whitePawn; whitePawn; whitePawn; whitePawn; whitePawn; whitePawn; whitePawn; whitePawn]) @
40 | (createRow One [white Rook; white Knight; white Bishop; white King; white Queen; white Bishop; white Knight; white Rook]) )
41 |
42 | { Board = board;
43 | NextMove = White;
44 | Message = "Welcome to F# Chess!" }
45 |
46 | let validateFromPieceTurn gameState (attemptedMove: AttemptedMove) : Result =
47 | match gameState.Board.[attemptedMove.FromCell] with
48 | | Some (fromColor, fromRank) ->
49 | if fromColor = gameState.NextMove
50 | then Ok { FromPiece = (fromColor, fromRank); FromCell = attemptedMove.FromCell; ToCell = attemptedMove.ToCell }
51 | else Error "It's not your turn"
52 | | None ->
53 | Error "No piece was selected to move"
54 |
55 | let validateNotFriendlyTarget gameState move =
56 | match gameState.Board.[move.ToCell] with
57 | | Some (toColor, toRank) ->
58 | if gameState.NextMove = toColor
59 | then Error "Can not take a friendly piece"
60 | else Ok move
61 | | None -> Ok move
62 |
63 | let getHorizDist fromCell toCell =
64 | let toIdx = Column.List |> List.findIndex (fun c -> c = toCell.Col)
65 | let fromIdx = Column.List |> List.findIndex (fun c -> c = fromCell.Col)
66 | toIdx - fromIdx
67 |
68 | let getVertDist fromCell toCell =
69 | let toIdx = Row.List |> List.findIndex (fun r -> r = toCell.Row)
70 | let fromIdx = Row.List |> List.findIndex (fun r -> r = fromCell.Row)
71 | toIdx - fromIdx
72 |
73 | let tryGetCell (colIdx,rowIdx) =
74 | if colIdx < Column.List.Length && colIdx >= 0 && rowIdx < Column.List.Length && rowIdx >= 0
75 | then Some { Col = Column.List.[colIdx]; Row = Row.List.[rowIdx] }
76 | else None
77 |
78 | let getCoords cell =
79 | let colIdx = Column.List |> List.findIndex (fun c -> c = cell.Col)
80 | let rowIdx = Row.List |> List.findIndex (fun r -> r = cell.Row)
81 | (colIdx, rowIdx)
82 |
83 | let validateMoveShape gameState move : Result =
84 | let (fromPieceColor, fromPieceRank) = move.FromPiece
85 | let toPieceOpt = gameState.Board.Item move.ToCell
86 |
87 | let xDelta = getHorizDist move.FromCell move.ToCell
88 | let yDelta = getVertDist move.FromCell move.ToCell
89 |
90 | let validateKnight() =
91 | let isL = match (abs xDelta, abs yDelta) with | (1,2) -> true | (2,1) -> true | _ -> false
92 | if isL
93 | then Ok move
94 | else Error "Knight can only move in an L pattern"
95 |
96 | let validateRook() =
97 | let isUpDownLeftRight = (abs xDelta > 0 && yDelta = 0) || (xDelta = 0 && abs yDelta > 0)
98 | if isUpDownLeftRight
99 | then Ok move
100 | else Error "Rook can only move up, down, left or right"
101 |
102 | let validateBishop() =
103 | let isDiag = (abs xDelta = abs yDelta)
104 | if isDiag
105 | then Ok move
106 | else Error "Bishop can only move diagonally"
107 |
108 | let validateKing() =
109 | let isAnyDirectionOneSpace = (abs xDelta = 1 || xDelta = 0) && (abs yDelta = 1 || yDelta = 0)
110 | if isAnyDirectionOneSpace
111 | then Ok move
112 | else Error "King can only move one space in any direction"
113 |
114 | let validateQueen() =
115 | let isAnyDirection = (abs xDelta = abs yDelta) || (abs xDelta > 0 && yDelta = 0) || (xDelta = 0 && abs yDelta > 0)
116 | if isAnyDirection
117 | then Ok move
118 | else Error "Queen can only move diagonally, up, down, left or right"
119 |
120 | let validatePawn hasMoved =
121 | match toPieceOpt with
122 | | Some toPiece -> // Moving to an occupied cell
123 | // Check for diagonal captures
124 | match (fromPieceColor, abs xDelta, yDelta) with
125 | | (White, 1, 1)
126 | | (Black, 1, -1)
127 | -> Ok move
128 | | _ -> Error "Pawn can only capture moving one space diagonally"
129 | | None -> // Moving to an empty cell
130 | // Check for straight non-captures
131 | match (fromPieceColor, xDelta, yDelta, hasMoved) with
132 | | (White, 0, 1, _) -> Ok move // can always move forward one space to an empty cell
133 | | (White, 0, 2, NotMoved) -> Ok move // can move forward two spaces only if pawn has not yet moved
134 | | (Black, 0, -1, _) -> Ok move // can always move forward one space to an empty cell
135 | | (Black, 0, -2, NotMoved) -> Ok move // can move forward two spaces only if pawn has not yet moved
136 | | _ -> Error "Pawn can move forward one space (or two spaces on the first move)"
137 |
138 | match fromPieceRank with
139 | | Bishop -> validateBishop()
140 | | Rook -> validateRook()
141 | | King -> validateKing()
142 | | Queen -> validateQueen()
143 | | Knight -> validateKnight()
144 | | Pawn hasMoved -> validatePawn hasMoved
145 |
146 | let validateNoInterposition gameState move =
147 | match move.FromPiece with
148 | | color, Knight -> Ok move
149 | | _ ->
150 | let xDelta = getHorizDist move.FromCell move.ToCell
151 | let yDelta = getVertDist move.FromCell move.ToCell
152 |
153 | let normalize n = if n > 0 then 1 elif n < 0 then -1 else 0
154 | let addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
155 | let unitVector = (normalize xDelta, normalize yDelta)
156 |
157 | let rec moveSeq startCell vector =
158 | seq {
159 | let nextCell =
160 | startCell
161 | |> getCoords
162 | |> addVectors vector
163 | |> tryGetCell
164 |
165 | if nextCell.IsSome then
166 | yield nextCell.Value
167 | yield! moveSeq nextCell.Value vector
168 | }
169 |
170 | let valid =
171 | moveSeq move.FromCell unitVector
172 | |> Seq.takeWhile (fun nextCell -> nextCell <> move.ToCell)
173 | |> Seq.forall (fun nextCell -> gameState.Board.[nextCell].IsNone)
174 |
175 | if valid
176 | then Ok move
177 | else Error "Another piece is blocking this move"
178 |
179 | let updateBoard (board: Board) move =
180 | let fromPieceColor, fromPieceRank = move.FromPiece
181 | match fromPieceRank with
182 | | Pawn pi ->
183 | board.Add(move.FromCell, None).Add(move.ToCell, Some (fromPieceColor, Pawn Moved))
184 | | _ ->
185 | board.Add(move.FromCell, None).Add(move.ToCell, Some (fromPieceColor, fromPieceRank))
186 |
187 | let updateNextMoveColor color =
188 | match color with
189 | | Black -> White
190 | | White -> Black
191 |
192 | let validateMove (gameState: GameState) (attemptedMove: AttemptedMove) =
193 | attemptedMove
194 | |> validateFromPieceTurn gameState
195 | |> Result.bind (validateNotFriendlyTarget gameState)
196 | |> Result.bind (validateMoveShape gameState)
197 | |> Result.bind (validateNoInterposition gameState)
198 |
199 | let move (gameState: GameState) (attemptedMove: AttemptedMove) =
200 | let validatedMove = validateMove gameState attemptedMove
201 | match validatedMove with
202 | | Ok move ->
203 | { gameState with
204 | Board = updateBoard gameState.Board move
205 | NextMove = updateNextMoveColor(gameState.NextMove)
206 | Message = "" }
207 | | Error msg ->
208 | { gameState with Message = msg }
209 |
--------------------------------------------------------------------------------
/Chess.Domain/Validation.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.Domain
2 |
3 | module Validation =
4 |
5 | let (>>=) result f =
6 | match result with
7 | | Ok t -> f t
8 | | Error msg -> Error msg
9 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Assets/AboutAssets.txt:
--------------------------------------------------------------------------------
1 | Any raw assets you want to be deployed with your application can be placed in
2 | this directory (and child directories) and given a Build Action of "AndroidAsset".
3 |
4 | These files will be deployed with you package and will be accessible using Android's
5 | AssetManager, like this:
6 |
7 | public class ReadAsset : Activity
8 | {
9 | protected override void OnCreate (Bundle bundle)
10 | {
11 | base.OnCreate (bundle);
12 |
13 | InputStream input = Assets.Open ("my_asset.txt");
14 | }
15 | }
16 |
17 | Additionally, some Android functions will automatically load asset files:
18 |
19 | Typeface tf = Typeface.CreateFromAsset (Context.Assets, "fonts/samplefont.ttf");
20 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/MainActivity.fs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Fabulous contributors. See LICENSE.md for license.
2 | namespace Chess.FabUI.Android
3 |
4 | open System
5 |
6 | open Android.App
7 | open Android.Content
8 | open Android.Content.PM
9 | open Android.Runtime
10 | open Android.Views
11 | open Android.Widget
12 | open Android.OS
13 | open Xamarin.Forms.Platform.Android
14 |
15 | []
16 | type MainActivity() =
17 | inherit FormsAppCompatActivity()
18 | override this.OnCreate (bundle: Bundle) =
19 | FormsAppCompatActivity.TabLayoutResource <- Resources.Layout.Tabbar
20 | FormsAppCompatActivity.ToolbarResource <- Resources.Layout.Toolbar
21 | base.OnCreate (bundle)
22 |
23 | Xamarin.Essentials.Platform.Init(this, bundle)
24 |
25 | Xamarin.Forms.Forms.Init (this, bundle)
26 |
27 | let appcore = new Chess.FabUI.App()
28 | this.LoadApplication (appcore)
29 |
30 | override this.OnRequestPermissionsResult(requestCode: int, permissions: string[], [] grantResults: Android.Content.PM.Permission[]) =
31 | Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults)
32 |
33 | base.OnRequestPermissionsResult(requestCode, permissions, grantResults)
34 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Properties/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Properties/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.FabUI.Android
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 | open Android.App
7 |
8 | // the name of the type here needs to match the name inside the ResourceDesigner attribute
9 | type Resources = Chess.FabUI.Android.Resource
10 | []
11 |
12 | // General Information about an assembly is controlled through the following
13 | // set of attributes. Change these attribute values to modify the information
14 | // associated with an assembly.
15 | []
16 | []
17 | []
18 | []
19 | []
20 | []
21 | []
22 | []
23 | []
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // []
35 | []
36 | []
37 |
38 | // Add some common permissions, these can be removed if not needed
39 | []
40 | []
41 | do()
42 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/AboutResources.txt:
--------------------------------------------------------------------------------
1 | Images, layout descriptions, binary blobs and string dictionaries can be included
2 | in your application as resource files. Various Android APIs are designed to
3 | operate on the resource IDs instead of dealing with images, strings or binary blobs
4 | directly.
5 |
6 | For example, a sample Android app that contains a user interface layout (main.xml),
7 | an internationalization string table (strings.xml) and some icons (drawable-XXX/icon.png)
8 | would keep its resources in the "Resources" directory of the application:
9 |
10 | Resources/
11 | drawable-hdpi/
12 | icon.png
13 |
14 | drawable-ldpi/
15 | icon.png
16 |
17 | drawable-mdpi/
18 | icon.png
19 |
20 | layout/
21 | main.xml
22 |
23 | values/
24 | strings.xml
25 |
26 | In order to get the build system to recognize Android resources, set the build action to
27 | "AndroidResource". The native Android APIs do not operate directly with filenames, but
28 | instead operate on resource IDs. When you compile an Android application that uses resources,
29 | the build system will package the resources for distribution and generate a class called
30 | "Resource" that contains the tokens for each one of the resources included. For example,
31 | for the above Resources layout, this is what the Resource class would expose:
32 |
33 | public class Resource {
34 | public class drawable {
35 | public const int icon = 0x123;
36 | }
37 |
38 | public class layout {
39 | public const int main = 0x456;
40 | }
41 |
42 | public class strings {
43 | public const int first_string = 0xabc;
44 | public const int second_string = 0xbcd;
45 | }
46 | }
47 |
48 | You would then use R.drawable.icon to reference the drawable/icon.png file, or Resource.layout.main
49 | to reference the layout/main.xml file, or Resource.strings.first_string to reference the first
50 | string in the dictionary file values/strings.xml.
51 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/layout/Tabbar.axml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/layout/Toolbar.axml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-anydpi-v26/icon.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-anydpi-v26/icon_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-hdpi/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-hdpi/Icon.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-hdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-hdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-mdpi/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-mdpi/icon.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-mdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-mdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xhdpi/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xhdpi/Icon.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xxhdpi/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xxhdpi/Icon.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xxhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xxhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xxxhdpi/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xxxhdpi/Icon.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 | #3F51B5
5 | #303F9F
6 | #FF4081
7 |
8 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/Resources/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
26 |
27 |
30 |
31 |
--------------------------------------------------------------------------------
/Chess.FabUI.Android/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/App.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.FabUI.WPF
2 |
3 | open System
4 |
5 | open Xamarin.Forms
6 | open Xamarin.Forms.Platform.WPF
7 |
8 | type MainWindow() =
9 | inherit FormsApplicationPage()
10 |
11 | module Main =
12 | []
13 | []
14 | let main(_args) =
15 |
16 | let app = new System.Windows.Application()
17 | Forms.Init()
18 | let window = MainWindow(Title = "F# Chess", Height=530., Width=402.)
19 | window.LoadApplication(new Chess.FabUI.App())
20 |
21 | app.Run(window)
22 |
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Chess.FabUI.WPF.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | WinExe
4 | net472
5 | false
6 |
7 |
8 |
9 | PreserveNewest
10 |
11 |
12 | PreserveNewest
13 |
14 |
15 | PreserveNewest
16 |
17 |
18 | PreserveNewest
19 |
20 |
21 | PreserveNewest
22 |
23 |
24 | PreserveNewest
25 |
26 |
27 | PreserveNewest
28 |
29 |
30 | PreserveNewest
31 |
32 |
33 | PreserveNewest
34 |
35 |
36 | PreserveNewest
37 |
38 |
39 | PreserveNewest
40 |
41 |
42 | PreserveNewest
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 4.0
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/bishop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/bishop.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/king.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/king.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/knight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/knight.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/pawn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/pawn.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/queen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/queen.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_black/rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_black/rook.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/bishop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/bishop.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/king.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/king.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/knight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/knight.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/pawn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/pawn.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/queen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/queen.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Images/pieces_white/rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.WPF/Images/pieces_white/rook.png
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/Properties/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.FabUI.WPF
2 | open System.Reflection
3 | open System.Runtime.CompilerServices
4 |
5 | // the name of the type here needs to match the name inside the ResourceDesigner attribute
6 | //type Resources = Chess.FabUI.Droid.Resource
7 | //[]
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 |
17 | // The assembly version has the format {Major}.{Minor}.{Build}.{Revision}
18 |
19 | []
20 |
21 | //[]
22 | //[]
23 |
24 | ()
25 |
--------------------------------------------------------------------------------
/Chess.FabUI.WPF/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/AppDelegate.fs:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Fabulous contributors. See LICENSE.md for license.
2 | namespace Chess.FabUI.iOS
3 |
4 | open System
5 | open UIKit
6 | open Foundation
7 | open Xamarin.Forms
8 | open Xamarin.Forms.Platform.iOS
9 |
10 | []
11 | type AppDelegate () =
12 | inherit FormsApplicationDelegate ()
13 |
14 | override this.FinishedLaunching (app, options) =
15 | Forms.Init()
16 | let appcore = new Chess.FabUI.App()
17 | this.LoadApplication (appcore)
18 | base.FinishedLaunching(app, options)
19 |
20 | module Main =
21 | []
22 | let main args =
23 | UIApplication.Main(args, null, "AppDelegate")
24 | 0
25 |
26 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "scale": "2x",
5 | "size": "20x20",
6 | "idiom": "iphone",
7 | "filename": "Icon40.png"
8 | },
9 | {
10 | "scale": "3x",
11 | "size": "20x20",
12 | "idiom": "iphone",
13 | "filename": "Icon60.png"
14 | },
15 | {
16 | "scale": "2x",
17 | "size": "29x29",
18 | "idiom": "iphone",
19 | "filename": "Icon58.png"
20 | },
21 | {
22 | "scale": "3x",
23 | "size": "29x29",
24 | "idiom": "iphone",
25 | "filename": "Icon87.png"
26 | },
27 | {
28 | "scale": "2x",
29 | "size": "40x40",
30 | "idiom": "iphone",
31 | "filename": "Icon80.png"
32 | },
33 | {
34 | "scale": "3x",
35 | "size": "40x40",
36 | "idiom": "iphone",
37 | "filename": "Icon120.png"
38 | },
39 | {
40 | "scale": "2x",
41 | "size": "60x60",
42 | "idiom": "iphone",
43 | "filename": "Icon120.png"
44 | },
45 | {
46 | "scale": "3x",
47 | "size": "60x60",
48 | "idiom": "iphone",
49 | "filename": "Icon180.png"
50 | },
51 | {
52 | "scale": "1x",
53 | "size": "20x20",
54 | "idiom": "ipad",
55 | "filename": "Icon20.png"
56 | },
57 | {
58 | "scale": "2x",
59 | "size": "20x20",
60 | "idiom": "ipad",
61 | "filename": "Icon40.png"
62 | },
63 | {
64 | "scale": "1x",
65 | "size": "29x29",
66 | "idiom": "ipad",
67 | "filename": "Icon29.png"
68 | },
69 | {
70 | "scale": "2x",
71 | "size": "29x29",
72 | "idiom": "ipad",
73 | "filename": "Icon58.png"
74 | },
75 | {
76 | "scale": "1x",
77 | "size": "40x40",
78 | "idiom": "ipad",
79 | "filename": "Icon40.png"
80 | },
81 | {
82 | "scale": "2x",
83 | "size": "40x40",
84 | "idiom": "ipad",
85 | "filename": "Icon80.png"
86 | },
87 | {
88 | "scale": "1x",
89 | "size": "76x76",
90 | "idiom": "ipad",
91 | "filename": "Icon76.png"
92 | },
93 | {
94 | "scale": "2x",
95 | "size": "76x76",
96 | "idiom": "ipad",
97 | "filename": "Icon152.png"
98 | },
99 | {
100 | "scale": "2x",
101 | "size": "83.5x83.5",
102 | "idiom": "ipad",
103 | "filename": "Icon167.png"
104 | },
105 | {
106 | "scale": "1x",
107 | "size": "1024x1024",
108 | "idiom": "ios-marketing",
109 | "filename": "Icon1024.png"
110 | }
111 | ],
112 | "properties": {},
113 | "info": {
114 | "version": 1,
115 | "author": "xcode"
116 | }
117 | }
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon1024.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon120.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon152.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon167.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon180.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon20.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon29.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon40.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon58.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon60.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon76.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon80.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Assets.xcassets/AppIcon.appiconset/Icon87.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Chess.FabUI.iOS.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | iPhoneSimulator
8 | 8.0.30703
9 | 2.0
10 | {18D06679-5E5E-484C-82F4-AFCA81594CC5}
11 | {FEACFBD2-3405-455C-9665-78FE426C6842};{F2A71F9B-5D33-465A-A702-920D77279786}
12 | {6143fdea-f3c2-4a09-aafa-6e230626515e}
13 | Exe
14 | Chess.FabUI.iOS
15 | Resources
16 | Chess.FabUI.iOS
17 | NSUrlSessionHandler
18 |
19 |
20 | true
21 | true
22 |
23 |
24 | true
25 | full
26 | false
27 | bin\iPhoneSimulator\Debug
28 | DEBUG
29 | prompt
30 | 4
31 | false
32 | x86_64
33 | None
34 | true
35 |
36 |
37 | none
38 | true
39 | bin\iPhoneSimulator\Release
40 | prompt
41 | 4
42 | None
43 | x86_64
44 | false
45 |
46 |
47 | true
48 | full
49 | false
50 | bin\iPhone\Debug
51 | DEBUG
52 | prompt
53 | 4
54 | false
55 | ARM64
56 | iPhone Developer
57 | true
58 | Entitlements.plist
59 |
60 |
61 | none
62 | true
63 | bin\iPhone\Release
64 | prompt
65 | 4
66 | ARM64
67 | false
68 | iPhone Developer
69 | Entitlements.plist
70 |
71 |
72 | none
73 | True
74 | bin\iPhone\Ad-Hoc
75 | prompt
76 | 4
77 | False
78 | ARM64
79 | True
80 | Automatic:AdHoc
81 | iPhone Distribution
82 | Entitlements.plist
83 |
84 |
85 | none
86 | True
87 | bin\iPhone\AppStore
88 | prompt
89 | 4
90 | False
91 | ARM64
92 | Automatic:AppStore
93 | iPhone Distribution
94 | Entitlements.plist
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 | false
108 |
109 |
110 | false
111 |
112 |
113 | false
114 |
115 |
116 | false
117 |
118 |
119 | false
120 |
121 |
122 | false
123 |
124 |
125 | false
126 |
127 |
128 | false
129 |
130 |
131 | false
132 |
133 |
134 | false
135 |
136 |
137 | false
138 |
139 |
140 | false
141 |
142 |
143 | false
144 |
145 |
146 | false
147 |
148 |
149 |
150 |
151 | True
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 | ..\packages\Xamarin.Forms.3.4.0.1009999\lib\Xamarin.iOS10\Xamarin.Forms.Core.dll
161 |
162 |
163 | ..\packages\Xamarin.Forms.3.4.0.1009999\lib\Xamarin.iOS10\Xamarin.Forms.Platform.dll
164 |
165 |
166 | ..\packages\Xamarin.Forms.3.4.0.1009999\lib\Xamarin.iOS10\Xamarin.Forms.Platform.iOS.dll
167 |
168 |
169 | ..\packages\Xamarin.Forms.3.4.0.1009999\lib\Xamarin.iOS10\Xamarin.Forms.Xaml.dll
170 |
171 |
172 | ..\packages\Fabulous.Core.0.33.2\lib\netstandard2.0\Fabulous.Core.dll
173 |
174 |
175 | ..\packages\Fabulous.LiveUpdate.0.33.2\lib\netstandard2.0\Fabulous.LiveUpdate.dll
176 |
177 |
178 | ..\packages\Fabulous.CustomControls.0.33.2\lib\netstandard2.0\Fabulous.CustomControls.dll
179 |
180 |
181 | ..\packages\Newtonsoft.Json.11.0.2\lib\netstandard2.0\Newtonsoft.Json.dll
182 |
183 |
184 | ..\packages\Xamarin.Essentials.0.6.0-preview\lib\monoandroid71\Xamarin.Essentials.dll
185 |
186 |
187 | {2C44CD42-E4D1-48AE-805B-F30E85FB92D9}
188 | Chess.FabUI
189 |
190 |
191 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIDeviceFamily
6 |
7 | 1
8 | 2
9 |
10 | UISupportedInterfaceOrientations
11 |
12 | UIInterfaceOrientationPortrait
13 | UIInterfaceOrientationLandscapeLeft
14 | UIInterfaceOrientationLandscapeRight
15 |
16 | UISupportedInterfaceOrientations~ipad
17 |
18 | UIInterfaceOrientationPortrait
19 | UIInterfaceOrientationPortraitUpsideDown
20 | UIInterfaceOrientationLandscapeLeft
21 | UIInterfaceOrientationLandscapeRight
22 |
23 | MinimumOSVersion
24 | 8.0
25 | CFBundleDisplayName
26 | Chess.FabUI
27 | CFBundleIdentifier
28 | com.companyname
29 | CFBundleVersion
30 | 1.0
31 | UILaunchStoryboardName
32 | LaunchScreen
33 | CFBundleName
34 | Chess.FabUI
35 | XSAppIconAssets
36 | Assets.xcassets/AppIcon.appiconset
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Properties/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.FabUI.iOS
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 | []
19 |
20 | // Version information for an assembly consists of the following four values:
21 | //
22 | // Major Version
23 | // Minor Version
24 | // Build Number
25 | // Revision
26 | //
27 | // You can specify all the values or you can default the Build and Revision Numbers
28 | // by using the '*' as shown below:
29 | // []
30 | []
31 | []
32 | do()
33 |
34 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Resources/Default-568h@2x.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/Default-Portrait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Resources/Default-Portrait.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/Default-Portrait@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Resources/Default-Portrait@2x.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/Default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Resources/Default.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/Default@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.FabUI.iOS/Resources/Default@2x.png
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/Resources/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/Chess.FabUI.iOS/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Chess.FabUI/Chess.FabUI.fs:
--------------------------------------------------------------------------------
1 | namespace Chess.FabUI
2 |
3 | open System.Diagnostics
4 | open Fabulous.Core
5 | open Fabulous.DynamicViews
6 | open Xamarin.Forms
7 | open Chess.Domain
8 | open Chess.Domain.Entities
9 |
10 | module App =
11 | type Model =
12 | { GameState: Entities.GameState
13 | FromCell: Cell option }
14 |
15 | type Msg =
16 | /// User will pick a "from" cell, and then a "to" cell.
17 | | PickCell of Cell
18 |
19 | let init () =
20 | { GameState = Implementation.initGame(); FromCell = None }, Cmd.none
21 |
22 | let update msg model =
23 | match msg with
24 | | PickCell cell ->
25 | match model.FromCell with
26 | | None -> // FromCell was not previously selected
27 | match model.GameState.Board.[cell] with
28 | | Some piece -> { model with FromCell = Some cell }, Cmd.none // Selected a cell has a piece, so update FromCell
29 | | None -> model, Cmd.none // Selected cell has no piece, so ignore it
30 |
31 | | Some fromCell -> // FromCell was already selected
32 | let gameState = Implementation.move model.GameState { AttemptedMove.FromCell = fromCell; AttemptedMove.ToCell = cell }
33 | { model with GameState = gameState; FromCell = None }, Cmd.none
34 |
35 | let view (model: Model) dispatch =
36 |
37 | let getCellBgColor cell colIdx rowIdx =
38 | if Some cell = model.FromCell then Color.LightGreen
39 | elif (colIdx + rowIdx) % 2 = 0 then Xamarin.Forms.Color.White
40 | else Color.LightBlue
41 |
42 | let getCellBorderColor cell =
43 | if Some cell = model.FromCell then Color.Green
44 | else Color.Gray
45 |
46 | let indexedCells =
47 | let indexedCols = List.zip Entities.Column.List [0..7]
48 | let indexedRows = List.zip Entities.Row.List ([0..7] |> List.rev)
49 |
50 | [ for col, colIdx in indexedCols do
51 | for row, rowIdx in indexedRows do
52 | yield { Col = col; Row = row }, (colIdx, rowIdx) ]
53 |
54 | let imageForPiece pieceOpt =
55 | match pieceOpt with
56 | | Some (color, rank) ->
57 | let colorStr = match color with | White -> "white" | Black -> "black"
58 | let rankStr = match rank with | Pawn _ -> "pawn" | Rook -> "rook" | Bishop -> "bishop" | King -> "king" | Queen -> "queen" | Knight -> "knight"
59 | sprintf "Images/pieces_%s/%s.png" colorStr rankStr
60 |
61 | | None -> ""
62 |
63 | View.ContentPage(
64 | StackLayout.stackLayout [ // <-- Fabulous.SimpleElements nuget package
65 | StackLayout.Children [
66 | Grid.grid [
67 | Grid.Rows ([ for n in 1..8 -> 50. ] |> List.map GridLength)
68 | Grid.Columns ([ for n in 1..8 -> 50. ] |> List.map GridLength)
69 | Grid.ColumnSpacing 0.
70 | Grid.RowSpacing 0.
71 | Grid.Children [
72 | for (cell, (colIdx, rowIdx)) in indexedCells do
73 | let bgColor = getCellBgColor cell colIdx rowIdx
74 | let borderColor = getCellBorderColor cell
75 | let imageSource = imageForPiece model.GameState.Board.[cell]
76 | let onTap = View.TapGestureRecognizer(command=(fun () -> dispatch (PickCell cell)))
77 |
78 | yield View.Frame(
79 | backgroundColor = bgColor,
80 | borderColor = borderColor,
81 | gestureRecognizers = [onTap]
82 | ).GridColumn(colIdx).GridRow(rowIdx)
83 |
84 | yield View.Image(
85 | source = imageSource,
86 | gestureRecognizers = [onTap]
87 | ).GridColumn(colIdx).GridRow(rowIdx)
88 | ]
89 | ]
90 |
91 | Label.label [ Label.Text model.GameState.Message ]
92 | ]
93 | ]
94 | )
95 |
96 | // Note, this declaration is needed if you enable LiveUpdate
97 | let program = Program.mkProgram init update view
98 |
99 |
100 |
101 |
102 | type App () as app =
103 | inherit Application ()
104 |
105 | let runner =
106 | App.program
107 | #if DEBUG
108 | |> Program.withConsoleTrace
109 | #endif
110 | |> Program.runWithDynamicView app
111 |
112 | #if DEBUG
113 | // Uncomment this line to enable live update in debug mode.
114 | // See https://fsprojects.github.io/Fabulous/tools.html for further instructions.
115 | //
116 | do runner.EnableLiveUpdate()
117 | #endif
118 |
119 | // Uncomment this code to save the application state to app.Properties using Newtonsoft.Json
120 | // See https://fsprojects.github.io/Fabulous/models.html for further instructions.
121 | #if APPSAVE
122 | let modelId = "model"
123 | override __.OnSleep() =
124 |
125 | let json = Newtonsoft.Json.JsonConvert.SerializeObject(runner.CurrentModel)
126 | Console.WriteLine("OnSleep: saving model into app.Properties, json = {0}", json)
127 |
128 | app.Properties.[modelId] <- json
129 |
130 | override __.OnResume() =
131 | Console.WriteLine "OnResume: checking for model in app.Properties"
132 | try
133 | match app.Properties.TryGetValue modelId with
134 | | true, (:? string as json) ->
135 |
136 | Console.WriteLine("OnResume: restoring model from app.Properties, json = {0}", json)
137 | let model = Newtonsoft.Json.JsonConvert.DeserializeObject(json)
138 |
139 | Console.WriteLine("OnResume: restoring model from app.Properties, model = {0}", (sprintf "%0A" model))
140 | runner.SetCurrentModel (model, Cmd.none)
141 |
142 | | _ -> ()
143 | with ex ->
144 | App.program.onError("Error while restoring model found in app.Properties", ex)
145 |
146 | override this.OnStart() =
147 | Console.WriteLine "OnStart: using same logic as OnResume()"
148 | this.OnResume()
149 | #endif
150 |
151 |
152 |
--------------------------------------------------------------------------------
/Chess.FabUI/Chess.FabUI.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | false
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Chess.WebUI/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | insert_final_newline = true
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | indent_style = space
12 | indent_size = 4
13 |
14 | [*.styl]
15 | indent_size = 4
16 |
--------------------------------------------------------------------------------
/Chess.WebUI/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/Chess.WebUI/.gitignore:
--------------------------------------------------------------------------------
1 | public/bundle.js*
2 |
3 | # Node
4 | node_modules/
5 |
6 | ## Ignore Visual Studio temporary files, build results, and
7 | ## files generated by popular Visual Studio add-ons.
8 |
9 | # User-specific files
10 | *.suo
11 | *.user
12 | *.sln.docstates
13 |
14 | # Xamarin Studio / monodevelop user-specific
15 | *.userprefs
16 | *.dll.mdb
17 | *.exe.mdb
18 |
19 | # Build results
20 |
21 | [Dd]ebug/
22 | [Rr]elease/
23 | x64/
24 | [Bb]in/
25 | [Oo]bj/
26 |
27 | # MSTest test Results
28 | [Tt]est[Rr]esult*/
29 | [Bb]uild[Ll]og.*
30 |
31 | *_i.c
32 | *_p.c
33 | *.ilk
34 | *.meta
35 | *.obj
36 | *.pch
37 | *.pdb
38 | *.pgc
39 | *.pgd
40 | *.rsp
41 | *.sbr
42 | *.tlb
43 | *.tli
44 | *.tlh
45 | *.tmp
46 | *.tmp_proj
47 | *.log
48 | *.vspscc
49 | *.vssscc
50 | .builds
51 | *.pidb
52 | *.log
53 | *.scc
54 |
55 | # Visual C++ cache files
56 | ipch/
57 | *.aps
58 | *.ncb
59 | *.opensdf
60 | *.sdf
61 | *.cachefile
62 |
63 | # Visual Studio profiler
64 | *.psess
65 | *.vsp
66 | *.vspx
67 |
68 | # Other Visual Studio data
69 | .vs/
70 |
71 | # Guidance Automation Toolkit
72 | *.gpState
73 |
74 | # ReSharper is a .NET coding add-in
75 | _ReSharper*/
76 | *.[Rr]e[Ss]harper
77 |
78 | # TeamCity is a build add-in
79 | _TeamCity*
80 |
81 | # DotCover is a Code Coverage Tool
82 | *.dotCover
83 |
84 | # NCrunch
85 | *.ncrunch*
86 | .*crunch*.local.xml
87 |
88 | # Installshield output folder
89 | #[Ee]xpress/
90 |
91 | # DocProject is a documentation generator add-in
92 | DocProject/buildhelp/
93 | DocProject/Help/*.HxT
94 | DocProject/Help/*.HxC
95 | DocProject/Help/*.hhc
96 | DocProject/Help/*.hhk
97 | DocProject/Help/*.hhp
98 | DocProject/Help/Html2
99 | DocProject/Help/html
100 |
101 | # Click-Once directory
102 | publish/
103 |
104 | # Publish Web Output
105 | *.Publish.xml
106 |
107 | # Enable nuget.exe in the .nuget folder (though normally executables are not tracked)
108 | !.nuget/NuGet.exe
109 |
110 | # Windows Azure Build Output
111 | csx
112 | *.build.csdef
113 |
114 | # Windows Store app package directory
115 | AppPackages/
116 |
117 | # Others
118 | sql/
119 | *.Cache
120 | ClientBin/
121 | [Ss]tyle[Cc]op.*
122 | ~$*
123 | *~
124 | *.dbmdl
125 | *.[Pp]ublish.xml
126 | *.pfx
127 | *.publishsettings
128 |
129 | # RIA/Silverlight projects
130 | Generated_Code/
131 |
132 | # Backup & report files from converting an old project file to a newer
133 | # Visual Studio version. Backup files are not needed, because we have git ;-)
134 | _UpgradeReport_Files/
135 | Backup*/
136 | UpgradeLog*.XML
137 | UpgradeLog*.htm
138 |
139 | # SQL Server files
140 | App_Data/*.mdf
141 | App_Data/*.ldf
142 |
143 |
144 | #LightSwitch generated files
145 | GeneratedArtifacts/
146 | _Pvt_Extensions/
147 | ModelManifest.xml
148 |
149 | # =========================
150 | # Windows detritus
151 | # =========================
152 |
153 | # Windows image file caches
154 | Thumbs.db
155 | ehthumbs.db
156 |
157 | # Folder config file
158 | Desktop.ini
159 |
160 | # Recycle Bin used on file shares
161 | $RECYCLE.BIN/
162 |
163 | # Mac desktop service store files
164 | .DS_Store
165 |
166 | # ===================================================
167 | # Exclude F# project specific directories and files
168 | # ===================================================
169 |
170 | # NuGet Packages Directory
171 | packages/
172 |
173 | # Generated documentation folder
174 | docs/output/
175 |
176 | # Temp folder used for publishing docs
177 | temp*/
178 |
179 | # Test results produced by build
180 | TestResults.xml
181 | TestResult.xml
182 |
183 | # Nuget outputs
184 | nuget/*.nupkg
185 | release.cmd
186 | release.sh
187 | localpackages/
188 | paket-files
189 | *.orig
190 | docs/content/license.md
191 | docs/content/release-notes.md
192 | .fake
193 | docs/tools/FSharp.Formatting.svclog
194 | .ionide.debug
195 | *.bak
196 | project.lock.json
197 |
--------------------------------------------------------------------------------
/Chess.WebUI/.paket/Paket.Restore.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
8 |
9 | true
10 | $(MSBuildThisFileDirectory)
11 | $(MSBuildThisFileDirectory)..\
12 | $(PaketRootPath)paket-files\paket.restore.cached
13 | $(PaketRootPath)paket.lock
14 | /Library/Frameworks/Mono.framework/Commands/mono
15 | mono
16 |
17 | $(PaketRootPath)paket.exe
18 | $(PaketToolsPath)paket.exe
19 | "$(PaketExePath)"
20 | $(MonoPath) --runtime=v4.0.30319 "$(PaketExePath)"
21 |
22 |
23 | <_PaketExeExtension>$([System.IO.Path]::GetExtension("$(PaketExePath)"))
24 | dotnet "$(PaketExePath)"
25 |
26 |
27 | "$(PaketExePath)"
28 |
29 | $(PaketRootPath)paket.bootstrapper.exe
30 | $(PaketToolsPath)paket.bootstrapper.exe
31 | "$(PaketBootStrapperExePath)"
32 | $(MonoPath) --runtime=v4.0.30319 "$(PaketBootStrapperExePath)"
33 |
34 |
35 |
36 |
37 | true
38 | true
39 |
40 |
41 |
42 |
43 |
44 |
45 | true
46 | $(NoWarn);NU1603
47 |
48 |
49 |
50 |
51 | /usr/bin/shasum $(PaketRestoreCacheFile) | /usr/bin/awk '{ print $1 }'
52 | /usr/bin/shasum $(PaketLockFilePath) | /usr/bin/awk '{ print $1 }'
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))
66 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)'))
67 | true
68 | false
69 | true
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | $(MSBuildProjectDirectory)\obj\$(MSBuildProjectFile).paket.references.cached
79 |
80 | $(MSBuildProjectFullPath).paket.references
81 |
82 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references
83 |
84 | $(MSBuildProjectDirectory)\paket.references
85 | $(MSBuildProjectDirectory)\obj\$(MSBuildProjectFile).$(TargetFramework).paket.resolved
86 | true
87 | references-file-or-cache-not-found
88 |
89 |
90 |
91 |
92 | $([System.IO.File]::ReadAllText('$(PaketReferencesCachedFilePath)'))
93 | $([System.IO.File]::ReadAllText('$(PaketOriginalReferencesFilePath)'))
94 | references-file
95 | false
96 |
97 |
98 |
99 |
100 | false
101 |
102 |
103 |
104 |
105 | true
106 | target-framework '$(TargetFramework)'
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[0])
124 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[1])
125 | $([System.String]::Copy('%(PaketReferencesFileLines.Identity)').Split(',')[4])
126 |
127 |
128 | %(PaketReferencesFileLinesInfo.PackageVersion)
129 | All
130 |
131 |
132 |
133 |
134 | $(MSBuildProjectDirectory)/obj/$(MSBuildProjectFile).paket.clitools
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[0])
144 | $([System.String]::Copy('%(PaketCliToolFileLines.Identity)').Split(',')[1])
145 |
146 |
147 | %(PaketCliToolFileLinesInfo.PackageVersion)
148 |
149 |
150 |
151 |
155 |
156 |
157 |
158 |
159 |
160 | false
161 |
162 |
163 |
164 |
165 |
166 | <_NuspecFilesNewLocation Include="$(BaseIntermediateOutputPath)$(Configuration)\*.nuspec"/>
167 |
168 |
169 |
170 | $(MSBuildProjectDirectory)/$(MSBuildProjectFile)
171 | true
172 | false
173 | true
174 | $(BaseIntermediateOutputPath)$(Configuration)
175 | $(BaseIntermediateOutputPath)
176 |
177 |
178 |
179 | <_NuspecFiles Include="$(AdjustedNuspecOutputPath)\*.nuspec"/>
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
232 |
233 |
274 |
275 |
276 |
277 |
--------------------------------------------------------------------------------
/Chess.WebUI/.paket/paket.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WebUI/.paket/paket.exe
--------------------------------------------------------------------------------
/Chess.WebUI/.paket/paket.exe.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | True
10 |
11 |
12 |
13 |
14 |
15 |
16 | True
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Chess.WebUI/.paket/paket.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | true
7 | $(MSBuildThisFileDirectory)
8 | $(MSBuildThisFileDirectory)..\
9 | $(PaketRootPath)paket.lock
10 | $(PaketRootPath)paket-files\paket.restore.cached
11 | /Library/Frameworks/Mono.framework/Commands/mono
12 | mono
13 |
14 |
15 |
16 |
17 | $(PaketRootPath)paket.exe
18 | $(PaketToolsPath)paket.exe
19 | "$(PaketExePath)"
20 |
21 |
22 |
23 |
24 |
25 | $(MSBuildProjectFullPath).paket.references
26 |
27 |
28 |
29 |
30 | $(MSBuildProjectDirectory)\$(MSBuildProjectName).paket.references
31 |
32 |
33 |
34 |
35 | $(MSBuildProjectDirectory)\paket.references
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | $(PaketCommand) restore --references-file "$(PaketReferences)"
48 |
49 | RestorePackages; $(BuildDependsOn);
50 |
51 |
52 |
53 | true
54 |
55 |
56 |
57 | $([System.IO.File]::ReadAllText('$(PaketRestoreCacheFile)'))
58 | $([System.IO.File]::ReadAllText('$(PaketLockFilePath)'))
59 | true
60 | false
61 | true
62 |
63 |
64 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Chess.WebUI/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "dotnet",
6 | "runner": "terminal",
7 | "args": [],
8 | "options": {
9 | "cwd": "${workspaceRoot}/src"
10 | },
11 | "tasks": [
12 | {
13 | "taskName": "Start",
14 | "args": ["fable", "yarn-run", "start" ],
15 | "isBuildCommand": true,
16 | "suppressTaskName": true,
17 | "isBackground": true,
18 | "problemMatcher": {
19 | "fileLocation": "absolute",
20 | "background": {
21 | "activeOnStart": true,
22 | "beginsPattern":{
23 | "regexp": "webpack: Compiling"
24 | },
25 | "endsPattern":{
26 | "regexp": "webpack: (Compiled successfully|Failed to compile)"
27 | }
28 | },
29 | "pattern": {
30 | "regexp": "^(.*)\\((\\d+),(\\d+)\\): \\((\\d+),(\\d+)\\) (warning|error) FABLE: (.*)$",
31 | "file": 1,
32 | "line": 2,
33 | "column": 3,
34 | "endLine": 4,
35 | "endColumn": 5,
36 | "severity": 6,
37 | "message": 7
38 | }
39 | }
40 | }
41 | ]
42 | }
--------------------------------------------------------------------------------
/Chess.WebUI/Chess.WebUI.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{f2a71f9b-5d33-465a-a702-920d77279786}") = "Chess.WebUI", "src/Chess.WebUI.fsproj", "{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | EndGlobal
18 |
--------------------------------------------------------------------------------
/Chess.WebUI/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Chess.WebUI/README.md:
--------------------------------------------------------------------------------
1 | # Fable.Elmish.React Template
2 |
3 | This template can be used to generate a simple web app with [Fable](http://fable.io/) and [Elmish](https://fable-elmish.github.io/).
4 | You can find more templates by searching `Fable.Template` packages in [Nuget](https://www.nuget.org).
5 |
6 | ## Requirements
7 |
8 | * [dotnet SDK](https://www.microsoft.com/net/download/core) 2.0.0 or higher
9 | * [node.js](https://nodejs.org) 4.8.2 or higher
10 | * npm5: JS package manager
11 |
12 | Although is not a Fable requirement, on macOS and Linux you'll need [Mono](http://www.mono-project.com/) for other F# tooling like Paket or editor support.
13 |
14 | ## Editor
15 |
16 | The project can be used by editors compatible with the new .fsproj format, like VS Code + [Ionide](http://ionide.io/), Emacs with [fsharp-mode](https://github.com/fsharp/emacs-fsharp-mode) or [Rider](https://www.jetbrains.com/rider/). **Visual Studio for Mac** is also compatible but in the current version the package auto-restore function conflicts with Paket so you need to disable it: `Preferences > Nuget > General`.
17 |
18 | ## Installing the template
19 |
20 | In a terminal, run `dotnet new -i Fable.Template.Elmish.React::*` to install or update the template to latest version.
21 |
22 | > In some shells you many need quotations: `dotnet new -i "Fable.Template.Elmish.React::*"`. If you use dotnet SDK 2, you should only need to type `dotnet new -i Fable.Template.Elmish.React`.
23 |
24 | ## Creating a new project with the template
25 |
26 | In a terminal, run `dotnet fable-elmish-react` to create a project in the current directory. Type `dotnet new fable-elmish-react -n awesome` instead to create a subfolder named `awesome` and put the new project there.
27 |
28 | > The project will have the name of the directory. You may get some issues if the directory name contains some special characters like hyphens
29 |
30 | ## Building and running the app
31 |
32 | * Install JS dependencies: `npm install`
33 | * **Move to `src` folder**: `cd src`
34 | * Install F# dependencies: `dotnet restore`
35 | * Start Fable daemon and [Webpack](https://webpack.js.org/) dev server: `dotnet fable npm-start`
36 | * In your browser, open: http://localhost:8080/
37 |
38 | > `dotnet fable yarn-start` (or `npm-start`) is used to start the Fable daemon and run a script in package.json concurrently. It's a shortcut of `yarn-run [SCRIP_NAME]`, e.g. `dotnet fable yarn-run start`.
39 |
40 | If you are using VS Code + [Ionide](http://ionide.io/), you can also use the key combination: Ctrl+Shift+B (Cmd+Shift+B on macOS) instead of typing the `dotnet fable yarn-start` command. This also has the advantage that Fable-specific errors will be highlighted in the editor along with other F# errors.
41 |
42 | Any modification you do to the F# code will be reflected in the web page after saving. When you want to output the JS code to disk, run `dotnet fable yarn-build` (or `npm-build`) and you'll get a minified JS bundle in the `public` folder.
43 |
44 | ## Project structure
45 |
46 | ### Paket
47 |
48 | [Paket](https://fsprojects.github.io/Paket/) is the package manager used for F# dependencies. It doesn't need a global installation, the binary is included in the `.paket` folder. Other Paket related files are:
49 |
50 | - **paket.dependencies**: contains all the dependencies in the repository.
51 | - **paket.references**: there should be one such a file next to each `.fsproj` file.
52 | - **paket.lock**: automatically generated, but should committed to source control, [see why](https://fsprojects.github.io/Paket/faq.html#Why-should-I-commit-the-lock-file).
53 | - **Nuget.Config**: prevents conflicts with Paket in machines with some Nuget configuration.
54 |
55 | > Paket dependencies will be installed in the `packages` directory. See [Paket website](https://fsprojects.github.io/Paket/) for more info.
56 |
57 | ### npm
58 |
59 | - **package.json**: contains the JS dependencies together with other info, like development scripts.
60 | - **package-lock.json**: is the lock file created by npm5.
61 |
62 | > JS dependencies will be installed in `node_modules`. See [npm](https://www.npmjs.com/) website for more info.
63 |
64 | ### Webpack
65 |
66 | [Webpack](https://webpack.js.org) is a bundler, which links different JS sources into a single file making deployment much easier. It also offers other features, like a static dev server that can automatically refresh the browser upon changes in your code or a minifier for production release. Fable interacts with Webpack through the `fable-loader`.
67 |
68 | - **webpack.config.js**: is the configuration file for Webpack. It allows you to set many things: like the path of the bundle, the port for the development server or [Babel](https://babeljs.io/) options. See [Webpack website](https://webpack.js.org) for more info.
69 |
70 | ### F# source files
71 |
72 | The template only contains two F# source files: the project (.fsproj) and a source file (.fs) in `src` folder.
73 |
--------------------------------------------------------------------------------
/Chess.WebUI/RELEASE_NOTES.md:
--------------------------------------------------------------------------------
1 | ### 0.3.5
2 |
3 | * Update paket.exe
4 |
5 | ### 0.3.4
6 |
7 | * Fix mistakes in the README
8 | * Add VSCode tasks
9 | * Fix IE11 support
10 | * Use source-map only during development
11 | * Update dependencies
12 |
13 | ### 0.3.3
14 |
15 | * Add Fable.Elmish.HMR
16 |
17 | ### 0.3.2
18 |
19 | * Fix #30: Upgrade dependencies, use Fable.React 1.2.0
20 |
21 | ### 0.3.1
22 |
23 | * Fix dotnet version in README
24 |
25 | ### 0.3.0
26 |
27 | * Go to netstandard2.0
28 | * Updates all deps (.Net & JS)
29 |
30 | ### 0.2.6
31 |
32 | * Include user choice between npm5 and yarn
33 | * Fix viewport (eg: for mobile)
34 | * Update dependencies to latest version
35 | * Better documention in the README.md
36 | * Webpack 3
37 | * Move project file into src
38 |
39 | ### 0.2.5
40 |
41 | * Use dotnet-fable as clitool
42 | * Fix Navbar display
43 | * Fix #15: Prevent template engine to process paket files
44 | * Do not emit: //+:cnd in App.fs
45 |
46 | ### 0.2.4
47 |
48 | * Update paket to latest version
49 |
50 | ### 0.2.3
51 |
52 | * Move RELEASE_NOTES into template directory
53 | * Fix #12: Could not download FSharp.Core 4.2
54 |
55 | ### 0.2.2
56 |
57 | * Update to Fable 1.0.8
58 | * Update npm packages to latest versions
59 |
60 | ### 0.2.0
61 |
62 | * Use Paket to resolve Fable deps
63 | * Change `GroupIdentity` to prevent conflict with *Fable simple* template
64 |
65 | ### 0.1.8
66 |
67 | * Simply `toHash` function. Remove `function` in favor of `match page with`
68 | * Remove `classList` helper. It's now present in `fable-react`
69 | * Set minimun version supported in package.json
70 |
71 | ### 0.1.7
72 |
73 | * Fix `fable-core` to use `next` version
74 | * Update react/*.proj file
75 | * Fix `DEBUG` conditional statement
76 |
77 | ### 0.1.6
78 |
79 | * Set all fable-dependencies to use `next` version
80 | * Fix nuget file. (There was node_modules inside of it.)
81 | * Fix void elements usage
82 |
--------------------------------------------------------------------------------
/Chess.WebUI/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Chess.WebUI",
3 | "version": "1.0.0",
4 | "description": "Simple Fable App",
5 | "scripts": {
6 | "build": "webpack -p",
7 | "start": "webpack-dev-server",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "babel-runtime": "^6.26.0",
15 | "react": "^15.6.2",
16 | "react-dom": "^15.6.2",
17 | "remotedev": "^0.2.7"
18 | },
19 | "devDependencies": {
20 | "babel-core": "^6.26.0",
21 | "babel-loader": "^7.1.2",
22 | "babel-plugin-transform-runtime": "^6.23.0",
23 | "babel-preset-es2015": "^6.24.1",
24 | "bulma": "^0.5.2",
25 | "css-loader": "^0.28.7",
26 | "fable-loader": "^1.1.2",
27 | "fable-utils": "^1.0.6",
28 | "loglevel": "^1.5.0",
29 | "node-sass": "^7.0.0",
30 | "sass-loader": "^6.0.6",
31 | "style-loader": "^0.18.2",
32 | "webpack": "^3.6.0",
33 | "webpack-dev-server": "^2.8.2"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Chess.WebUI/paket.dependencies:
--------------------------------------------------------------------------------
1 | source https://nuget.org/api/v2
2 |
3 | storage:none
4 |
5 | nuget Fable.Elmish.HMR
6 | nuget FSharp.Core
7 | nuget Fable.Core
8 | nuget Fable.Elmish.React
9 | nuget Fable.Elmish.Browser
10 | nuget Fable.Elmish.Debugger
11 |
12 | clitool dotnet-fable
--------------------------------------------------------------------------------
/Chess.WebUI/public/img/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WebUI/public/img/favicon-16x16.png
--------------------------------------------------------------------------------
/Chess.WebUI/public/img/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WebUI/public/img/favicon-32x32.png
--------------------------------------------------------------------------------
/Chess.WebUI/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Elmish Fable App
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Chess.WebUI/sass/main.sass:
--------------------------------------------------------------------------------
1 | // Colors
2 | $purple: #7a325d
3 | $primary: $purple
4 | $black: #202020
5 |
6 | @import '../node_modules/bulma/bulma'
7 |
8 | .navbar-bg
9 | background-color: $black
10 | .nav
11 | background-color: $black
12 | .title
13 | color: #686868
14 | font-weight: 600
15 |
16 | .twitter
17 | color: #55acee !important // Override bulma
18 | border-color: #55acee
19 |
20 | .github
21 | color: $black !important // Override bulma
22 | border-color: $black
23 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/App.fs:
--------------------------------------------------------------------------------
1 | module App.View
2 |
3 | open Elmish
4 | open Elmish.Browser.Navigation
5 | open Elmish.Browser.UrlParser
6 | open Fable.Core
7 | open Fable.Core.JsInterop
8 | open Fable.Import
9 | open Fable.Import.Browser
10 | open Types
11 | open App.State
12 | open Global
13 |
14 | importAll "../sass/main.sass"
15 |
16 | open Fable.Helpers.React
17 | open Fable.Helpers.React.Props
18 |
19 | let menuItem label page currentPage =
20 | li
21 | [ ]
22 | [ a
23 | [ classList [ "is-active", page = currentPage ]
24 | Href (toHash page) ]
25 | [ str label ] ]
26 |
27 | let menu currentPage =
28 | aside
29 | [ ClassName "menu" ]
30 | [ p
31 | [ ClassName "menu-label" ]
32 | [ str "General" ]
33 | ul
34 | [ ClassName "menu-list" ]
35 | [ menuItem "Home" Home currentPage
36 | menuItem "Counter sample" Counter currentPage
37 | menuItem "About" Page.About currentPage ] ]
38 |
39 | let root model dispatch =
40 |
41 | let pageHtml =
42 | function
43 | | Page.About -> Info.View.root
44 | | Counter -> Counter.View.root model.counter (CounterMsg >> dispatch)
45 | | Home -> Home.View.root model.home (HomeMsg >> dispatch)
46 |
47 | div
48 | []
49 | [ div
50 | [ ClassName "navbar-bg" ]
51 | [ div
52 | [ ClassName "container" ]
53 | [ Navbar.View.root ] ]
54 | div
55 | [ ClassName "section" ]
56 | [ div
57 | [ ClassName "container" ]
58 | [ div
59 | [ ClassName "columns" ]
60 | [ div
61 | [ ClassName "column is-3" ]
62 | [ menu model.currentPage ]
63 | div
64 | [ ClassName "column" ]
65 | [ pageHtml model.currentPage ] ] ] ] ]
66 |
67 | open Elmish.React
68 | open Elmish.Debug
69 | open Elmish.HMR
70 |
71 | // App
72 | Program.mkProgram init update root
73 | |> Program.toNavigable (parseHash pageParser) urlUpdate
74 | #if DEBUG
75 | |> Program.withDebugger
76 | |> Program.withHMR
77 | #endif
78 | |> Program.withReact "elmish-app"
79 | |> Program.run
80 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Chess.WebUI.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netstandard2.0
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Counter/State.fs:
--------------------------------------------------------------------------------
1 | module Counter.State
2 |
3 | open Elmish
4 | open Types
5 |
6 | let init () : Model * Cmd =
7 | 0, []
8 |
9 | let update msg model =
10 | match msg with
11 | | Increment ->
12 | model + 1, []
13 | | Decrement ->
14 | model - 1, []
15 | | Reset ->
16 | 0, []
17 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Counter/Types.fs:
--------------------------------------------------------------------------------
1 | module Counter.Types
2 |
3 | type Model = int
4 |
5 | type Msg =
6 | | Increment
7 | | Decrement
8 | | Reset
9 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Counter/View.fs:
--------------------------------------------------------------------------------
1 | module Counter.View
2 |
3 | open Fable.Core
4 | open Fable.Helpers.React
5 | open Fable.Helpers.React.Props
6 | open Types
7 |
8 | let simpleButton txt action dispatch =
9 | div
10 | [ ClassName "column is-narrow" ]
11 | [ a
12 | [ ClassName "button"
13 | OnClick (fun _ -> action |> dispatch) ]
14 | [ str txt ] ]
15 |
16 | let root model dispatch =
17 | div
18 | [ ClassName "columns is-vcentered" ]
19 | [ div [ ClassName "column" ] [ ]
20 | div
21 | [ ClassName "column is-narrow"
22 | Style
23 | [ CSSProp.Width "170px" ] ]
24 | [ str (sprintf "Counter value: %i" model) ]
25 | simpleButton "+1" Increment dispatch
26 | simpleButton "-1" Decrement dispatch
27 | simpleButton "Reset" Reset dispatch
28 | div [ ClassName "column" ] [ ] ]
29 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Global.fs:
--------------------------------------------------------------------------------
1 | module Global
2 |
3 | type Page =
4 | | Home
5 | | Counter
6 | | About
7 |
8 | let toHash page =
9 | match page with
10 | | About -> "#about"
11 | | Counter -> "#counter"
12 | | Home -> "#home"
13 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Home/State.fs:
--------------------------------------------------------------------------------
1 | module Home.State
2 |
3 | open Elmish
4 | open Types
5 |
6 | let init () : Model * Cmd =
7 | "", []
8 |
9 | let update msg model : Model * Cmd =
10 | match msg with
11 | | ChangeStr str ->
12 | str, []
13 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Home/Types.fs:
--------------------------------------------------------------------------------
1 | module Home.Types
2 |
3 | type Model = string
4 |
5 | type Msg =
6 | | ChangeStr of string
7 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Home/View.fs:
--------------------------------------------------------------------------------
1 | module Home.View
2 |
3 | open Fable.Core
4 | open Fable.Core.JsInterop
5 | open Fable.Helpers.React
6 | open Fable.Helpers.React.Props
7 | open Types
8 |
9 | let root model dispatch =
10 | div
11 | [ ]
12 | [ p
13 | [ ClassName "control" ]
14 | [ input
15 | [ ClassName "input"
16 | Type "text"
17 | Placeholder "Type your name"
18 | DefaultValue model
19 | AutoFocus true
20 | OnChange (fun ev -> !!ev.target?value |> ChangeStr |> dispatch ) ] ]
21 | br [ ]
22 | span
23 | [ ]
24 | [ str (sprintf "Hello %s" model) ] ]
25 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Info/View.fs:
--------------------------------------------------------------------------------
1 | module Info.View
2 |
3 | open Fable.Helpers.React
4 | open Fable.Helpers.React.Props
5 |
6 | let root =
7 | div
8 | [ ClassName "content" ]
9 | [ h1
10 | [ ]
11 | [ str "About page" ]
12 | p
13 | [ ]
14 | [ str "This template is a simple application build with Fable + Elmish + React." ] ]
15 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Navbar/View.fs:
--------------------------------------------------------------------------------
1 | module Navbar.View
2 |
3 | open Fable.Helpers.React
4 | open Fable.Helpers.React.Props
5 |
6 | let navButton classy href faClass txt =
7 | p
8 | [ ClassName "control" ]
9 | [ a
10 | [ ClassName (sprintf "button %s" classy)
11 | Href href ]
12 | [ span
13 | [ ClassName "icon" ]
14 | [ i
15 | [ ClassName (sprintf "fa %s" faClass) ]
16 | [ ] ]
17 | span
18 | [ ]
19 | [ str txt ] ] ]
20 |
21 | let navButtons =
22 | span
23 | [ ClassName "nav-item" ]
24 | [ div
25 | [ ClassName "field is-grouped" ]
26 | [ navButton "twitter" "https://twitter.com/FableCompiler" "fa-twitter" "Twitter"
27 | navButton "github" "https://github.com/fable-compiler/fable-elmish" "fa-github" "Fork me"
28 | navButton "github" "https://gitter.im/fable-compiler/Fable" "fa-comments" "Gitter" ] ]
29 |
30 | let root =
31 | nav
32 | [ ClassName "nav" ]
33 | [ div
34 | [ ClassName "nav-left" ]
35 | [ h1
36 | [ ClassName "nav-item is-brand title is-4" ]
37 | [ str "Elmish" ] ]
38 | div
39 | [ ClassName "nav-right" ]
40 | [ navButtons ] ]
41 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/State.fs:
--------------------------------------------------------------------------------
1 | module App.State
2 |
3 | open Elmish
4 | open Elmish.Browser.Navigation
5 | open Elmish.Browser.UrlParser
6 | open Fable.Import.Browser
7 | open Global
8 | open Types
9 |
10 | let pageParser: ParserPage,Page> =
11 | oneOf [
12 | map About (s "about")
13 | map Counter (s "counter")
14 | map Home (s "home")
15 | ]
16 |
17 | let urlUpdate (result: Option) model =
18 | match result with
19 | | None ->
20 | console.error("Error parsing url")
21 | model,Navigation.modifyUrl (toHash model.currentPage)
22 | | Some page ->
23 | { model with currentPage = page }, []
24 |
25 | let init result =
26 | let (counter, counterCmd) = Counter.State.init()
27 | let (home, homeCmd) = Home.State.init()
28 | let (model, cmd) =
29 | urlUpdate result
30 | { currentPage = Home
31 | counter = counter
32 | home = home }
33 | model, Cmd.batch [ cmd
34 | Cmd.map CounterMsg counterCmd
35 | Cmd.map HomeMsg homeCmd ]
36 |
37 | let update msg model =
38 | match msg with
39 | | CounterMsg msg ->
40 | let (counter, counterCmd) = Counter.State.update msg model.counter
41 | { model with counter = counter }, Cmd.map CounterMsg counterCmd
42 | | HomeMsg msg ->
43 | let (home, homeCmd) = Home.State.update msg model.home
44 | { model with home = home }, Cmd.map HomeMsg homeCmd
45 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/Types.fs:
--------------------------------------------------------------------------------
1 | module App.Types
2 |
3 | open Global
4 |
5 | type Msg =
6 | | CounterMsg of Counter.Types.Msg
7 | | HomeMsg of Home.Types.Msg
8 |
9 | type Model = {
10 | currentPage: Page
11 | counter: Counter.Types.Model
12 | home: Home.Types.Model
13 | }
14 |
--------------------------------------------------------------------------------
/Chess.WebUI/src/paket.references:
--------------------------------------------------------------------------------
1 | FSharp.Core
2 | Fable.Core
3 | Fable.Elmish.React
4 | Fable.Elmish.Browser
5 | Fable.Elmish.Debugger
6 | Fable.Elmish.HMR
7 | dotnet-fable
8 |
--------------------------------------------------------------------------------
/Chess.WebUI/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require("path");
2 | var webpack = require("webpack");
3 | var fableUtils = require("fable-utils");
4 |
5 | function resolve(filePath) {
6 | return path.join(__dirname, filePath)
7 | }
8 |
9 | var babelOptions = fableUtils.resolveBabelOptions({
10 | presets: [["es2015", { "modules": false }]],
11 | plugins: [["transform-runtime", {
12 | "helpers": true,
13 | // We don't need the polyfills as we're already calling
14 | // cdn.polyfill.io/v2/polyfill.js in index.html
15 | "polyfill": false,
16 | "regenerator": false
17 | }]]
18 | });
19 |
20 | var isProduction = process.argv.indexOf("-p") >= 0;
21 | console.log("Bundling for " + (isProduction ? "production" : "development") + "...");
22 |
23 | module.exports = {
24 | devtool: isProduction ? undefined : "source-map",
25 | entry: resolve('./src/Chess.WebUI.fsproj'),
26 | output: {
27 | filename: 'bundle.js',
28 | path: resolve('./public'),
29 | },
30 | resolve: {
31 | modules: [
32 | "node_modules", resolve("./node_modules/")
33 | ]
34 | },
35 | devServer: {
36 | contentBase: resolve('./public'),
37 | port: 8080,
38 | hot: true,
39 | inline: true
40 | },
41 | module: {
42 | rules: [
43 | {
44 | test: /\.fs(x|proj)?$/,
45 | use: {
46 | loader: "fable-loader",
47 | options: {
48 | babel: babelOptions,
49 | define: isProduction ? [] : ["DEBUG"]
50 | }
51 | }
52 | },
53 | {
54 | test: /\.js$/,
55 | exclude: /node_modules/,
56 | use: {
57 | loader: 'babel-loader',
58 | options: babelOptions
59 | },
60 | },
61 | {
62 | test: /\.sass$/,
63 | use: [
64 | "style-loader",
65 | "css-loader",
66 | "sass-loader"
67 | ]
68 | }
69 | ]
70 | },
71 | plugins: isProduction ? [] : [
72 | new webpack.HotModuleReplacementPlugin(),
73 | new webpack.NamedModulesPlugin()
74 | ]
75 | };
76 |
--------------------------------------------------------------------------------
/Chess.WpfUI/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Chess.WpfUI/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Chess.WpfUI/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace Chess.WpfUI
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Chess.WpfUI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}
8 | WinExe
9 | Properties
10 | Chess.WpfUI
11 | Chess.WpfUI
12 | v4.7.1
13 | 512
14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
15 | 4
16 | true
17 |
18 |
19 |
20 | AnyCPU
21 | true
22 | full
23 | false
24 | bin\Debug\
25 | DEBUG;TRACE
26 | prompt
27 | 4
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 | TRACE
35 | prompt
36 | 4
37 |
38 |
39 |
40 | ..\packages\FSharp.Core.4.6.2\lib\net45\FSharp.Core.dll
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 4.0
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | MSBuild:Compile
60 | Designer
61 |
62 |
63 | MSBuild:Compile
64 | Designer
65 |
66 |
67 | App.xaml
68 | Code
69 |
70 |
71 | MainWindow.xaml
72 | Code
73 |
74 |
75 |
76 |
77 | Code
78 |
79 |
80 | True
81 | True
82 | Resources.resx
83 |
84 |
85 | True
86 | Settings.settings
87 | True
88 |
89 |
90 | ResXFileCodeGenerator
91 | Resources.Designer.cs
92 |
93 |
94 |
95 | SettingsSingleFileGenerator
96 | Settings.Designer.cs
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | {e2f18796-6da8-45e4-a1a3-0db4f80e2624}
106 | Chess.Domain
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
131 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/bishop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/bishop.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/king.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/king.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/knight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/knight.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/pawn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/pawn.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/queen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/queen.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_black/rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_black/rook.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/bishop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/bishop.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/king.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/king.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/knight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/knight.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/pawn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/pawn.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/queen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/queen.png
--------------------------------------------------------------------------------
/Chess.WpfUI/Images/pieces_white/rook.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JordanMarr/FsharpChess/d26c814cd810a3ae812c911981ee9bd46da7fe95/Chess.WpfUI/Images/pieces_white/rook.png
--------------------------------------------------------------------------------
/Chess.WpfUI/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
37 |
38 |
39 |
42 |
43 |
44 |
47 |
48 |
49 |
52 |
53 |
54 |
57 |
58 |
59 |
62 |
63 |
64 |
67 |
68 |
69 |
72 |
73 |
74 |
75 |
78 |
79 |
80 |
83 |
84 |
85 |
88 |
89 |
90 |
93 |
94 |
95 |
98 |
99 |
100 |
103 |
104 |
105 |
108 |
109 |
110 |
113 |
114 |
115 |
116 |
119 |
120 |
121 |
124 |
125 |
126 |
129 |
130 |
131 |
134 |
135 |
136 |
139 |
140 |
141 |
144 |
145 |
146 |
149 |
150 |
151 |
154 |
155 |
156 |
157 |
160 |
161 |
162 |
165 |
166 |
167 |
170 |
171 |
172 |
175 |
176 |
177 |
180 |
181 |
182 |
185 |
186 |
187 |
190 |
191 |
192 |
195 |
196 |
197 |
198 |
201 |
202 |
203 |
206 |
207 |
208 |
211 |
212 |
213 |
216 |
217 |
218 |
221 |
222 |
223 |
226 |
227 |
228 |
231 |
232 |
233 |
236 |
237 |
238 |
239 |
242 |
243 |
244 |
247 |
248 |
249 |
252 |
253 |
254 |
257 |
258 |
259 |
262 |
263 |
264 |
267 |
268 |
269 |
272 |
273 |
274 |
277 |
278 |
279 |
280 |
283 |
284 |
285 |
288 |
289 |
290 |
293 |
294 |
295 |
298 |
299 |
300 |
303 |
304 |
305 |
308 |
309 |
310 |
313 |
314 |
315 |
318 |
319 |
320 |
321 |
324 |
325 |
326 |
329 |
330 |
331 |
334 |
335 |
336 |
339 |
340 |
341 |
344 |
345 |
346 |
349 |
350 |
351 |
354 |
355 |
356 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
--------------------------------------------------------------------------------
/Chess.WpfUI/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 | using Chess.Domain;
16 |
17 | namespace Chess.WpfUI
18 | {
19 | ///
20 | /// Interaction logic for MainWindow.xaml
21 | ///
22 | public partial class MainWindow : Window
23 | {
24 | Api.ChessApi _api;
25 | List _moveQueue;
26 |
27 |
28 | public MainWindow()
29 | {
30 | InitializeComponent();
31 |
32 | _api = new Api.ChessApi();
33 | _moveQueue = new List();
34 | }
35 |
36 | private void Window_Loaded(object sender, RoutedEventArgs e)
37 | {
38 | RefreshBoard();
39 | }
40 |
41 | private void RefreshBoard()
42 | {
43 | foreach (var cell in _api.Cells)
44 | {
45 | var border = (Border)FindName(cell.Coord);
46 | var button = border.Child as Button;
47 | var img = button.Content as Image;
48 | if (cell.IsOccupied)
49 | {
50 | var path = $"/Images/pieces_{cell.Color}/{cell.Rank}.png";
51 | var bm = new BitmapImage(new Uri(path, UriKind.Relative));
52 | img.Source = bm;
53 | }
54 | else
55 | {
56 | img.Source = null;
57 | }
58 | }
59 |
60 | StatusMessage.Text = _api.Message;
61 | }
62 |
63 | private void Cell_Click(object sender, RoutedEventArgs e)
64 | {
65 | var btn = sender as Button;
66 | var border = btn.Parent as Border;
67 |
68 | if (_moveQueue.FirstOrDefault()?.Coord == border.Name)
69 | {
70 | _moveQueue.ForEach(q => q.RevertColor());
71 | _moveQueue.Clear();
72 | return; // Can't click a cell twice
73 | }
74 |
75 | _moveQueue.Add(new QueuedCell(border));
76 |
77 | if (_moveQueue.Count > 1)
78 | {
79 | _api.Move(_moveQueue[0].Coord, _moveQueue[1].Coord);
80 | _moveQueue.ForEach(q => q.RevertColor());
81 | _moveQueue.Clear();
82 | RefreshBoard();
83 | }
84 | }
85 |
86 |
87 | private class QueuedCell
88 | {
89 | public QueuedCell(Border border)
90 | {
91 | Border = border;
92 | Coord = border.Name;
93 | OrigColor = (border.Background as SolidColorBrush).Color;
94 |
95 | // Highlight cell
96 | border.Background = new SolidColorBrush(Colors.LightPink);
97 | }
98 |
99 | public Border Border { get; private set; }
100 | public string Coord { get; private set; }
101 | public Color OrigColor { get; private set; }
102 |
103 | public void RevertColor()
104 | {
105 | Border.Background = new SolidColorBrush(OrigColor);
106 | }
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTitle("Chess.WpfUI")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("Chess.WpfUI")]
15 | [assembly: AssemblyCopyright("Copyright © 2017")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Chess.WpfUI.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Chess.WpfUI.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Chess.WpfUI.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Chess.WpfUI/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Chess.WpfUI/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Chess.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.28729.10
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Chess.Domain", "Chess.Domain\Chess.Domain.fsproj", "{E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Chess.WpfUI", "Chess.WpfUI\Chess.WpfUI.csproj", "{039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UI", "UI", "{C352872B-5D72-4081-A29A-A8C86F5AB683}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Chess.ConsoleUI", "Chess.ConsoleUI\Chess.ConsoleUI.csproj", "{227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Fabulous UI", "Fabulous UI", "{4DA72EBA-3BF8-416E-AA80-B2FF49619085}"
15 | EndProject
16 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Chess.FabUI", "Chess.FabUI\Chess.FabUI.fsproj", "{28527D6A-4CB7-4AE7-9E98-561833460E6B}"
17 | EndProject
18 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Chess.FabUI.WPF", "Chess.FabUI.WPF\Chess.FabUI.WPF.fsproj", "{3A91CBBE-E5B4-43F8-9D1D-8E6147675246}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Ad-Hoc|Any CPU = Ad-Hoc|Any CPU
23 | Ad-Hoc|iPhone = Ad-Hoc|iPhone
24 | Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator
25 | AppStore|Any CPU = AppStore|Any CPU
26 | AppStore|iPhone = AppStore|iPhone
27 | AppStore|iPhoneSimulator = AppStore|iPhoneSimulator
28 | Debug|Any CPU = Debug|Any CPU
29 | Debug|iPhone = Debug|iPhone
30 | Debug|iPhoneSimulator = Debug|iPhoneSimulator
31 | Release|Any CPU = Release|Any CPU
32 | Release|iPhone = Release|iPhone
33 | Release|iPhoneSimulator = Release|iPhoneSimulator
34 | EndGlobalSection
35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
36 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
37 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
38 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
39 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
40 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
41 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
42 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
43 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|Any CPU.Build.0 = Release|Any CPU
44 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|iPhone.ActiveCfg = Release|Any CPU
45 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|iPhone.Build.0 = Release|Any CPU
46 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
47 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
48 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
49 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|Any CPU.Build.0 = Debug|Any CPU
50 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|iPhone.ActiveCfg = Debug|Any CPU
51 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|iPhone.Build.0 = Debug|Any CPU
52 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
53 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
54 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|Any CPU.ActiveCfg = Release|Any CPU
55 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|Any CPU.Build.0 = Release|Any CPU
56 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|iPhone.ActiveCfg = Release|Any CPU
57 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|iPhone.Build.0 = Release|Any CPU
58 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
59 | {E2F18796-6DA8-45E4-A1A3-0DB4F80E2624}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
60 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
61 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
62 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
63 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
64 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
65 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
66 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
67 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|Any CPU.Build.0 = Release|Any CPU
68 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|iPhone.ActiveCfg = Release|Any CPU
69 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|iPhone.Build.0 = Release|Any CPU
70 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
71 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
72 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
73 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
74 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
75 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|iPhone.Build.0 = Debug|Any CPU
76 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
77 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
78 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
79 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|Any CPU.Build.0 = Release|Any CPU
80 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|iPhone.ActiveCfg = Release|Any CPU
81 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|iPhone.Build.0 = Release|Any CPU
82 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
83 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
84 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
85 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
86 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
87 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
88 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
89 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
90 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
91 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|Any CPU.Build.0 = Release|Any CPU
92 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|iPhone.ActiveCfg = Release|Any CPU
93 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|iPhone.Build.0 = Release|Any CPU
94 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
95 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
96 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
97 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
98 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|iPhone.ActiveCfg = Debug|Any CPU
99 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|iPhone.Build.0 = Debug|Any CPU
100 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
101 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
102 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
103 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|Any CPU.Build.0 = Release|Any CPU
104 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|iPhone.ActiveCfg = Release|Any CPU
105 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|iPhone.Build.0 = Release|Any CPU
106 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
107 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
108 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
109 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
110 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
111 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
112 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
113 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
114 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
115 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|Any CPU.Build.0 = Debug|Any CPU
116 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
117 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|iPhone.Build.0 = Debug|Any CPU
118 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
119 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
120 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
121 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
122 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|iPhone.ActiveCfg = Debug|Any CPU
123 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|iPhone.Build.0 = Debug|Any CPU
124 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
125 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
126 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
127 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|Any CPU.Build.0 = Release|Any CPU
128 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|iPhone.ActiveCfg = Release|Any CPU
129 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|iPhone.Build.0 = Release|Any CPU
130 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
131 | {28527D6A-4CB7-4AE7-9E98-561833460E6B}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
132 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
133 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
134 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
135 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
136 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
137 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
138 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
139 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|Any CPU.Build.0 = Debug|Any CPU
140 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
141 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|iPhone.Build.0 = Debug|Any CPU
142 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
143 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
144 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
145 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|Any CPU.Build.0 = Debug|Any CPU
146 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|iPhone.ActiveCfg = Debug|Any CPU
147 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|iPhone.Build.0 = Debug|Any CPU
148 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
149 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
150 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|Any CPU.ActiveCfg = Release|Any CPU
151 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|Any CPU.Build.0 = Release|Any CPU
152 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|iPhone.ActiveCfg = Release|Any CPU
153 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|iPhone.Build.0 = Release|Any CPU
154 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
155 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
156 | EndGlobalSection
157 | GlobalSection(SolutionProperties) = preSolution
158 | HideSolutionNode = FALSE
159 | EndGlobalSection
160 | GlobalSection(NestedProjects) = preSolution
161 | {039D0DC3-6D17-4409-8FC8-0BB427AD7DB7} = {C352872B-5D72-4081-A29A-A8C86F5AB683}
162 | {227BA2EA-261C-4EAC-B9FE-F6E16A1AD5E1} = {C352872B-5D72-4081-A29A-A8C86F5AB683}
163 | {28527D6A-4CB7-4AE7-9E98-561833460E6B} = {4DA72EBA-3BF8-416E-AA80-B2FF49619085}
164 | {3A91CBBE-E5B4-43F8-9D1D-8E6147675246} = {4DA72EBA-3BF8-416E-AA80-B2FF49619085}
165 | EndGlobalSection
166 | GlobalSection(ExtensibilityGlobals) = postSolution
167 | SolutionGuid = {69C12E65-33D6-402A-90D6-D37AB418B7C0}
168 | EndGlobalSection
169 | EndGlobal
170 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FsharpChess
2 | Chess with an F# domain engine and a simple WPF UI.
3 |
4 | I created this project as part of my ongoing effort to understand F#. I am a full time C# developer, so I am currently trying to rethink my imperative approach to designing software of doing everything with mutable state.
5 |
6 | I would really love it if anyone has any ideas on how to make this better, more "functional", or anything, really.
7 |
8 | # F# Domain
9 |
10 | ## Chess.fs
11 | This contains the domain entities (nouns), use cases (actions or methods), and the implementation methods (moving, validation, etc).
12 |
13 | ## Api.fs
14 | This provides a "ChessApi" class that allows the C# code to interface with the F# backend. The ChessApi class contains a mutable copy of the game state (the board, which is just a dictionary/map of cells and optional pieces, whose turn it is, etc). This is currently the only mutable state in the F# library. The idea is that I didn't want to make the C# calling code responsible for receiving the state and passing in back in for each move, as that seems like a very functional way of doing things. Instead, I wanted to "encapsulate" mutable state management within the F# ChessApi class.
15 |
16 | # C# WPF UI
17 | The WPF UI is a very simple code-behind design (no MVVM here), because my purpose was to focus on the F# bits.
18 | It creates an instance of the F# ChessApi class and it refreshes the UI after each move based on the newly generated game state.
19 |
20 | # TODO
21 | - [x] Implement "interposition" (or "blocking") - all pieces that capture linearly (all except the knight) should not be able to skip past enemy pieces. They should only be allowed the capture the first piece in their movement path.
22 | - [ ] Implement GameProgress to handle "check" and "checkmate" (game over + victor) and "stalement" status
23 | - [ ] Create checkmate detection - engine needs to be able to detect when a move results in the other color's king having no valid escape moves
24 | - [ ] Implement "legal" move detection - a player cannot move their own king into danger
25 | - [ ] Implement stalemate detection - when a player is not in check, but has no legal moves
26 | - [ ] If a player's king is in check, their next move MUST remove them from check state
27 |
--------------------------------------------------------------------------------
|