2
0
Эх сурвалжийг харах

CardGame Starter Kit - initial port. Only tested on macOS.

Dominique Louis 1 сар өмнө
parent
commit
b95cad9801
100 өөрчлөгдсөн 3599 нэмэгдсэн , 0 устгасан
  1. 36 0
      CardsStarterKit/.config/dotnet-tools.json
  2. 49 0
      CardsStarterKit/.vscode/launch.json
  3. 81 0
      CardsStarterKit/.vscode/tasks.json
  4. 56 0
      CardsStarterKit/CardsStarterKit.sln
  5. 460 0
      CardsStarterKit/Core/Content/Content.mgcb
  6. 60 0
      CardsStarterKit/Core/Content/Fonts/Bold.spritefont
  7. 60 0
      CardsStarterKit/Core/Content/Fonts/MenuFont.spritefont
  8. 60 0
      CardsStarterKit/Core/Content/Fonts/Regular.spritefont
  9. BIN
      CardsStarterKit/Core/Content/Images/Button.png
  10. BIN
      CardsStarterKit/Core/Content/Images/ButtonPressed.png
  11. BIN
      CardsStarterKit/Core/Content/Images/ButtonRegular.png
  12. BIN
      CardsStarterKit/Core/Content/Images/Cards/CardBack_Blue.png
  13. BIN
      CardsStarterKit/Core/Content/Images/Cards/CardBack_Red.png
  14. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubAce.png
  15. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubEight.png
  16. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubFive.png
  17. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubFour.png
  18. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubJack.png
  19. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubKing.png
  20. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubNine.png
  21. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubQueen.png
  22. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubSeven.png
  23. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubSix.png
  24. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubTen.png
  25. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubThree.png
  26. BIN
      CardsStarterKit/Core/Content/Images/Cards/ClubTwo.png
  27. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondAce.png
  28. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondEight.png
  29. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondFive.png
  30. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondFour.png
  31. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondJack.png
  32. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondKing.png
  33. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondNine.png
  34. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondQueen.png
  35. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondSeven.png
  36. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondSix.png
  37. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondTen.png
  38. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondThree.png
  39. BIN
      CardsStarterKit/Core/Content/Images/Cards/DiamondTwo.png
  40. BIN
      CardsStarterKit/Core/Content/Images/Cards/FirstJoker.png
  41. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartAce.png
  42. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartEight.png
  43. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartFive.png
  44. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartFour.png
  45. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartJack.png
  46. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartKing.png
  47. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartNine.png
  48. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartQueen.png
  49. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartSeven.png
  50. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartSix.png
  51. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartTen.png
  52. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartThree.png
  53. BIN
      CardsStarterKit/Core/Content/Images/Cards/HeartTwo.png
  54. BIN
      CardsStarterKit/Core/Content/Images/Cards/SecondJoker.png
  55. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeAce.png
  56. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeEight.png
  57. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeFive.png
  58. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeFour.png
  59. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeJack.png
  60. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeKing.png
  61. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeNine.png
  62. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeQueen.png
  63. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeSeven.png
  64. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeSix.png
  65. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeTen.png
  66. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeThree.png
  67. BIN
      CardsStarterKit/Core/Content/Images/Cards/SpadeTwo.png
  68. BIN
      CardsStarterKit/Core/Content/Images/Chips/chip100.png
  69. BIN
      CardsStarterKit/Core/Content/Images/Chips/chip25.png
  70. BIN
      CardsStarterKit/Core/Content/Images/Chips/chip5.png
  71. BIN
      CardsStarterKit/Core/Content/Images/Chips/chip500.png
  72. BIN
      CardsStarterKit/Core/Content/Images/Chips/chipBlack.png
  73. BIN
      CardsStarterKit/Core/Content/Images/Chips/chipRed.png
  74. BIN
      CardsStarterKit/Core/Content/Images/Chips/chipWhite.png
  75. BIN
      CardsStarterKit/Core/Content/Images/Chips/chipYellow.png
  76. BIN
      CardsStarterKit/Core/Content/Images/GamePadCursor.png
  77. BIN
      CardsStarterKit/Core/Content/Images/UI/Shuffle_Blue.png
  78. BIN
      CardsStarterKit/Core/Content/Images/UI/Shuffle_Red.png
  79. BIN
      CardsStarterKit/Core/Content/Images/UI/blackjack.png
  80. BIN
      CardsStarterKit/Core/Content/Images/UI/bust.png
  81. BIN
      CardsStarterKit/Core/Content/Images/UI/lose.png
  82. BIN
      CardsStarterKit/Core/Content/Images/UI/pass.png
  83. BIN
      CardsStarterKit/Core/Content/Images/UI/push.png
  84. BIN
      CardsStarterKit/Core/Content/Images/UI/ring.png
  85. BIN
      CardsStarterKit/Core/Content/Images/UI/table.png
  86. BIN
      CardsStarterKit/Core/Content/Images/UI/win.png
  87. BIN
      CardsStarterKit/Core/Content/Images/blank.png
  88. BIN
      CardsStarterKit/Core/Content/Images/instructions.png
  89. BIN
      CardsStarterKit/Core/Content/Images/titlescreen.png
  90. BIN
      CardsStarterKit/Core/Content/Images/youLose.png
  91. BIN
      CardsStarterKit/Core/Content/Sounds/Bet.wav
  92. BIN
      CardsStarterKit/Core/Content/Sounds/CardFlip.wav
  93. BIN
      CardsStarterKit/Core/Content/Sounds/CardsShuffle.wav
  94. BIN
      CardsStarterKit/Core/Content/Sounds/Deal.wav
  95. BIN
      CardsStarterKit/Core/Game/Background.png
  96. 22 0
      CardsStarterKit/Core/Game/Blackjack.Core.csproj
  97. 1644 0
      CardsStarterKit/Core/Game/Blackjack/Game/BlackjackCardGame.cs
  98. 754 0
      CardsStarterKit/Core/Game/Blackjack/Misc/BetGameComponent.cs
  99. 70 0
      CardsStarterKit/Core/Game/Blackjack/Players/BlackjackAIPlayer.cs
  100. 247 0
      CardsStarterKit/Core/Game/Blackjack/Players/BlackjackPlayer.cs

+ 36 - 0
CardsStarterKit/.config/dotnet-tools.json

@@ -0,0 +1,36 @@
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {
+    "dotnet-mgcb": {
+      "version": "3.8.4",
+      "commands": [
+        "mgcb"
+      ]
+    },
+    "dotnet-mgcb-editor": {
+      "version": "3.8.4",
+      "commands": [
+        "mgcb-editor"
+      ]
+    },
+    "dotnet-mgcb-editor-linux": {
+      "version": "3.8.4",
+      "commands": [
+        "mgcb-editor-linux"
+      ]
+    },
+    "dotnet-mgcb-editor-windows": {
+      "version": "3.8.4",
+      "commands": [
+        "mgcb-editor-windows"
+      ]
+    },
+    "dotnet-mgcb-editor-mac": {
+      "version": "3.8.4",
+      "commands": [
+        "mgcb-editor-mac"
+      ]
+    }
+  }
+}

+ 49 - 0
CardsStarterKit/.vscode/launch.json

@@ -0,0 +1,49 @@
+{
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "name": "Launch DesktopGL",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-desktop",
+            "program": "${workspaceFolder}/Platforms/Desktop/bin/Debug/net8.0/Blackjack.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Desktop",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        },
+        {
+            "name": "Launch Windows",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-windows",
+            "program": "${workspaceFolder}/Platforms/Windows/bin/Debug/net8.0/Blackjack.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Windows",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        },
+        {
+            "name": "Launch Android",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-android",
+            "program": "${workspaceFolder}/Platforms/Android/bin/Debug/net8.0/Blackjack.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/Android",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        },
+        {
+            "name": "Launch iOS",
+            "type": "coreclr",
+            "request": "launch",
+            "preLaunchTask": "build-ios",
+            "program": "${workspaceFolder}/Platforms/iOS/bin/Debug/net8.0/Blackjack.dll",
+            "args": [],
+            "cwd": "${workspaceFolder}/Platforms/iOS",
+            "console": "internalConsole",
+            "stopAtEntry": false
+        }
+    ]
+}

+ 81 - 0
CardsStarterKit/.vscode/tasks.json

@@ -0,0 +1,81 @@
+{
+    "version": "2.0.0",
+    "tasks": [
+        {
+            "label": "build-desktop",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Desktop/BlackJack.DesktopGL.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "echo": true,
+                "reveal": "always",
+                "focus": false,
+                "panel": "shared",
+                "showReuseMessage": true,
+                "clear": false
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-windows",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Windows/BlackJack.Windows.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "echo": true,
+                "reveal": "always",
+                "focus": false,
+                "panel": "shared",
+                "showReuseMessage": true,
+                "clear": false
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-android",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/Android/BlackJack.Android.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "echo": true,
+                "reveal": "always",
+                "focus": false,
+                "panel": "shared",
+                "showReuseMessage": true,
+                "clear": false
+            },
+            "problemMatcher": "$msCompile"
+        },
+        {
+            "label": "build-ios",
+            "type": "shell",
+            "command": "dotnet",
+            "args": [
+                "build",
+                "${workspaceFolder}/Platforms/iOS/BlackJack.iOS.csproj"
+            ],
+            "group": "build",
+            "presentation": {
+                "echo": true,
+                "reveal": "always",
+                "focus": false,
+                "panel": "shared",
+                "showReuseMessage": true,
+                "clear": false
+            },
+            "problemMatcher": "$msCompile"
+        }
+    ]
+}

+ 56 - 0
CardsStarterKit/CardsStarterKit.sln

@@ -0,0 +1,56 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cards.Framework", "Framework\Cards.Framework.csproj", "{89781445-5440-49D1-AB1B-67C6667D43DC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blackjack.Core", "Core\Game\Blackjack.Core.csproj", "{80C61169-FFE2-4335-BCE6-F0A4722FA419}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlackJack.Windows", "Platforms\Windows\BlackJack.Windows.csproj", "{92B782FF-2679-431D-B095-9BB86D09ED59}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlackJack.iOS", "Platforms\iOS\BlackJack.iOS.csproj", "{02C6C7B5-5F17-4E12-9278-A9AC14358525}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlackJack.DesktopGL", "Platforms\Desktop\BlackJack.DesktopGL.csproj", "{E23472DC-9347-4327-9292-732B80959226}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlackJack.Android", "Platforms\Android\BlackJack.Android.csproj", "{B767C86E-EAB0-4ACF-B2DE-687828BB949B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{89781445-5440-49D1-AB1B-67C6667D43DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{89781445-5440-49D1-AB1B-67C6667D43DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{89781445-5440-49D1-AB1B-67C6667D43DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{89781445-5440-49D1-AB1B-67C6667D43DC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{80C61169-FFE2-4335-BCE6-F0A4722FA419}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{80C61169-FFE2-4335-BCE6-F0A4722FA419}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{80C61169-FFE2-4335-BCE6-F0A4722FA419}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{80C61169-FFE2-4335-BCE6-F0A4722FA419}.Release|Any CPU.Build.0 = Release|Any CPU
+		{92B782FF-2679-431D-B095-9BB86D09ED59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{92B782FF-2679-431D-B095-9BB86D09ED59}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{92B782FF-2679-431D-B095-9BB86D09ED59}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{92B782FF-2679-431D-B095-9BB86D09ED59}.Release|Any CPU.Build.0 = Release|Any CPU
+		{02C6C7B5-5F17-4E12-9278-A9AC14358525}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{02C6C7B5-5F17-4E12-9278-A9AC14358525}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{02C6C7B5-5F17-4E12-9278-A9AC14358525}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{02C6C7B5-5F17-4E12-9278-A9AC14358525}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E23472DC-9347-4327-9292-732B80959226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E23472DC-9347-4327-9292-732B80959226}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E23472DC-9347-4327-9292-732B80959226}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E23472DC-9347-4327-9292-732B80959226}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B767C86E-EAB0-4ACF-B2DE-687828BB949B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B767C86E-EAB0-4ACF-B2DE-687828BB949B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B767C86E-EAB0-4ACF-B2DE-687828BB949B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B767C86E-EAB0-4ACF-B2DE-687828BB949B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {4FA51D01-9782-46F8-AD43-7AD6134607E6}
+	EndGlobalSection
+EndGlobal

+ 460 - 0
CardsStarterKit/Core/Content/Content.mgcb

@@ -0,0 +1,460 @@
+
+#----------------------------- Global Properties ----------------------------#
+
+/outputDir:bin/$(Platform)
+/intermediateDir:obj/$(Platform)
+/platform:DesktopGL
+/config:$(Configuration)
+/profile:HiDef
+/compress:False
+
+#-------------------------------- References --------------------------------#
+
+
+
+#---------------------------------- Content ---------------------------------#
+
+#begin Fonts/Bold.spritefont
+/importer:FontDescriptionImporter
+/processor:FontDescriptionProcessor
+/build:Fonts/Bold.spritefont
+
+#begin Fonts/MenuFont.spritefont
+/importer:FontDescriptionImporter
+/processor:FontDescriptionProcessor
+/build:Fonts/MenuFont.spritefont
+
+#begin Fonts/Regular.spritefont
+/importer:FontDescriptionImporter
+/processor:FontDescriptionProcessor
+/build:Fonts/Regular.spritefont
+
+#begin Images/blank.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/blank.png
+
+#begin Images/Button.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Button.png
+
+#begin Images/ButtonPressed.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/ButtonPressed.png
+
+#begin Images/ButtonRegular.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/ButtonRegular.png
+
+#begin Images/Cards/CardBack_Blue.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/CardBack_Blue.png
+
+#begin Images/Cards/CardBack_Red.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/CardBack_Red.png
+
+#begin Images/Cards/ClubAce.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubAce.png
+
+#begin Images/Cards/ClubEight.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubEight.png
+
+#begin Images/Cards/ClubFive.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubFive.png
+
+#begin Images/Cards/ClubFour.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubFour.png
+
+#begin Images/Cards/ClubJack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubJack.png
+
+#begin Images/Cards/ClubKing.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubKing.png
+
+#begin Images/Cards/ClubNine.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubNine.png
+
+#begin Images/Cards/ClubQueen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubQueen.png
+
+#begin Images/Cards/ClubSeven.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubSeven.png
+
+#begin Images/Cards/ClubSix.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubSix.png
+
+#begin Images/Cards/ClubTen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubTen.png
+
+#begin Images/Cards/ClubThree.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubThree.png
+
+#begin Images/Cards/ClubTwo.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/ClubTwo.png
+
+#begin Images/Cards/DiamondAce.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondAce.png
+
+#begin Images/Cards/DiamondEight.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondEight.png
+
+#begin Images/Cards/DiamondFive.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondFive.png
+
+#begin Images/Cards/DiamondFour.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondFour.png
+
+#begin Images/Cards/DiamondJack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondJack.png
+
+#begin Images/Cards/DiamondKing.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondKing.png
+
+#begin Images/Cards/DiamondNine.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondNine.png
+
+#begin Images/Cards/DiamondQueen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondQueen.png
+
+#begin Images/Cards/DiamondSeven.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondSeven.png
+
+#begin Images/Cards/DiamondSix.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondSix.png
+
+#begin Images/Cards/DiamondTen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondTen.png
+
+#begin Images/Cards/DiamondThree.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondThree.png
+
+#begin Images/Cards/DiamondTwo.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/DiamondTwo.png
+
+#begin Images/Cards/FirstJoker.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/FirstJoker.png
+
+#begin Images/Cards/HeartAce.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartAce.png
+
+#begin Images/Cards/HeartEight.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartEight.png
+
+#begin Images/Cards/HeartFive.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartFive.png
+
+#begin Images/Cards/HeartFour.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartFour.png
+
+#begin Images/Cards/HeartJack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartJack.png
+
+#begin Images/Cards/HeartKing.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartKing.png
+
+#begin Images/Cards/HeartNine.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartNine.png
+
+#begin Images/Cards/HeartQueen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartQueen.png
+
+#begin Images/Cards/HeartSeven.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartSeven.png
+
+#begin Images/Cards/HeartSix.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartSix.png
+
+#begin Images/Cards/HeartTen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartTen.png
+
+#begin Images/Cards/HeartThree.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartThree.png
+
+#begin Images/Cards/HeartTwo.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/HeartTwo.png
+
+#begin Images/Cards/SecondJoker.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SecondJoker.png
+
+#begin Images/Cards/SpadeAce.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeAce.png
+
+#begin Images/Cards/SpadeEight.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeEight.png
+
+#begin Images/Cards/SpadeFive.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeFive.png
+
+#begin Images/Cards/SpadeFour.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeFour.png
+
+#begin Images/Cards/SpadeJack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeJack.png
+
+#begin Images/Cards/SpadeKing.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeKing.png
+
+#begin Images/Cards/SpadeNine.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeNine.png
+
+#begin Images/Cards/SpadeQueen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeQueen.png
+
+#begin Images/Cards/SpadeSeven.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeSeven.png
+
+#begin Images/Cards/SpadeSix.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeSix.png
+
+#begin Images/Cards/SpadeTen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeTen.png
+
+#begin Images/Cards/SpadeThree.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeThree.png
+
+#begin Images/Cards/SpadeTwo.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Cards/SpadeTwo.png
+
+#begin Images/Chips/chip100.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chip100.png
+
+#begin Images/Chips/chip25.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chip25.png
+
+#begin Images/Chips/chip5.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chip5.png
+
+#begin Images/Chips/chip500.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chip500.png
+
+#begin Images/Chips/chipBlack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chipBlack.png
+
+#begin Images/Chips/chipRed.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chipRed.png
+
+#begin Images/Chips/chipWhite.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chipWhite.png
+
+#begin Images/Chips/chipYellow.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/Chips/chipYellow.png
+
+#begin Images/GamePadCursor.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/GamePadCursor.png
+
+#begin Images/titlescreen.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/titlescreen.png
+
+#begin Images/UI/blackjack.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/blackjack.png
+
+#begin Images/UI/bust.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/bust.png
+
+#begin Images/UI/lose.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/lose.png
+
+#begin Images/UI/pass.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/pass.png
+
+#begin Images/UI/push.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/push.png
+
+#begin Images/UI/ring.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/ring.png
+
+#begin Images/UI/Shuffle_Blue.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/Shuffle_Blue.png
+
+#begin Images/UI/Shuffle_Red.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/Shuffle_Red.png
+
+#begin Images/UI/table.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/table.png
+
+#begin Images/UI/win.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/UI/win.png
+
+#begin Images/youLose.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/youLose.png
+
+#begin Images/instructions.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/build:Images/instructions.png
+
+#begin Sounds/Bet.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/build:Sounds/Bet.wav
+
+#begin Sounds/CardFlip.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/build:Sounds/CardFlip.wav
+
+#begin Sounds/CardsShuffle.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/build:Sounds/CardsShuffle.wav
+
+#begin Sounds/Deal.wav
+/importer:WavImporter
+/processor:SoundEffectProcessor
+/build:Sounds/Deal.wav

+ 60 - 0
CardsStarterKit/Core/Content/Fonts/Bold.spritefont

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file contains an xml description of a font, and will be read by the XNA
+Framework Content Pipeline. Follow the comments to customize the appearance
+of the font in your game, and to change the characters which are available to draw
+with.
+-->
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+  <Asset Type="Graphics:FontDescription">
+
+    <!--
+    Modify this string to change the font that will be imported.
+    -->
+    <FontName>Arial</FontName>
+
+    <!--
+    Size is a float value, measured in points. Modify this value to change
+    the size of the font.
+    -->
+    <Size>20</Size>
+
+    <!--
+    Spacing is a float value, measured in pixels. Modify this value to change
+    the amount of spacing in between characters.
+    -->
+    <Spacing>0</Spacing>
+
+    <!--
+    UseKerning controls the layout of the font. If this value is true, kerning information
+    will be used when placing characters.
+    -->
+    <UseKerning>true</UseKerning>
+
+    <!--
+    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
+    and "Bold, Italic", and are case sensitive.
+    -->
+    <Style>Bold</Style>
+
+    <!--
+    If you uncomment this line, the default character will be substituted if you draw
+    or measure text that contains characters which were not included in the font.
+    -->
+    <!-- <DefaultCharacter>*</DefaultCharacter> -->
+
+    <!--
+    CharacterRegions control what letters are available in the font. Every
+    character from Start to End will be built and made available for drawing. The
+    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
+    character set. The characters are ordered according to the Unicode standard.
+    See the documentation for more information.
+    -->
+    <CharacterRegions>
+      <CharacterRegion>
+        <Start>&#32;</Start>
+        <End>&#126;</End>
+      </CharacterRegion>
+    </CharacterRegions>
+  </Asset>
+</XnaContent>

+ 60 - 0
CardsStarterKit/Core/Content/Fonts/MenuFont.spritefont

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file contains an xml description of a font, and will be read by the XNA
+Framework Content Pipeline. Follow the comments to customize the appearance
+of the font in your game, and to change the characters which are available to draw
+with.
+-->
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+  <Asset Type="Graphics:FontDescription">
+
+    <!--
+    Modify this string to change the font that will be imported.
+    -->
+    <FontName>Arial</FontName>
+
+    <!--
+    Size is a float value, measured in points. Modify this value to change
+    the size of the font.
+    -->
+    <Size>24</Size>
+
+    <!--
+    Spacing is a float value, measured in pixels. Modify this value to change
+    the amount of spacing in between characters.
+    -->
+    <Spacing>0</Spacing>
+
+    <!--
+    UseKerning controls the layout of the font. If this value is true, kerning information
+    will be used when placing characters.
+    -->
+    <UseKerning>true</UseKerning>
+
+    <!--
+    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
+    and "Bold, Italic", and are case sensitive.
+    -->
+    <Style>Bold</Style>
+
+    <!--
+    If you uncomment this line, the default character will be substituted if you draw
+    or measure text that contains characters which were not included in the font.
+    -->
+    <!-- <DefaultCharacter>*</DefaultCharacter> -->
+
+    <!--
+    CharacterRegions control what letters are available in the font. Every
+    character from Start to End will be built and made available for drawing. The
+    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
+    character set. The characters are ordered according to the Unicode standard.
+    See the documentation for more information.
+    -->
+    <CharacterRegions>
+      <CharacterRegion>
+        <Start>&#32;</Start>
+        <End>&#126;</End>
+      </CharacterRegion>
+    </CharacterRegions>
+  </Asset>
+</XnaContent>

+ 60 - 0
CardsStarterKit/Core/Content/Fonts/Regular.spritefont

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+This file contains an xml description of a font, and will be read by the XNA
+Framework Content Pipeline. Follow the comments to customize the appearance
+of the font in your game, and to change the characters which are available to draw
+with.
+-->
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+  <Asset Type="Graphics:FontDescription">
+
+    <!--
+    Modify this string to change the font that will be imported.
+    -->
+    <FontName>Arial</FontName>
+
+    <!--
+    Size is a float value, measured in points. Modify this value to change
+    the size of the font.
+    -->
+    <Size>20</Size>
+
+    <!--
+    Spacing is a float value, measured in pixels. Modify this value to change
+    the amount of spacing in between characters.
+    -->
+    <Spacing>0</Spacing>
+
+    <!--
+    UseKerning controls the layout of the font. If this value is true, kerning information
+    will be used when placing characters.
+    -->
+    <UseKerning>true</UseKerning>
+
+    <!--
+    Style controls the style of the font. Valid entries are "Regular", "Bold", "Italic",
+    and "Bold, Italic", and are case sensitive.
+    -->
+    <Style>Regular</Style>
+
+    <!--
+    If you uncomment this line, the default character will be substituted if you draw
+    or measure text that contains characters which were not included in the font.
+    -->
+    <!-- <DefaultCharacter>*</DefaultCharacter> -->
+
+    <!--
+    CharacterRegions control what letters are available in the font. Every
+    character from Start to End will be built and made available for drawing. The
+    default range is from 32, (ASCII space), to 126, ('~'), covering the basic Latin
+    character set. The characters are ordered according to the Unicode standard.
+    See the documentation for more information.
+    -->
+    <CharacterRegions>
+      <CharacterRegion>
+        <Start>&#32;</Start>
+        <End>&#126;</End>
+      </CharacterRegion>
+    </CharacterRegions>
+  </Asset>
+</XnaContent>

BIN
CardsStarterKit/Core/Content/Images/Button.png


BIN
CardsStarterKit/Core/Content/Images/ButtonPressed.png


BIN
CardsStarterKit/Core/Content/Images/ButtonRegular.png


BIN
CardsStarterKit/Core/Content/Images/Cards/CardBack_Blue.png


BIN
CardsStarterKit/Core/Content/Images/Cards/CardBack_Red.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubAce.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubEight.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubFive.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubFour.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubJack.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubKing.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubNine.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubQueen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubSeven.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubSix.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubTen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubThree.png


BIN
CardsStarterKit/Core/Content/Images/Cards/ClubTwo.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondAce.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondEight.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondFive.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondFour.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondJack.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondKing.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondNine.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondQueen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondSeven.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondSix.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondTen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondThree.png


BIN
CardsStarterKit/Core/Content/Images/Cards/DiamondTwo.png


BIN
CardsStarterKit/Core/Content/Images/Cards/FirstJoker.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartAce.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartEight.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartFive.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartFour.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartJack.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartKing.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartNine.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartQueen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartSeven.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartSix.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartTen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartThree.png


BIN
CardsStarterKit/Core/Content/Images/Cards/HeartTwo.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SecondJoker.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeAce.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeEight.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeFive.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeFour.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeJack.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeKing.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeNine.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeQueen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeSeven.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeSix.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeTen.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeThree.png


BIN
CardsStarterKit/Core/Content/Images/Cards/SpadeTwo.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chip100.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chip25.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chip5.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chip500.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chipBlack.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chipRed.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chipWhite.png


BIN
CardsStarterKit/Core/Content/Images/Chips/chipYellow.png


BIN
CardsStarterKit/Core/Content/Images/GamePadCursor.png


BIN
CardsStarterKit/Core/Content/Images/UI/Shuffle_Blue.png


BIN
CardsStarterKit/Core/Content/Images/UI/Shuffle_Red.png


BIN
CardsStarterKit/Core/Content/Images/UI/blackjack.png


BIN
CardsStarterKit/Core/Content/Images/UI/bust.png


BIN
CardsStarterKit/Core/Content/Images/UI/lose.png


BIN
CardsStarterKit/Core/Content/Images/UI/pass.png


BIN
CardsStarterKit/Core/Content/Images/UI/push.png


BIN
CardsStarterKit/Core/Content/Images/UI/ring.png


BIN
CardsStarterKit/Core/Content/Images/UI/table.png


BIN
CardsStarterKit/Core/Content/Images/UI/win.png


BIN
CardsStarterKit/Core/Content/Images/blank.png


BIN
CardsStarterKit/Core/Content/Images/instructions.png


BIN
CardsStarterKit/Core/Content/Images/titlescreen.png


BIN
CardsStarterKit/Core/Content/Images/youLose.png


BIN
CardsStarterKit/Core/Content/Sounds/Bet.wav


BIN
CardsStarterKit/Core/Content/Sounds/CardFlip.wav


BIN
CardsStarterKit/Core/Content/Sounds/CardsShuffle.wav


BIN
CardsStarterKit/Core/Content/Sounds/Deal.wav


BIN
CardsStarterKit/Core/Game/Background.png


+ 22 - 0
CardsStarterKit/Core/Game/Blackjack.Core.csproj

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <RootNamespace>Blackjack.Core</RootNamespace>
+    <AssemblyTitle>Blackjack</AssemblyTitle>
+    <AssemblyProduct>Blackjack</AssemblyProduct>
+    <AssemblyDescription></AssemblyDescription>
+    <AssemblyCompany>Microsoft</AssemblyCompany>
+    <AssemblyCopyright>Copyright © Microsoft 2010</AssemblyCopyright>
+    <AssemblyVersion>1.0.0.0</AssemblyVersion>
+    <Authors>CartBlanche</Authors>
+    <Company>MonoGame Foundation</Company>
+    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
+  </PropertyGroup>
+  <ItemGroup>
+    <PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.*" PrivateAssets="all"/>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Framework\Cards.Framework.csproj" />
+  </ItemGroup>
+</Project>

+ 1644 - 0
CardsStarterKit/Core/Game/Blackjack/Game/BlackjackCardGame.cs

@@ -0,0 +1,1644 @@
+//-----------------------------------------------------------------------------
+// BlackjackGame.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CardsFramework;
+using Microsoft.Xna.Framework;
+using System.Threading;
+using Microsoft.Xna.Framework.Input;
+using Microsoft.Xna.Framework.Graphics;
+using GameStateManagement;
+using System.Reflection;
+
+namespace Blackjack
+{
+    /// <summary>
+    /// The various possible game states.
+    /// </summary>
+    public enum BlackjackGameState
+    {
+        Shuffling,
+        Betting,
+        Playing,
+        Dealing,
+        RoundEnd,
+        GameOver,
+    }
+
+    class BlackjackCardGame : CardsGame
+    {
+        Dictionary<Player, string> playerHandValueTexts =
+            new Dictionary<Player, string>();
+        Dictionary<Player, string> playerSecondHandValueTexts =
+            new Dictionary<Player, string>();
+        private Hand deadCards = new Hand(); // stores used cards
+        private BlackjackPlayer dealerPlayer;
+        bool[] turnFinishedByPlayer;
+        TimeSpan dealDuration = TimeSpan.FromMilliseconds(500);
+
+        AnimatedHandGameComponent[] animatedHands;
+        // An additional list for managing hands created when performing a split.
+        AnimatedHandGameComponent[] animatedSecondHands;
+
+        BetGameComponent betGameComponent;
+        AnimatedHandGameComponent dealerHandComponent;
+        Dictionary<string, Button> buttons = new Dictionary<string, Button>();
+        Button newGame;
+        bool showInsurance;
+
+        // An offset used for drawing the second hand which appears after a split in
+        // the correct location.
+        Vector2 secondHandOffset =
+            new Vector2(100 * BlackjackGame.WidthScale, 25 * BlackjackGame.HeightScale);
+        static Vector2 ringOffset = new Vector2(0, 110);
+
+        Vector2 frameSize = BlackjackGame.IsMobile ? new Vector2(162, 162) : new Vector2(180, 180);
+
+        public BlackjackGameState State { get; set; }
+        ScreenManager screenManager;
+
+        const int maxPlayers = 3;
+        const int minPlayers = 1;
+
+        /// <summary>
+        /// Creates a new instance of the <see cref="BlackjackCardGame"/> class.
+        /// </summary>
+        /// <param name="tableBounds">The table bounds. These serves as the bounds for 
+        /// the game's main area.</param>
+        /// <param name="dealerPosition">Position for the dealer's deck.</param>
+        /// <param name="placeOrder">A method that translate a player index into the
+        /// position of his deck on the game table.</param>
+        /// <param name="screenManager">The games <see cref="ScreenManager"/>.</param>
+        /// <param name="theme">The game's deck theme name.</param>
+        public BlackjackCardGame(Rectangle tableBounds, Vector2 dealerPosition,
+            Func<int, Vector2> placeOrder, ScreenManager screenManager, string theme)
+            : base(6, 0, CardSuit.AllSuits, CardsFramework.CardValue.NonJokers,
+            minPlayers, maxPlayers, new BlackJackTable(ringOffset, tableBounds,
+                dealerPosition, maxPlayers, placeOrder, theme, screenManager.Game),
+            theme, screenManager.Game)
+        {
+            dealerPlayer = new BlackjackPlayer("Dealer", this);
+            turnFinishedByPlayer = new bool[MaximumPlayers];
+            this.screenManager = screenManager;
+
+            if (animatedHands == null)
+            {
+                animatedHands = new AnimatedHandGameComponent[maxPlayers];
+            }
+            if (animatedSecondHands == null)
+            {
+                animatedSecondHands = new AnimatedHandGameComponent[maxPlayers];
+            }
+        }
+
+        /// <summary>
+        /// Performs necessary initializations.
+        /// </summary>
+        public void Initialize()
+        {
+            base.LoadContent();
+            // Initialize a new bet component
+            betGameComponent =
+                new BetGameComponent(players, screenManager.input, Theme, this);
+            Game.Components.Add(betGameComponent);
+
+            // Initialize the game buttons
+            string[] buttonsText = { "Hit", "Stand", "Double", "Split", "Insurance" };
+            for (int buttonIndex = 0; buttonIndex < buttonsText.Length; buttonIndex++)
+            {
+                Button button = new Button("ButtonRegular", "ButtonPressed",
+                    screenManager.input, this)
+                {
+                    Text = buttonsText[buttonIndex],
+                    Bounds = new Rectangle(screenManager.SafeArea.Left + 10 + buttonIndex * 110,
+                        screenManager.SafeArea.Bottom - 60,
+                    100, 50),
+                    Font = this.Font,
+                    Visible = false,
+                    Enabled = false
+                };
+                buttons.Add(buttonsText[buttonIndex], button);
+                Game.Components.Add(button);
+            }
+
+            newGame = new Button("ButtonRegular", "ButtonPressed",
+                screenManager.input, this)
+            {
+                Text = "New Hand",
+
+                Bounds = new Rectangle(screenManager.SafeArea.Left + 10,
+                    screenManager.SafeArea.Bottom - 60, 200, 50),
+                Font = this.Font,
+                Visible = false,
+                Enabled = false
+            };
+
+            // Alter the insurance button's bounds as it is considerably larger than
+            // the other buttons
+            Rectangle insuranceBounds = buttons["Insurance"].Bounds;
+            insuranceBounds.Width = 200;
+            buttons["Insurance"].Bounds = insuranceBounds;
+
+            newGame.Click += newGame_Click;
+            Game.Components.Add(newGame);
+
+            // Register to click event
+            buttons["Hit"].Click += Hit_Click;
+            buttons["Stand"].Click += Stand_Click;
+            buttons["Double"].Click += Double_Click;
+            buttons["Split"].Click += Split_Click;
+            buttons["Insurance"].Click += Insurance_Click;
+        }
+
+        /// <summary>
+        /// Perform the game's update logic.
+        /// </summary>
+        /// <param name="gameTime">Time elapsed since the last call to 
+        /// this method.</param>
+        public void Update(GameTime gameTime)
+        {
+            switch (State)
+            {
+                case BlackjackGameState.Shuffling:
+                    {
+                        ShowShuffleAnimation();
+                    } break;
+                case BlackjackGameState.Betting:
+                    {
+                        EnableButtons(false);
+                    } break;
+                case BlackjackGameState.Dealing:
+                    {
+                        // Deal 2 cards and start playing
+                        State = BlackjackGameState.Playing;
+                        Deal();
+                        StartPlaying();
+                    } break;
+                case BlackjackGameState.Playing:
+                    {
+                        // Calculate players' current hand values
+                        for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+                        {
+                            ((BlackjackPlayer)players[playerIndex]).CalculateValues();
+                        }
+                        dealerPlayer.CalculateValues();
+
+                        // Make sure no animations are running
+                        if (!CheckForRunningAnimations<AnimatedCardsGameComponent>())
+                        {
+                            BlackjackPlayer player =
+                                (BlackjackPlayer)GetCurrentPlayer();
+                            // If the current player is an AI player, make it play
+                            if (player is BlackjackAIPlayer)
+                            {
+                                ((BlackjackAIPlayer)player).AIPlay();
+                            }
+
+                            CheckRules();
+
+                            // If all players have finished playing, the 
+                            // current round ends
+                            if (State == BlackjackGameState.Playing &&
+                                GetCurrentPlayer() == null)
+                            {
+                                EndRound();
+                            }
+
+                            // Update button availability according to player options
+                            SetButtonAvailability();
+                        }
+                        else
+                            EnableButtons(false);
+                    } break;
+                case BlackjackGameState.RoundEnd:
+                    {
+                        if (dealerHandComponent.EstimatedTimeForAnimationsCompletion() == TimeSpan.Zero)
+                        {
+                            betGameComponent.CalculateBalance(dealerPlayer);
+                            // Check if there is enough money to play
+                            // then show new game option or tell the player he has lost
+                            if (((BlackjackPlayer)players[0]).Balance < 5)
+                            {
+                                EndGame();
+                            }
+                            else
+                            {
+                                newGame.Enabled = true;
+                                newGame.Visible = true;
+                            }
+                        }
+                    } break;
+                case BlackjackGameState.GameOver:
+                    {
+
+                    } break;
+                default: break;
+            }
+        }
+
+        /// <summary>
+        /// Shows the card shuffling animation.
+        /// </summary>
+        private void ShowShuffleAnimation()
+        {
+            // Add shuffling animation
+            AnimatedGameComponent animationComponent = new AnimatedGameComponent(this.Game)
+            {
+                CurrentPosition = GameTable.DealerPosition,
+                Visible = false
+            };
+            Game.Components.Add(animationComponent);
+
+            animationComponent.AddAnimation(
+                new FramesetGameComponentAnimation(cardsAssets["shuffle_" + Theme], 32, 11, frameSize)
+            {
+                Duration = TimeSpan.FromSeconds(1.5f),
+                PerformBeforeStart = ShowComponent,
+                PerformBeforSartArgs = animationComponent,
+                PerformWhenDone = PlayShuffleAndRemoveComponent,
+                PerformWhenDoneArgs = animationComponent
+            });
+            State = BlackjackGameState.Betting;
+        }
+
+        /// <summary>
+        /// Helper method to show component
+        /// </summary>
+        /// <param name="obj"></param>
+        void ShowComponent(object obj)
+        {
+            ((AnimatedGameComponent)obj).Visible = true;
+        }
+
+        /// <summary>
+        /// Helper method to play shuffle sound and remove component
+        /// </summary>
+        /// <param name="obj"></param>
+        void PlayShuffleAndRemoveComponent(object obj)
+        {
+            AudioManager.PlaySound("Shuffle");
+            Game.Components.Remove((AnimatedGameComponent)obj);
+        }
+
+        /// <summary>
+        /// Renders the visual elements for which the game itself is responsible.
+        /// </summary>
+        /// <param name="gameTime">Time passed since the last call to 
+        /// this method.</param>
+        public void Draw(GameTime gameTime)
+        {
+            SpriteBatch.Begin();
+
+            switch (State)
+            {
+                case BlackjackGameState.Playing:
+                    {
+                        ShowPlayerValues();
+                    } break;
+                case BlackjackGameState.GameOver:
+                    {
+                    } break;
+                case BlackjackGameState.RoundEnd:
+                    {
+                        if (dealerHandComponent.EstimatedTimeForAnimationsCompletion() == TimeSpan.Zero)
+                        {
+                            ShowDealerValue();
+                        }
+                        ShowPlayerValues();
+                    } break;
+                default: break;
+            }
+
+            SpriteBatch.End();
+        }
+
+        /// <summary>
+        /// Draws the dealer's hand value on the screen.
+        /// </summary>
+        private void ShowDealerValue()
+        {
+            // Calculate the value to display
+            string dealerValue = dealerPlayer.FirstValue.ToString();
+            if (dealerPlayer.FirstValueConsiderAce)
+            {
+                if (dealerPlayer.FirstValue + 10 == 21)
+                {
+                    dealerValue = "21";
+                }
+                else
+                {
+                    dealerValue += @"\" + (dealerPlayer.FirstValue + 10).ToString();
+                }
+            }
+
+            // Draw the value
+            Vector2 measure = Font.MeasureString(dealerValue);
+            Vector2 position = GameTable.DealerPosition - new Vector2(measure.X + 20, 0);
+
+            SpriteBatch.Draw(screenManager.BlankTexture,
+                new Rectangle((int)position.X - 4, (int)position.Y,
+                (int)measure.X + 8, (int)measure.Y), Color.Black);
+
+            SpriteBatch.DrawString(Font, dealerValue,
+                position, Color.White);
+        }
+
+        /// <summary>
+        /// Draws the players' hand value on the screen.
+        /// </summary>
+        private void ShowPlayerValues()
+        {
+            Color color = Color.Black;
+            Player currentPlayer = GetCurrentPlayer();
+
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                BlackjackPlayer player = (BlackjackPlayer)players[playerIndex];
+                // The current player's hand value will be red to serve as a visual
+                // prompt for who the active player is
+                if (player == currentPlayer)
+                {
+                    color = Color.Red;
+                }
+                else
+                {
+                    color = Color.White;
+                }
+
+                // Calculate the values to draw
+                string playerHandValueText;
+                string playerSecondHandValueText = null;
+                if (!animatedHands[playerIndex].IsAnimating)
+                {
+                    if (player.FirstValue > 0)
+                    {
+                        playerHandValueText = player.FirstValue.ToString();
+                        // Take the fact that an ace is wither 1 or 11 into 
+                        // consideration when calculating the value to display
+                        // Since the ace already counts as 1, we add 10 to get
+                        // the alternate value
+                        if (player.FirstValueConsiderAce)
+                        {
+                            if (player.FirstValue + 10 == 21)
+                            {
+                                playerHandValueText = "21";
+                            }
+                            else
+                            {
+                                playerHandValueText += @"\" +
+                                    (player.FirstValue + 10).ToString();
+                            }
+                        }
+                        playerHandValueTexts[player] = playerHandValueText;
+                    }
+                    else
+                    {
+                        playerHandValueText = null;
+                    }
+
+                    if (player.IsSplit)
+                    {
+                        // If the player has performed a split, he has an additional
+                        // hand with its own value
+                        if (player.SecondValue > 0)
+                        {
+                            playerSecondHandValueText = player.SecondValue.ToString();
+                            if (player.SecondValueConsiderAce)
+                            {
+                                if (player.SecondValue + 10 == 21)
+                                {
+                                    playerSecondHandValueText = "21";
+                                }
+                                else
+                                {
+                                    playerSecondHandValueText +=
+                                        @"\" + (player.SecondValue + 10).ToString();
+                                }
+                            }
+                            playerSecondHandValueTexts[player] =
+                                playerSecondHandValueText;
+                        }
+                        else
+                        {
+                            playerSecondHandValueText = null;
+                        }
+                    }
+                }
+                else
+                {
+                    playerHandValueTexts.TryGetValue(player, out playerHandValueText);
+                    playerSecondHandValueTexts.TryGetValue(
+                        player, out playerSecondHandValueText);
+                }
+
+                if (player.IsSplit)
+                {
+                    // If the player has performed a split, mark the active hand alone
+                    // with a red value
+                    color = player.CurrentHandType == HandTypes.First &&
+                        player == currentPlayer ? Color.Red : Color.White;
+
+                    if (playerHandValueText != null)
+                    {
+                        DrawValue(animatedHands[playerIndex], playerIndex, playerHandValueText, color);
+                    }
+
+                    color = player.CurrentHandType == HandTypes.Second &&
+                        player == currentPlayer ? Color.Red : Color.White;
+
+                    if (playerSecondHandValueText != null)
+                    {
+                        DrawValue(animatedSecondHands[playerIndex], playerIndex, playerSecondHandValueText,
+                            color);
+                    }
+                }
+                else
+                {
+                    // If there is a value to draw, draw it
+                    if (playerHandValueText != null)
+                    {
+                        DrawValue(animatedHands[playerIndex], playerIndex, playerHandValueText, color);
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Draws the value of a player's hand above his top card.
+        /// The value will be drawn over a black background.
+        /// </summary>
+        /// <param name="animatedHand">The player's hand.</param>
+        /// <param name="place">A number representing the player's position on the
+        /// game table.</param>
+        /// <param name="value">The value to draw.</param>
+        /// <param name="valueColor">The color in which to draw the value.</param>
+        private void DrawValue(AnimatedHandGameComponent animatedHand, int place,
+            string value, Color valueColor)
+        {
+            Hand hand = animatedHand.Hand;
+
+            Vector2 position = GameTable.PlaceOrder(place) +
+                animatedHand.GetCardRelativePosition(hand.Count - 1);
+            Vector2 measure = Font.MeasureString(value);
+
+            position.X += (cardsAssets["CardBack_" + Theme].Bounds.Width - measure.X) / 2;
+            position.Y -= measure.Y + 5;
+
+            SpriteBatch.Draw(screenManager.BlankTexture,
+                new Rectangle((int)position.X - 4, (int)position.Y,
+                (int)measure.X + 8, (int)measure.Y), Color.Black);
+            SpriteBatch.DrawString(Font, value, position, valueColor);
+
+        }
+
+        /// <summary>
+        /// Adds a player to the game.
+        /// </summary>
+        /// <param name="player">The player to add.</param>
+        public override void AddPlayer(Player player)
+        {
+            if (player is BlackjackPlayer && players.Count < MaximumPlayers)
+            {
+                players.Add(player);
+            }
+        }
+
+        /// <summary>
+        /// Gets the active player.
+        /// </summary>
+        /// <returns>The first payer who has placed a bet and has not 
+        /// finish playing.</returns>
+        public override Player GetCurrentPlayer()
+        {
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                if (((BlackjackPlayer)players[playerIndex]).MadeBet && turnFinishedByPlayer[playerIndex] == false)
+                {
+                    return players[playerIndex];
+                }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Calculate the value of a blackjack card.
+        /// </summary>
+        /// <param name="card">The card to calculate the value for.</param>
+        /// <returns>The card's value. All card values are equal to their face number,
+        /// except for jack/queen/king which value at 10.</returns>
+        /// <remarks>An ace's value will be 1. Game logic will treat it as 11 where
+        /// appropriate.</remarks>
+        public override int CardValue(TraditionalCard card)
+        {
+            return Math.Min(base.CardValue(card), 10);
+        }
+
+        /// <summary>
+        /// Deals 2 cards to each player including the dealer and adds the appropriate 
+        /// animations.
+        /// </summary>
+        public override void Deal()
+        {
+            if (State == BlackjackGameState.Playing)
+            {
+                TraditionalCard card;
+                for (int dealIndex = 0; dealIndex < 2; dealIndex++)
+                {
+                    for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+                    {
+                        if (((BlackjackPlayer)players[playerIndex]).MadeBet)
+                        {
+                            // Deal a card to one of the players
+                            card = dealer.DealCardToHand(players[playerIndex].Hand);
+
+                            AddDealAnimation(card, animatedHands[playerIndex], true, dealDuration,
+                                DateTime.Now + TimeSpan.FromSeconds(
+                                dealDuration.TotalSeconds * (dealIndex * players.Count + playerIndex)));
+                        }
+                    }
+                    // Deal a card to the dealer
+                    card = dealer.DealCardToHand(dealerPlayer.Hand);
+                    AddDealAnimation(card, dealerHandComponent, dealIndex == 0, dealDuration, DateTime.Now);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Performs necessary initializations needed after dealing the cards in order
+        /// to start playing.
+        /// </summary>
+        public override void StartPlaying()
+        {
+            // Check that there are enough players to start playing
+            if ((MinimumPlayers <= players.Count && players.Count <= MaximumPlayers))
+            {
+                // Set up and register to gameplay events
+
+                GameRule gameRule = new BustRule(players);
+                rules.Add(gameRule);
+                gameRule.RuleMatch += BustGameRule;
+
+                gameRule = new BlackJackRule(players);
+                rules.Add(gameRule);
+                gameRule.RuleMatch += BlackJackGameRule;
+
+                gameRule = new InsuranceRule(dealerPlayer.Hand);
+                rules.Add(gameRule);
+                gameRule.RuleMatch += InsuranceGameRule;
+
+                // Display the hands participating in the game
+                for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+                {
+                    if (((BlackjackPlayer)players[playerIndex]).MadeBet)
+                    {
+                        animatedHands[playerIndex].Visible = false;
+                    }
+                    else
+                    {
+                        animatedHands[playerIndex].Visible = true;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Display an animation when a card is dealt.
+        /// </summary>
+        /// <param name="card">The card being dealt.</param>
+        /// <param name="animatedHand">The animated hand into which the card 
+        /// is dealt.</param>
+        /// <param name="flipCard">Should the card be flipped after dealing it.</param>
+        /// <param name="duration">The animations desired duration.</param>
+        /// <param name="startTime">The time at which the animation should 
+        /// start.</param>
+        public void AddDealAnimation(TraditionalCard card, AnimatedHandGameComponent
+            animatedHand, bool flipCard, TimeSpan duration, DateTime startTime)
+        {
+            // Get the card location and card component
+            int cardLocationInHand = animatedHand.GetCardLocationInHand(card);
+            AnimatedCardsGameComponent cardComponent = animatedHand.GetCardGameComponent(cardLocationInHand);
+
+            // Add the transition animation
+            cardComponent.AddAnimation(
+                new TransitionGameComponentAnimation(GameTable.DealerPosition,
+                animatedHand.CurrentPosition +
+                animatedHand.GetCardRelativePosition(cardLocationInHand))
+            {
+                StartTime = startTime,
+                PerformBeforeStart = ShowComponent,
+                PerformBeforSartArgs = cardComponent,
+                PerformWhenDone = PlayDealSound
+            });
+
+            if (flipCard)
+            {
+                // Add the flip animation
+                cardComponent.AddAnimation(new FlipGameComponentAnimation
+                {
+                    IsFromFaceDownToFaceUp = true,
+                    Duration = duration,
+                    StartTime = startTime + duration,
+                    PerformWhenDone = PlayFlipSound
+                });
+            }
+        }
+
+        /// <summary>
+        /// Helper method to play deal sound
+        /// </summary>
+        /// <param name="obj"></param>
+        void PlayDealSound(object obj)
+        {
+            AudioManager.PlaySound("Deal");
+        }
+
+        /// <summary>
+        /// Helper method to play flip sound
+        /// </summary>
+        /// <param name="obj"></param>
+        void PlayFlipSound(object obj)
+        {
+            AudioManager.PlaySound("Flip");
+        }
+
+        /// <summary>
+        /// Adds an animation which displays an asset over a player's hand. The asset
+        /// will appear above the hand and appear to "fall" on top of it.
+        /// </summary>
+        /// <param name="player">The player over the hand of which to place the
+        /// animation.</param>
+        /// <param name="assetName">Name of the asset to display above the hand.</param>
+        /// <param name="animationHand">Which hand to put cue over.</param>
+        /// <param name="waitForHand">Start the cue animation when the animation
+        /// of this hand over null of the animation of the currentHand</param>
+        void CueOverPlayerHand(BlackjackPlayer player, string assetName,
+            HandTypes animationHand, AnimatedHandGameComponent waitForHand)
+        {
+            // Get the position of the relevant hand
+            int playerIndex = players.IndexOf(player);
+            AnimatedHandGameComponent currentAnimatedHand;
+            Vector2 currentPosition;
+            if (playerIndex >= 0)
+            {
+                switch (animationHand)
+                {
+                    case HandTypes.First:
+                        currentAnimatedHand = animatedHands[playerIndex];
+                        currentPosition = currentAnimatedHand.CurrentPosition;
+                        break;
+                    case HandTypes.Second:
+                        currentAnimatedHand = animatedSecondHands[playerIndex];
+                        currentPosition = currentAnimatedHand.CurrentPosition +
+                            secondHandOffset;
+                        break;
+                    default:
+                        throw new Exception(
+                            "Player has an unsupported hand type.");
+                }
+            }
+            else
+            {
+                currentAnimatedHand = dealerHandComponent;
+                currentPosition = currentAnimatedHand.CurrentPosition;
+            }
+
+            // Add the animation component 
+            AnimatedGameComponent animationComponent =
+                new AnimatedGameComponent(this, cardsAssets[assetName])
+            {
+                CurrentPosition = currentPosition,
+                Visible = false
+            };
+            Game.Components.Add(animationComponent);
+
+            // Calculate when to start the animation. The animation will only begin
+            // after all hand cards finish animating
+            TimeSpan estimatedTimeToCompleteAnimations;
+            if (waitForHand != null)
+            {
+                estimatedTimeToCompleteAnimations = waitForHand.EstimatedTimeForAnimationsCompletion();
+            }
+            else
+            {
+                estimatedTimeToCompleteAnimations = currentAnimatedHand.EstimatedTimeForAnimationsCompletion();
+            }
+
+            // Add a scale effect animation
+            animationComponent.AddAnimation(new ScaleGameComponentAnimation(2.0f, 1.0f)
+            {
+                StartTime =
+                    DateTime.Now + estimatedTimeToCompleteAnimations,
+                Duration = TimeSpan.FromSeconds(1f),
+                PerformBeforeStart = ShowComponent,
+                PerformBeforSartArgs = animationComponent
+            });
+        }
+
+        /// <summary>
+        /// Ends the current round.
+        /// </summary>
+        private void EndRound()
+        {
+            RevealDealerFirstCard();
+            DealerAI();
+            ShowResults();
+            State = BlackjackGameState.RoundEnd;
+        }
+
+        /// <summary>
+        /// Causes the dealer's hand to be displayed.
+        /// </summary>
+        private void ShowDealerHand()
+        {
+            dealerHandComponent =
+                new BlackjackAnimatedDealerHandComponent(-1, dealerPlayer.Hand, this);
+            Game.Components.Add(dealerHandComponent);
+        }
+
+        /// <summary>
+        /// Reveal's the dealer's hidden card.
+        /// </summary>
+        private void RevealDealerFirstCard()
+        {
+            // Iterate over all dealer cards expect for the last
+            AnimatedCardsGameComponent cardComponent = dealerHandComponent.GetCardGameComponent(1);
+            cardComponent.AddAnimation(new FlipGameComponentAnimation()
+            {
+                Duration = TimeSpan.FromSeconds(0.5),
+                StartTime = DateTime.Now
+            });
+        }
+
+        /// <summary>
+        /// Present visual indication as to how the players fared in the current round.
+        /// </summary>
+        private void ShowResults()
+        {
+            // Calculate the dealer's hand value
+            int dealerValue = dealerPlayer.FirstValue;
+
+            if (dealerPlayer.FirstValueConsiderAce)
+            {
+                dealerValue += 10;
+            }
+
+            // Show each player's result
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                ShowResultForPlayer((BlackjackPlayer)players[playerIndex], dealerValue, HandTypes.First);
+                if (((BlackjackPlayer)players[playerIndex]).IsSplit)
+                {
+                    ShowResultForPlayer((BlackjackPlayer)players[playerIndex], dealerValue, HandTypes.Second);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Display's a player's status after the turn has ended.
+        /// </summary>
+        /// <param name="player">The player for which to display the status.</param>
+        /// <param name="dealerValue">The dealer's hand value.</param>
+        /// <param name="currentHandType">The player's hand to take into 
+        /// account.</param>
+        private void ShowResultForPlayer(BlackjackPlayer player, int dealerValue,
+            HandTypes currentHandType)
+        {
+            // Calculate the player's hand value and check his state (blackjack/bust)
+            bool blackjack, bust;
+            int playerValue;
+            switch (currentHandType)
+            {
+                case HandTypes.First:
+                    blackjack = player.BlackJack;
+                    bust = player.Bust;
+
+                    playerValue = player.FirstValue;
+
+                    if (player.FirstValueConsiderAce)
+                    {
+                        playerValue += 10;
+                    }
+                    break;
+                case HandTypes.Second:
+                    blackjack = player.SecondBlackJack;
+                    bust = player.SecondBust;
+
+                    playerValue = player.SecondValue;
+
+                    if (player.SecondValueConsiderAce)
+                    {
+                        playerValue += 10;
+                    }
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+            // The bust or blackjack state are animated independently of this method,
+            // so only trigger different outcome indications
+            if (player.MadeBet &&
+                (!blackjack || (dealerPlayer.BlackJack && blackjack)) && !bust)
+            {
+                string assetName = GetResultAsset(player, dealerValue, playerValue);
+
+                CueOverPlayerHand(player, assetName, currentHandType, dealerHandComponent);
+            }
+        }
+
+        /// <summary>
+        /// Return the asset name according to the result.
+        /// </summary>
+        /// <param name="player">The player for which to return the asset name.</param>
+        /// <param name="dealerValue">The dealer's hand value.</param>
+        /// <param name="playerValue">The player's hand value.</param>
+        /// <returns>The asset name</returns>
+        private string GetResultAsset(BlackjackPlayer player, int dealerValue, int playerValue)
+        {
+            string assetName;
+            if (dealerPlayer.Bust)
+            {
+                assetName = "win";
+            }
+            else if (dealerPlayer.BlackJack)
+            {
+                if (player.BlackJack)
+                {
+                    assetName = "push";
+                }
+                else
+                {
+                    assetName = "lose";
+                }
+            }
+            else if (playerValue < dealerValue)
+            {
+                assetName = "lose";
+            }
+            else if (playerValue > dealerValue)
+            {
+                assetName = "win";
+            }
+            else
+            {
+                assetName = "push";
+            }
+            return assetName;
+        }
+
+        /// <summary>
+        /// Have the dealer play. The dealer hits until reaching 17+ and then 
+        /// stands.
+        /// </summary>
+        private void DealerAI()
+        {
+            // The dealer may have not need to draw additional cards after his first
+            // two. Check if this is the case and if so end the dealer's play.
+            dealerPlayer.CalculateValues();
+            int dealerValue = dealerPlayer.FirstValue;
+
+            if (dealerPlayer.FirstValueConsiderAce)
+            {
+                dealerValue += 10;
+            }
+
+            if (dealerValue > 21)
+            {
+                dealerPlayer.Bust = true;
+                CueOverPlayerHand(dealerPlayer, "bust", HandTypes.First, dealerHandComponent);
+            }
+            else if (dealerValue == 21)
+            {
+                dealerPlayer.BlackJack = true;
+                CueOverPlayerHand(dealerPlayer, "blackjack", HandTypes.First, dealerHandComponent);
+            }
+
+            if (dealerPlayer.BlackJack || dealerPlayer.Bust)
+            {
+                return;
+            }
+
+            // Draw cards until 17 is reached, or the dealer gets a blackjack or busts
+            int cardsDealed = 0;
+            while (dealerValue <= 17)
+            {
+                TraditionalCard card = dealer.DealCardToHand(dealerPlayer.Hand);
+                AddDealAnimation(card, dealerHandComponent, true, dealDuration,
+                    DateTime.Now.AddMilliseconds(1000 * (cardsDealed + 1)));
+                cardsDealed++;
+                dealerPlayer.CalculateValues();
+                dealerValue = dealerPlayer.FirstValue;
+
+                if (dealerPlayer.FirstValueConsiderAce)
+                {
+                    dealerValue += 10;
+                }
+
+                if (dealerValue > 21)
+                {
+                    dealerPlayer.Bust = true;
+                    CueOverPlayerHand(dealerPlayer, "bust", HandTypes.First, dealerHandComponent);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Displays the hands currently in play.
+        /// </summary>
+        private void DisplayPlayingHands()
+        {
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                AnimatedHandGameComponent animatedHandGameComponent =
+                    new BlackjackAnimatedPlayerHandComponent(playerIndex, players[playerIndex].Hand, this);
+                Game.Components.Add(animatedHandGameComponent);
+                animatedHands[playerIndex] = animatedHandGameComponent;
+            }
+
+            ShowDealerHand();
+        }
+
+        /// <summary>
+        /// Starts a new game round.
+        /// </summary>
+        public void StartRound()
+        {
+            playerHandValueTexts.Clear();
+            AudioManager.PlaySound("Shuffle");
+            dealer.Shuffle();
+            DisplayPlayingHands();
+            State = BlackjackGameState.Shuffling;
+        }
+
+        /// <summary>
+        /// Sets the button availability according to the options available to the 
+        /// current player.
+        /// </summary>
+        private void SetButtonAvailability()
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+            // Hide all buttons if no player is in play or the player is an AI player
+            if (player == null || player is BlackjackAIPlayer)
+            {
+                EnableButtons(false);
+                ChangeButtonsVisiblility(false);
+                return;
+            }
+
+            // Show all buttons
+            EnableButtons(true);
+            ChangeButtonsVisiblility(true);
+
+            // Set insurance button availability
+            buttons["Insurance"].Visible = showInsurance;
+            buttons["Insurance"].Enabled = showInsurance;
+
+            if (player.IsSplit == false)
+            {
+                // Remember that the bet amount was already reduced from the balance,
+                // so we only need to check if the player has more money than the
+                // current bet when trying to double/split
+
+                // Set double button availability
+                if (player.BetAmount > player.Balance || player.Hand.Count != 2)
+                {
+                    buttons["Double"].Visible = false;
+                    buttons["Double"].Enabled = false;
+                }
+
+                if (player.Hand.Count != 2 ||
+                    player.Hand[0].Value != player.Hand[1].Value ||
+                    player.BetAmount > player.Balance)
+                {
+                    buttons["Split"].Visible = false;
+                    buttons["Split"].Enabled = false;
+                }
+            }
+            else
+            {
+                // We've performed a split. Get the initial bet amount to check whether
+                // or not we can double the current bet.
+                float initialBet = player.BetAmount /
+                    ((player.Double ? 2f : 1f) + (player.SecondDouble ? 2f : 1f));
+
+                // Set double button availability.
+                if (initialBet > player.Balance || player.CurrentHand.Count != 2)
+                {
+                    buttons["Double"].Visible = false;
+                    buttons["Double"].Enabled = false;
+                }
+
+                // Once you've split, you can't split again
+                buttons["Split"].Visible = false;
+                buttons["Split"].Enabled = false;
+            }
+        }
+
+        /// <summary>
+        /// Checks for running animations.
+        /// </summary>
+        /// <typeparam name="T">The type of animation to look for.</typeparam>
+        /// <returns>True if a running animation of the desired type is found and
+        /// false otherwise.</returns>
+        internal bool CheckForRunningAnimations<T>() where T : AnimatedGameComponent
+        {
+            T animationComponent;
+            for (int componentIndex = 0; componentIndex < Game.Components.Count; componentIndex++)
+            {
+                animationComponent = Game.Components[componentIndex] as T;
+                if (animationComponent != null)
+                {
+                    if (animationComponent.IsAnimating)
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Ends the game.
+        /// </summary>
+        private void EndGame()
+        {
+            // Calculate the estimated time for all playing animations to end
+            long estimatedTime = 0;
+            AnimatedGameComponent animationComponent;
+            for (int componentIndex = 0; componentIndex < Game.Components.Count; componentIndex++)
+            {
+                animationComponent = Game.Components[componentIndex] as AnimatedGameComponent;
+                if (animationComponent != null)
+                {
+                    estimatedTime = Math.Max(estimatedTime,
+                        animationComponent.EstimatedTimeForAnimationsCompletion().Ticks);
+                }
+            }
+
+            // Add a component for an empty stalling animation. This actually acts
+            // as a timer.
+            Texture2D texture = this.Game.Content.Load<Texture2D>(@"Images\youlose");
+            animationComponent = new AnimatedGameComponent(this, texture)
+            {
+                CurrentPosition = new Vector2(
+                    this.Game.GraphicsDevice.Viewport.Bounds.Center.X - texture.Width / 2,
+                    this.Game.GraphicsDevice.Viewport.Bounds.Center.Y - texture.Height / 2),
+                Visible = false
+            };
+            this.Game.Components.Add(animationComponent);
+
+            // Add a button to return to the main menu
+            Rectangle bounds = this.Game.GraphicsDevice.Viewport.Bounds;
+            Vector2 center = new Vector2(bounds.Center.X, bounds.Center.Y);
+            Button backButton = new Button("ButtonRegular", "ButtonPressed",
+                screenManager.input, this)
+            {
+                Bounds = new Rectangle((int)center.X - 100, (int)center.Y + 80, 200, 50),
+                Font = this.Font,
+                Text = "Main Menu",
+                Visible = false,
+                Enabled = true,
+            };
+
+            backButton.Click += backButton_Click;
+
+            // Add stalling animation
+            animationComponent.AddAnimation(new AnimatedGameComponentAnimation()
+            {
+                Duration = TimeSpan.FromTicks(estimatedTime) + TimeSpan.FromSeconds(1),
+                PerformWhenDone = ResetGame,
+                PerformWhenDoneArgs = new object[] { animationComponent, backButton }
+            });
+            Game.Components.Add(backButton);
+        }
+
+        /// <summary>
+        /// Helper method to reset the game
+        /// </summary>
+        /// <param name="obj"></param>
+        void ResetGame(object obj)
+        {
+            object[] arr = (object[])obj;
+            State = BlackjackGameState.GameOver;
+            ((AnimatedGameComponent)arr[0]).Visible = true;
+            ((Button)arr[1]).Visible = true;
+
+            // Remove all unnecessary game components
+            for (int compontneIndex = 0; compontneIndex < Game.Components.Count; )
+            {
+                if ((Game.Components[compontneIndex] != ((AnimatedGameComponent)arr[0]) &&
+                    Game.Components[compontneIndex] != ((Button)arr[1])) &&
+                    (Game.Components[compontneIndex] is BetGameComponent ||
+                    Game.Components[compontneIndex] is AnimatedGameComponent ||
+                    Game.Components[compontneIndex] is Button))
+                {
+                    Game.Components.RemoveAt(compontneIndex);
+                }
+                else
+                    compontneIndex++;
+            }
+        }
+
+        /// <summary>
+        /// Finishes the current turn.
+        /// </summary>
+        private void FinishTurn()
+        {
+            // Remove all unnecessary components
+            for (int componentIndex = 0; componentIndex < Game.Components.Count; componentIndex++)
+            {
+                if (!(Game.Components[componentIndex] is GameTable ||
+                    Game.Components[componentIndex] is BlackjackCardGame ||
+                    Game.Components[componentIndex] is BetGameComponent ||
+                    Game.Components[componentIndex] is Button ||
+                    Game.Components[componentIndex] is ScreenManager ||
+                    Game.Components[componentIndex] is InputHelper))
+                {
+                    if (Game.Components[componentIndex] is AnimatedCardsGameComponent)
+                    {
+                        AnimatedCardsGameComponent animatedCard =
+                            (Game.Components[componentIndex] as AnimatedCardsGameComponent);
+                        animatedCard.AddAnimation(
+                            new TransitionGameComponentAnimation(animatedCard.CurrentPosition,
+                            new Vector2(animatedCard.CurrentPosition.X, this.Game.GraphicsDevice.Viewport.Height))
+                            {
+                                Duration = TimeSpan.FromSeconds(0.40),
+                                PerformWhenDone = RemoveComponent,
+                                PerformWhenDoneArgs = animatedCard
+                            });
+                    }
+                    else
+                    {
+                        Game.Components.RemoveAt(componentIndex);
+                        componentIndex--;
+                    }
+                }
+            }
+
+            // Reset player values
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                (players[playerIndex] as BlackjackPlayer).ResetValues();
+                players[playerIndex].Hand.DealCardsToHand(deadCards, players[playerIndex].Hand.Count);
+                turnFinishedByPlayer[playerIndex] = false;
+                animatedHands[playerIndex] = null;
+                animatedSecondHands[playerIndex] = null;
+            }
+
+            // Reset the bet component
+            betGameComponent.Reset();
+            betGameComponent.Enabled = true;
+
+            // Reset dealer
+            dealerPlayer.Hand.DealCardsToHand(deadCards, dealerPlayer.Hand.Count);
+            dealerPlayer.ResetValues();
+
+            // Reset rules
+            rules.Clear();
+        }
+
+        /// <summary>
+        /// Helper method to remove component
+        /// </summary>
+        /// <param name="obj"></param>
+        void RemoveComponent(object obj)
+        {
+            Game.Components.Remove((AnimatedGameComponent)obj);
+        }
+
+        /// <summary>
+        /// Performs the "Stand" move for the current player.
+        /// </summary>
+        public void Stand()
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+            if (player == null)
+                return;
+
+            // If the player only has one hand, his turn ends. Otherwise, he now plays
+            // using his next hand
+            if (player.IsSplit == false)
+            {
+                turnFinishedByPlayer[players.IndexOf(player)] = true;
+            }
+            else
+            {
+                switch (player.CurrentHandType)
+                {
+                    case HandTypes.First:
+                        if (player.SecondBlackJack)
+                        {
+                            turnFinishedByPlayer[players.IndexOf(player)] = true;
+                        }
+                        else
+                        {
+                            player.CurrentHandType = HandTypes.Second;
+                        }
+                        break;
+                    case HandTypes.Second:
+                        turnFinishedByPlayer[players.IndexOf(player)] = true;
+                        break;
+                    default:
+                        throw new Exception(
+                            "Player has an unsupported hand type.");
+                }
+            }
+        }
+
+        /// <summary>
+        /// Performs the "Split" move for the current player.
+        /// This includes adding the animations which shows the first hand splitting
+        /// into two.
+        /// </summary>
+        public void Split()
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+
+            int playerIndex = players.IndexOf(player);
+
+            player.InitializeSecondHand();
+
+            Vector2 sourcePosition = animatedHands[playerIndex].GetCardGameComponent(1).CurrentPosition;
+            Vector2 targetPosition = animatedHands[playerIndex].GetCardGameComponent(0).CurrentPosition +
+                secondHandOffset;
+            // Create an animation moving the top card to the second hand location
+            AnimatedGameComponentAnimation animation = new TransitionGameComponentAnimation(sourcePosition,
+                    targetPosition)
+            {
+                StartTime = DateTime.Now,
+                Duration = TimeSpan.FromSeconds(0.5f)
+            };
+
+            // Actually perform the split
+            player.SplitHand();
+
+            // Add additional chip stack for the second hand
+            betGameComponent.AddChips(playerIndex, player.BetAmount,
+                false, true);
+
+            // Initialize visual representation of the second hand
+            animatedSecondHands[playerIndex] =
+                new BlackjackAnimatedPlayerHandComponent(playerIndex, secondHandOffset,
+                    player.SecondHand, this);
+            Game.Components.Add(animatedSecondHands[playerIndex]);
+
+            AnimatedCardsGameComponent animatedGameComponet = animatedSecondHands[playerIndex].GetCardGameComponent(0);
+            animatedGameComponet.IsFaceDown = false;
+            animatedGameComponet.AddAnimation(animation);
+
+            // Deal an additional cards to each of the new hands
+            TraditionalCard card = dealer.DealCardToHand(player.Hand);
+            AddDealAnimation(card, animatedHands[playerIndex], true, dealDuration,
+                DateTime.Now + animation.EstimatedTimeForAnimationCompletion);
+            card = dealer.DealCardToHand(player.SecondHand);
+            AddDealAnimation(card, animatedSecondHands[playerIndex], true, dealDuration,
+                DateTime.Now + animation.EstimatedTimeForAnimationCompletion +
+                dealDuration);
+        }
+
+        /// <summary>
+        /// Performs the "Double" move for the current player.
+        /// </summary>
+        public void Double()
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+
+            int playerIndex = players.IndexOf(player);
+
+            switch (player.CurrentHandType)
+            {
+                case HandTypes.First:
+                    player.Double = true;
+                    float betAmount = player.BetAmount;
+
+                    if (player.IsSplit)
+                    {
+                        betAmount /= 2f;
+                    }
+
+                    betGameComponent.AddChips(playerIndex, betAmount, false, false);
+                    break;
+                case HandTypes.Second:
+                    player.SecondDouble = true;
+                    if (player.Double == false)
+                    {
+                        // The bet is evenly spread between both hands, add one half
+                        betGameComponent.AddChips(playerIndex, player.BetAmount / 2f,
+                            false, true);
+                    }
+                    else
+                    {
+                        // The first hand's bet is double, add one third of the total
+                        betGameComponent.AddChips(playerIndex, player.BetAmount / 3f,
+                            false, true);
+                    }
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+            Hit();
+            Stand();
+        }
+
+        /// <summary>
+        /// Performs the "Hit" move for the current player.
+        /// </summary>
+        public void Hit()
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+            if (player == null)
+                return;
+
+            int playerIndex = players.IndexOf(player);
+
+            // Draw a card to the appropriate hand
+            switch (player.CurrentHandType)
+            {
+                case HandTypes.First:
+                    TraditionalCard card = dealer.DealCardToHand(player.Hand);
+                    AddDealAnimation(card, animatedHands[playerIndex], true,
+                        dealDuration, DateTime.Now);
+                    break;
+                case HandTypes.Second:
+                    card = dealer.DealCardToHand(player.SecondHand);
+                    AddDealAnimation(card, animatedSecondHands[playerIndex], true,
+                        dealDuration, DateTime.Now);
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+        }
+
+        /// <summary>
+        /// Changes the visiblility of most game buttons.
+        /// </summary>
+        /// <param name="visible">True to make the buttons visible, false to make
+        /// them invisible.</param>
+        void ChangeButtonsVisiblility(bool visible)
+        {
+            buttons["Hit"].Visible = visible;
+            buttons["Stand"].Visible = visible;
+            buttons["Double"].Visible = visible;
+            buttons["Split"].Visible = visible;
+            buttons["Insurance"].Visible = visible;
+        }
+
+        /// <summary>
+        /// Enables or disable most game buttons.
+        /// </summary>
+        /// <param name="enabled">True to enable the buttons , false to 
+        /// disable them.</param>
+        void EnableButtons(bool enabled)
+        {
+            buttons["Hit"].Enabled = enabled;
+            buttons["Stand"].Enabled = enabled;
+            buttons["Double"].Enabled = enabled;
+            buttons["Split"].Enabled = enabled;
+            buttons["Insurance"].Enabled = enabled;
+        }
+
+        /// <summary>
+        /// Add an indication that the player has passed on the current round.
+        /// </summary>
+        /// <param name="indexPlayer">The player's index.</param>
+        public void ShowPlayerPass(int indexPlayer)
+        {
+            // Add animation component
+            AnimatedGameComponent passComponent = new AnimatedGameComponent(this, cardsAssets["pass"])
+            {
+                CurrentPosition = GameTable.PlaceOrder(indexPlayer),
+                Visible = false
+            };
+            Game.Components.Add(passComponent);
+
+            // Hide insurance button only when the first payer passes
+            Action<object> performWhenDone = null;
+            if (indexPlayer == 0)
+            {
+                performWhenDone = HideInshurance;
+            }
+            // Add scale animation for the pass "card"
+            passComponent.AddAnimation(new ScaleGameComponentAnimation(2.0f, 1.0f)
+            {
+                AnimationCycles = 1,
+                PerformBeforeStart = ShowComponent,
+                PerformBeforSartArgs = passComponent,
+                StartTime = DateTime.Now,
+                Duration = TimeSpan.FromSeconds(1),
+                PerformWhenDone = performWhenDone
+            });
+        }
+
+        /// <summary>
+        /// Helper method to hide insurance
+        /// </summary>
+        /// <param name="obj"></param>
+        void HideInshurance(object obj)
+        {
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Shows the insurance button if the first player can afford insurance.
+        /// </summary>
+        /// <param name="sender">The sender.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing 
+        /// the event data.</param>
+        void InsuranceGameRule(object sender, EventArgs e)
+        {
+            BlackjackPlayer player = (BlackjackPlayer)players[0];
+            if (player.Balance >= player.BetAmount / 2)
+            {
+                showInsurance = true;
+            }
+        }
+
+        /// <summary>
+        /// Shows the bust visual cue after the bust rule has been matched.
+        /// </summary>
+        /// <param name="sender">The sender.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing 
+        /// the event data.</param>
+        void BustGameRule(object sender, EventArgs e)
+        {
+            showInsurance = false;
+            BlackjackGameEventArgs args = (e as BlackjackGameEventArgs);
+            BlackjackPlayer player = (BlackjackPlayer)args.Player;
+
+            CueOverPlayerHand(player, "bust", args.Hand, null);
+
+            switch (args.Hand)
+            {
+                case HandTypes.First:
+                    player.Bust = true;
+
+                    if (player.IsSplit && !player.SecondBlackJack)
+                    {
+                        player.CurrentHandType = HandTypes.Second;
+                    }
+                    else
+                    {
+                        turnFinishedByPlayer[players.IndexOf(player)] = true;
+                    }
+                    break;
+                case HandTypes.Second:
+                    player.SecondBust = true;
+                    turnFinishedByPlayer[players.IndexOf(player)] = true;
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+        }
+
+        /// <summary>
+        /// Shows the blackjack visual cue after the blackjack rule has been matched.
+        /// </summary>
+        /// <param name="sender">The sender.</param>
+        /// <param name="e">The <see cref="System.EventArgs"/> instance containing 
+        /// the event data.</param>
+        void BlackJackGameRule(object sender, EventArgs e)
+        {
+            showInsurance = false;
+            BlackjackGameEventArgs args = (e as BlackjackGameEventArgs);
+            BlackjackPlayer player = (BlackjackPlayer)args.Player;
+
+            CueOverPlayerHand(player, "blackjack", args.Hand, null);
+
+            switch (args.Hand)
+            {
+                case HandTypes.First:
+                    player.BlackJack = true;
+
+                    if (player.IsSplit)
+                    {
+                        player.CurrentHandType = HandTypes.Second;
+                    }
+                    else
+                    {
+                        turnFinishedByPlayer[players.IndexOf(player)] = true;
+                    }
+                    break;
+                case HandTypes.Second:
+                    player.SecondBlackJack = true;
+                    if (player.CurrentHandType == HandTypes.Second)
+                    {
+                        turnFinishedByPlayer[players.IndexOf(player)] = true;
+                    }
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+        }
+
+        /// <summary>
+        /// Handles the Click event of the insurance button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Insurance_Click(object sender, EventArgs e)
+        {
+            BlackjackPlayer player = (BlackjackPlayer)GetCurrentPlayer();
+            if (player == null)
+                return;
+            player.IsInsurance = true;
+            player.Balance -= player.BetAmount / 2f;
+            betGameComponent.AddChips(players.IndexOf(player), player.BetAmount / 2, true, false);
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the new game button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void newGame_Click(object sender, EventArgs e)
+        {
+            FinishTurn();
+            StartRound();
+            newGame.Enabled = false;
+            newGame.Visible = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the hit button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Hit_Click(object sender, EventArgs e)
+        {
+            Hit();
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the stand button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Stand_Click(object sender, EventArgs e)
+        {
+            Stand();
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the double button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Double_Click(object sender, EventArgs e)
+        {
+            Double();
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the split button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Split_Click(object sender, EventArgs e)
+        {
+            Split();
+            showInsurance = false;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the back button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">>The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void backButton_Click(object sender, EventArgs e)
+        {
+            // Remove all unnecessary components
+            for (int componentIndex = 0; componentIndex < Game.Components.Count; componentIndex++)
+            {
+                if (!(Game.Components[componentIndex] is ScreenManager))
+                {
+                    Game.Components.RemoveAt(componentIndex);
+                    componentIndex--;
+                }
+            }
+
+            foreach (GameScreen screen in screenManager.GetScreens())
+                screen.ExitScreen();
+
+            screenManager.AddScreen(new BackgroundScreen(), null);
+            screenManager.AddScreen(new MainMenuScreen(), null);
+        }
+    }
+}

+ 754 - 0
CardsStarterKit/Core/Game/Blackjack/Misc/BetGameComponent.cs

@@ -0,0 +1,754 @@
+//-----------------------------------------------------------------------------
+// BetGameComponent.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+
+using System.Text;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using CardsFramework;
+using GameStateManagement;
+using Microsoft.Xna.Framework.Input.Touch;
+
+namespace Blackjack
+{
+    public class BetGameComponent : DrawableGameComponent
+    {
+        List<Player> players;
+        string theme;
+        int[] assetNames = { 5, 25, 100, 500 };
+        Dictionary<int, Texture2D> chipsAssets;
+        Texture2D blankChip;
+        Vector2[] positions;
+        CardsFramework.CardsGame cardGame;
+        SpriteBatch spriteBatch;
+
+        bool isKeyDown = false;
+
+        Button bet;
+        Button clear;
+
+        Vector2 ChipOffset { get; set; }
+        static float insuranceYPosition = 120 * BlackjackGame.HeightScale;
+        static Vector2 secondHandOffset = new Vector2(25 * BlackjackGame.WidthScale,
+            30 * BlackjackGame.HeightScale);
+
+        List<AnimatedGameComponent> currentChipComponent = new List<AnimatedGameComponent>();
+        int currentBet = 0;
+        InputState input;
+        InputHelper inputHelper;
+
+        /// <summary>
+        /// Creates a new instance of the <see cref="BetGameComponent"/> class.
+        /// </summary>
+        /// <param name="players">A list of participating players.</param>
+        /// <param name="input">An instance of 
+        /// <see cref="GameStateManagement.InputState"/> which can be used to 
+        /// check user input.</param>
+        /// <param name="theme">The name of the selcted card theme.</param>
+        /// <param name="cardGame">An instance of <see cref="CardsGame"/> which
+        /// is the current game.</param>
+        public BetGameComponent(List<Player> players, InputState input,
+            string theme, CardsGame cardGame)
+            : base(cardGame.Game)
+        {
+            this.players = players;
+            this.theme = theme;
+            this.cardGame = cardGame;
+            this.input = input;
+            chipsAssets = new Dictionary<int, Texture2D>();
+        }
+
+
+        /// <summary>
+        /// Initializes the component.
+        /// </summary>
+        public override void Initialize()
+        {
+            // Enable tap gesture
+            TouchPanel.EnabledGestures = GestureType.Tap;
+
+            // Get xbox cursor
+            inputHelper = null;
+            for (int componentIndex = 0; componentIndex < Game.Components.Count; componentIndex++)
+            {
+                if (Game.Components[componentIndex] is InputHelper)
+                {
+                    inputHelper = (InputHelper)Game.Components[componentIndex];
+                    break;
+                }
+            }
+
+            // Show mouse
+            Game.IsMouseVisible = true;
+            base.Initialize();
+
+            spriteBatch = new SpriteBatch(Game.GraphicsDevice);
+
+            // Calculate chips position for the chip buttons which allow placing the bet
+            Rectangle size = chipsAssets[assetNames[0]].Bounds;
+
+            Rectangle bounds = spriteBatch.GraphicsDevice.Viewport.TitleSafeArea;
+
+            positions[chipsAssets.Count - 1] = new Vector2(bounds.Left + 10,
+                bounds.Bottom - size.Height - 80);
+            for (int chipIndex = 2; chipIndex <= chipsAssets.Count; chipIndex++)
+            {
+                size = chipsAssets[assetNames[chipsAssets.Count - chipIndex]].Bounds;
+                positions[chipsAssets.Count - chipIndex] = positions[chipsAssets.Count - (chipIndex - 1)] -
+                    new Vector2(0, size.Height + 10);
+            }
+
+            // Initialize bet button
+            bet = new Button("ButtonRegular", "ButtonPressed", input, cardGame)
+            {
+                Bounds = new Rectangle(bounds.Left + 10, bounds.Bottom - 60, 100, 50),
+                Font = cardGame.Font,
+                Text = "Deal",
+            };
+            bet.Click += Bet_Click;
+            Game.Components.Add(bet);
+
+            // Initialize clear button
+            clear = new Button("ButtonRegular", "ButtonPressed", input, cardGame)
+            {
+                Bounds = new Rectangle(bounds.Left + 120, bounds.Bottom - 60, 100, 50),
+                Font = cardGame.Font,
+                Text = "Clear",
+            };
+            clear.Click += Clear_Click;
+            Game.Components.Add(clear);
+            ShowAndEnableButtons(false);
+        }
+
+        /// <summary>
+        /// Load component content.
+        /// </summary>
+        protected override void LoadContent()
+        {
+            // Load blank chip texture
+            blankChip = Game.Content.Load<Texture2D>(
+                string.Format(@"Images\Chips\chip{0}", "White"));
+
+            // Load chip textures
+            int[] assetNames = { 5, 25, 100, 500 };
+            for (int chipIndex = 0; chipIndex < assetNames.Length; chipIndex++)
+            {
+                chipsAssets.Add(assetNames[chipIndex], Game.Content.Load<Texture2D>(
+                    string.Format(@"Images\Chips\chip{0}", assetNames[chipIndex])));
+            }
+            positions = new Vector2[assetNames.Length];
+
+            base.LoadContent();
+        }
+
+        /// <summary>
+        /// Perform update logic related to the component.
+        /// </summary>
+        /// <param name="gameTime">Time elapsed since the last call to 
+        /// this method.</param>
+        public override void Update(GameTime gameTime)
+        {
+            if (players.Count > 0)
+            {
+                // If betting is possible
+                if (((BlackjackCardGame)cardGame).State == BlackjackGameState.Betting &&
+                    !((BlackjackPlayer)players[players.Count - 1]).IsDoneBetting)
+                {
+                    int playerIndex = GetCurrentPlayer();
+
+                    BlackjackPlayer player = (BlackjackPlayer)players[playerIndex];
+
+                    // If the player is an AI player, have it bet
+                    if (player is BlackjackAIPlayer)
+                    {
+                        ShowAndEnableButtons(false);
+                        int bet = ((BlackjackAIPlayer)player).AIBet();
+                        if (bet == 0)
+                        {
+                            Bet_Click(this, EventArgs.Empty);
+                        }
+                        else
+                        {
+                            AddChip(playerIndex, bet, false);
+                        }
+                    }
+                    else
+                    {
+                        // Reveal the input buttons for a human player and handle input
+                        // remember that buttons handle their own imput, so we only check
+                        // for input on the chip buttons
+                        ShowAndEnableButtons(true);
+
+                        HandleInput(Mouse.GetState());
+                    }
+                }
+
+                // Once all players are done betting, advance the game to the dealing stage
+                if (((BlackjackPlayer)players[players.Count - 1]).IsDoneBetting)
+                {
+                    BlackjackCardGame blackjackGame = ((BlackjackCardGame)cardGame);
+
+                    if (!blackjackGame.CheckForRunningAnimations<AnimatedGameComponent>())
+                    {
+                        ShowAndEnableButtons(false);
+                        blackjackGame.State = BlackjackGameState.Dealing;
+
+                        Enabled = false;
+                    }
+                }
+            }
+
+            base.Update(gameTime);
+        }
+
+        /// <summary>
+        /// Gets the player which is currently betting. This is the first player who has
+        /// yet to finish betting.
+        /// </summary>
+        /// <returns>The player which is currently betting.</returns>
+        private int GetCurrentPlayer()
+        {
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                if (!((BlackjackPlayer)players[playerIndex]).IsDoneBetting)
+                {
+                    return playerIndex;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// Handle the input of adding chip on all platform
+        /// </summary>
+        /// <param name="mouseState">Mouse input information.</param>
+        private void HandleInput(MouseState mouseState)
+        {
+            bool isPressed = false;
+            Vector2 position = Vector2.Zero;
+
+            if (mouseState.LeftButton == ButtonState.Pressed)
+            {
+                isPressed = true;
+                position = new Vector2(mouseState.X, mouseState.Y);
+            }
+            else if (inputHelper.IsPressed)
+            {
+                isPressed = true;
+                position = inputHelper.PointPosition;
+            }
+            else if ((input.Gestures.Count > 0) && input.Gestures[0].GestureType == GestureType.Tap)
+            {
+                isPressed = true;
+                position = input.Gestures[0].Position;
+            }
+
+            if (isPressed)
+            {
+                if (!isKeyDown)
+                {
+                    int chipValue = GetIntersectingChipValue(position);
+                    if (chipValue != 0)
+                    {
+                        AddChip(GetCurrentPlayer(), chipValue, false);
+                    }
+                    isKeyDown = true;
+                }
+            }
+            else
+            {
+                isKeyDown = false;
+            }
+        }
+
+        /// <summary>
+        /// Get which chip intersects with a given position.
+        /// </summary>
+        /// <param name="position">The position to check for intersection.</param>
+        /// <returns>The value of the chip intersecting with the specified position, or
+        /// 0 if no chips intersect with the position.</returns>
+        private int GetIntersectingChipValue(Vector2 position)
+        {
+            Rectangle size;
+            // Calculate the bounds of the position
+            Rectangle touchTap = new Rectangle((int)position.X - 1,
+                (int)position.Y - 1, 2, 2);
+            for (int chipIndex = 0; chipIndex < chipsAssets.Count; chipIndex++)
+            {
+                // Calculate the bounds of the asset
+                size = chipsAssets[assetNames[chipIndex]].Bounds;
+                size.X = (int)positions[chipIndex].X;
+                size.Y = (int)positions[chipIndex].Y;
+                if (size.Intersects(touchTap))
+                {
+                    return assetNames[chipIndex];
+                }
+            }
+
+            return 0;
+        }
+
+        /// <summary>
+        /// Draws the component
+        /// </summary>
+        /// <param name="gameTime">Time passed since the last call to 
+        /// this method.</param>
+        public override void Draw(GameTime gameTime)
+        {
+            spriteBatch.Begin();
+
+            // Draws the chips
+            for (int chipIndex = 0; chipIndex < chipsAssets.Count; chipIndex++)
+            {
+                spriteBatch.Draw(chipsAssets[assetNames[chipIndex]], positions[chipIndex],
+                    Color.White);
+            }
+
+            BlackjackPlayer player;
+
+            // Draws the player balance and bet amount
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                BlackJackTable table = (BlackJackTable)cardGame.GameTable;
+                Vector2 position = table[playerIndex] + table.RingOffset +
+                    new Vector2(table.RingTexture.Bounds.Width, 0);
+                player = (BlackjackPlayer)players[playerIndex];
+                spriteBatch.DrawString(cardGame.Font, "$" + player.BetAmount.ToString(),
+                    position, Color.White);
+                spriteBatch.DrawString(cardGame.Font, "$" + player.Balance.ToString(),
+                    position + new Vector2(0, 30), Color.White);
+            }
+
+            spriteBatch.End();
+
+            base.Draw(gameTime);
+        }
+
+        /// <summary>
+        /// Adds the chip to one of the player betting zones.
+        /// </summary>
+        /// <param name="playerIndex">Index of the player for whom to add 
+        /// a chip.</param>
+        /// <param name="chipValue">The value on the chip to add.</param>
+        /// <param name="secondHand">True if this chip is added to the chip pile
+        /// belonging to the player's second hand.</param>
+        public void AddChip(int playerIndex, int chipValue, bool secondHand)
+        {
+            // Only add the chip if the bet is successfully performed
+            if (((BlackjackPlayer)players[playerIndex]).Bet(chipValue))
+            {
+                currentBet += chipValue;
+                // Add chip component
+                AnimatedGameComponent chipComponent = new AnimatedGameComponent(cardGame,
+                    chipsAssets[chipValue])
+                {
+                    Visible = false
+                };
+
+                Game.Components.Add(chipComponent);
+
+                // Calculate the position for the new chip
+                Vector2 position;
+                // Get the proper offset according to the platform (pc, phone, xbox)
+                Vector2 offset = GetChipOffset(playerIndex, secondHand);
+
+                position = cardGame.GameTable[playerIndex] + offset +
+                    new Vector2(-currentChipComponent.Count * 2, currentChipComponent.Count * 1);
+
+
+                // Find the index of the chip
+                int currentChipIndex = 0;
+                for (int chipIndex = 0; chipIndex < chipsAssets.Count; chipIndex++)
+                {
+                    if (assetNames[chipIndex] == chipValue)
+                    {
+                        currentChipIndex = chipIndex;
+                        break;
+                    }
+                }
+
+                // Add transition animation
+                chipComponent.AddAnimation(new TransitionGameComponentAnimation(
+                    positions[currentChipIndex], position)
+                {
+                    Duration = TimeSpan.FromSeconds(1f),
+                    PerformBeforeStart = ShowComponent,
+                    PerformBeforSartArgs = chipComponent,
+                    PerformWhenDone = PlayBetSound
+                });
+
+                // Add flip animation
+                chipComponent.AddAnimation(new FlipGameComponentAnimation()
+                {
+                    Duration = TimeSpan.FromSeconds(1f),
+                    AnimationCycles = 3,
+                });
+
+                currentChipComponent.Add(chipComponent);
+            }
+        }
+
+        /// <summary>
+        /// Helper method to show component
+        /// </summary>
+        /// <param name="obj"></param>
+        void ShowComponent(object obj)
+        {
+            ((AnimatedGameComponent)obj).Visible = true;
+        }
+
+        /// <summary>
+        /// Helper method to play bet sound
+        /// </summary>
+        /// <param name="obj"></param>
+        void PlayBetSound(object obj)
+        {
+            AudioManager.PlaySound("Bet");
+        }
+
+        /// <summary>
+        /// Adds chips to a specified player.
+        /// </summary>
+        /// <param name="playerIndex">Index of the player.</param>
+        /// <param name="amount">The total amount to add.</param>
+        /// <param name="insurance">If true, an insurance chip is added instead of
+        /// regular chips.</param>
+        /// <param name="secondHand">True if chips are to be added to the player's
+        /// second hand.</param>
+        public void AddChips(int playerIndex, float amount, bool insurance, bool secondHand)
+        {
+            if (insurance)
+            {
+                AddInsuranceChipAnimation(amount);
+            }
+            else
+            {
+                AddChips(playerIndex, amount, secondHand);
+            }
+        }
+
+        /// <summary>
+        /// Resets this instance.
+        /// </summary>
+        public void Reset()
+        {
+            ShowAndEnableButtons(true);
+            currentChipComponent.Clear();
+        }
+
+        /// <summary>
+        /// Updates the balance of all players in light of their bets and the dealer's
+        /// hand.
+        /// </summary>
+        /// <param name="dealerPlayer">Player object representing the dealer.</param>
+        public void CalculateBalance(BlackjackPlayer dealerPlayer)
+        {
+            for (int playerIndex = 0; playerIndex < players.Count; playerIndex++)
+            {
+                BlackjackPlayer player = (BlackjackPlayer)players[playerIndex];
+
+                // Calculate first factor, which represents the amount of the first
+                // hand bet which returns to the player
+                float factor = CalculateFactorForHand(dealerPlayer, player,
+                    HandTypes.First);
+
+
+                if (player.IsSplit)
+                {
+                    // Calculate the return factor for the second hand
+                    float factor2 = CalculateFactorForHand(dealerPlayer, player,
+                        HandTypes.Second);
+                    // Calculate the initial bet performed by the player
+                    float initialBet =
+                        player.BetAmount /
+                        ((player.Double ? 2f : 1f) + (player.SecondDouble ? 2f : 1f));
+
+                    float bet1 = initialBet * (player.Double ? 2f : 1f);
+                    float bet2 = initialBet * (player.SecondDouble ? 2f : 1f);
+
+                    // Update the balance in light of the bets and results
+                    player.Balance += bet1 * factor + bet2 * factor2;
+
+                    if (player.IsInsurance && dealerPlayer.BlackJack)
+                    {
+                        player.Balance += initialBet;
+                    }
+                }
+                else
+                {
+                    if (player.IsInsurance && dealerPlayer.BlackJack)
+                    {
+                        player.Balance += player.BetAmount;
+                    }
+
+                    // Update the balance in light of the bets and results
+                    player.Balance += player.BetAmount * factor;
+                }
+
+                player.ClearBet();
+            }
+        }
+
+        /// <summary>
+        /// Adds chips to a specified player in order to reach a specified bet amount.
+        /// </summary>
+        /// <param name="playerIndex">Index of the player to whom the chips are to
+        /// be added.</param>
+        /// <param name="amount">The bet amount to add to the player.</param>
+        /// <param name="secondHand">True to add the chips to the player's second
+        /// hand, false to add them to the first hand.</param>
+        private void AddChips(int playerIndex, float amount, bool secondHand)
+        {
+            int[] assetNames = { 5, 25, 100, 500 };
+
+            while (amount > 0)
+            {
+                if (amount >= 5)
+                {
+                    // Add the chip with the highest possible value
+                    for (int chipIndex = assetNames.Length; chipIndex > 0; chipIndex--)
+                    {
+                        while (assetNames[chipIndex - 1] <= amount)
+                        {
+                            AddChip(playerIndex, assetNames[chipIndex - 1], secondHand);
+                            amount -= assetNames[chipIndex - 1];
+                        }
+                    }
+                }
+                else
+                {
+                    amount = 0;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Animates the placement of an insurance chip on the table.
+        /// </summary>
+        /// <param name="amount">The amount which should appear on the chip.</param>
+        private void AddInsuranceChipAnimation(float amount)
+        {
+            // Add chip component
+            AnimatedGameComponent chipComponent = new AnimatedGameComponent(cardGame, blankChip)
+            {
+                TextColor = Color.Black,
+                Enabled = true,
+                Visible = false
+            };
+
+            Game.Components.Add(chipComponent);
+
+            // Add transition animation
+            chipComponent.AddAnimation(new TransitionGameComponentAnimation(positions[0],
+                new Vector2(GraphicsDevice.Viewport.Width / 2, insuranceYPosition))
+            {
+                PerformBeforeStart = ShowComponent,
+                PerformBeforSartArgs = chipComponent,
+                PerformWhenDone = ShowChipAmountAndPlayBetSound,
+                PerformWhenDoneArgs = new object[] { chipComponent, amount },
+                Duration = TimeSpan.FromSeconds(1),
+                StartTime = DateTime.Now
+            });
+
+            // Add flip animation
+            chipComponent.AddAnimation(new FlipGameComponentAnimation()
+            {
+                Duration = TimeSpan.FromSeconds(1f),
+                AnimationCycles = 3,
+            });
+        }
+
+        /// <summary>
+        /// Helper method to show the amount on the chip and play bet sound
+        /// </summary>
+        /// <param name="obj"></param>
+        void ShowChipAmountAndPlayBetSound(object obj)
+        {
+            object[] arr = (object[])obj;
+            ((AnimatedGameComponent)arr[0]).Text = arr[1].ToString();
+            AudioManager.PlaySound("Bet");
+        }
+
+        /// <summary>
+        /// Gets the offset at which newly added chips should be placed.
+        /// </summary>
+        /// <param name="playerIndex">Index of the player to whom the chip 
+        /// is added.</param>
+        /// <param name="secondHand">True if the chip is added to the player's second
+        /// hand, false otherwise.</param>
+        /// <returns>The offset from the player's position where chips should be
+        /// placed.</returns>
+        private Vector2 GetChipOffset(int playerIndex, bool secondHand)
+        {
+            Vector2 offset = Vector2.Zero;
+
+            BlackJackTable table = ((BlackJackTable)cardGame.GameTable);
+            offset = table.RingOffset +
+                new Vector2(table.RingTexture.Bounds.Width - blankChip.Bounds.Width,
+                    table.RingTexture.Bounds.Height - blankChip.Bounds.Height) / 2f;
+
+            if (secondHand == true)
+            {
+                offset += secondHandOffset;
+            }
+
+            return offset;
+        }
+
+        /// <summary>
+        /// Show and enable, or hide and disable, the bet related buttons.
+        /// </summary>
+        /// <param name="visibleEnabled">True to show and enable the buttons, false
+        /// to hide and disable them.</param>
+        private void ShowAndEnableButtons(bool visibleEnabled)
+        {
+            bet.Visible = visibleEnabled;
+            bet.Enabled = visibleEnabled;
+            clear.Visible = visibleEnabled;
+            clear.Enabled = visibleEnabled;
+        }
+
+        /// <summary>
+        /// Returns a factor which determines how much of a bet a player should get 
+        /// back, according to the outcome of the round.
+        /// </summary>
+        /// <param name="dealerPlayer">The player representing the dealer.</param>
+        /// <param name="player">The player for whom we calculate the factor.</param>
+        /// <param name="currentHand">The hand to calculate the factor for.</param>
+        /// <returns></returns>
+        private float CalculateFactorForHand(BlackjackPlayer dealerPlayer,
+            BlackjackPlayer player, HandTypes currentHand)
+        {
+            float factor;
+
+            bool blackjack, bust, considerAce;
+            int playerValue;
+            player.CalculateValues();
+
+            // Get some player status information according to the desired hand
+            switch (currentHand)
+            {
+                case HandTypes.First:
+                    blackjack = player.BlackJack;
+                    bust = player.Bust;
+                    playerValue = player.FirstValue;
+                    considerAce = player.FirstValueConsiderAce;
+                    break;
+                case HandTypes.Second:
+                    blackjack = player.SecondBlackJack;
+                    bust = player.SecondBust;
+                    playerValue = player.SecondValue;
+                    considerAce = player.SecondValueConsiderAce;
+                    break;
+                default:
+                    throw new Exception(
+                        "Player has an unsupported hand type.");
+            }
+
+            if (considerAce)
+            {
+                playerValue += 10;
+            }
+
+
+            if (bust)
+            {
+                factor = -1; // Bust
+            }
+            else if (dealerPlayer.Bust)
+            {
+                if (blackjack)
+                {
+                    factor = 1.5f; // Win BlackJack
+                }
+                else
+                {
+                    factor = 1; // Win
+                }
+            }
+            else if (dealerPlayer.BlackJack)
+            {
+                if (blackjack)
+                {
+                    factor = 0; // Push BlackJack
+                }
+                else
+                {
+                    factor = -1; // Lose BlackJack
+                }
+            }
+            else if (blackjack)
+            {
+                factor = 1.5f;
+            }
+            else
+            {
+                int dealerValue = dealerPlayer.FirstValue;
+
+                if (dealerPlayer.FirstValueConsiderAce)
+                {
+                    dealerValue += 10;
+                }
+
+                if (playerValue > dealerValue)
+                {
+                    factor = 1; // Win
+                }
+                else if (playerValue < dealerValue)
+                {
+                    factor = -1; // Lose
+                }
+                else
+                {
+                    factor = 0; // Push
+                }
+            }
+            return factor;
+        }
+
+        /// <summary>
+        /// Handles the Click event of the Clear button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Clear_Click(object sender, EventArgs e)
+        {
+            // Clear current player chips from screen and resets his bet
+            currentBet = 0;
+            ((BlackjackPlayer)players[GetCurrentPlayer()]).ClearBet();
+            for (int chipComponentIndex = 0; chipComponentIndex < currentChipComponent.Count; chipComponentIndex++)
+            {
+                Game.Components.Remove(currentChipComponent[chipComponentIndex]);
+            }
+            currentChipComponent.Clear();
+        }
+
+        /// <summary>
+        /// Handles the Click event of the Bet button.
+        /// </summary>
+        /// <param name="sender">The source of the event.</param>
+        /// <param name="e">The 
+        /// <see cref="System.EventArgs"/> instance containing the event data.</param>
+        void Bet_Click(object sender, EventArgs e)
+        {
+            // Finish the bet
+            int playerIndex = GetCurrentPlayer();
+            // If the player did not bet, show that he has passed on this round
+            if (currentBet == 0)
+            {
+                ((BlackjackCardGame)cardGame).ShowPlayerPass(playerIndex);
+            }
+            ((BlackjackPlayer)players[playerIndex]).IsDoneBetting = true;
+            currentChipComponent.Clear();
+            currentBet = 0;
+        }
+    }
+}

+ 70 - 0
CardsStarterKit/Core/Game/Blackjack/Players/BlackjackAIPlayer.cs

@@ -0,0 +1,70 @@
+//-----------------------------------------------------------------------------
+// BlackjackAIPlayer.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CardsFramework;
+
+namespace Blackjack
+{
+    class BlackjackAIPlayer : BlackjackPlayer
+    {
+        static Random random = new Random();
+
+        public event EventHandler Hit;
+        public event EventHandler Stand;
+
+        /// <summary>
+        /// Creates a new instance of the <see cref="BlackjackAIPlayer"/> class.
+        /// </summary>
+        /// <param name="name">The name.</param>
+        /// <param name="game">The game.</param>
+        public BlackjackAIPlayer(string name, CardsGame game)
+            : base(name, game)
+        {
+        }
+
+        /// <summary>
+        /// Performs a move during a round.
+        /// </summary>
+        public void AIPlay()
+        {
+            int value = FirstValue;
+            if (FirstValueConsiderAce && value + 10 <= 21)
+            {
+                value += 10;
+            }
+
+            if (value < 17 && Hit != null)
+            {
+                Hit(this, EventArgs.Empty);
+            }
+            else if (Stand != null)
+            {
+                Stand(this, EventArgs.Empty);
+            }
+        }
+
+        /// <summary>
+        /// Returns the amount which the AI player decides to bet.
+        /// </summary>
+        /// <returns>The AI player's bet.</returns>
+        public int AIBet()
+        {
+            int[] chips = { 0, 5, 25, 100, 500 };
+            int bet = chips[random.Next(0, chips.Length)];
+
+            if (bet < Balance)
+            {
+                return bet;
+            }
+
+            return 0;
+        }
+    }
+}

+ 247 - 0
CardsStarterKit/Core/Game/Blackjack/Players/BlackjackPlayer.cs

@@ -0,0 +1,247 @@
+//-----------------------------------------------------------------------------
+// BlackjackPlayer.cs
+//
+// Microsoft XNA Community Game Platform
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//-----------------------------------------------------------------------------
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using CardsFramework;
+
+
+
+
+namespace Blackjack
+{
+    /// <summary>
+    /// Depicts hands the player can interact with.
+    /// </summary>
+    public enum HandTypes
+    {
+        First,
+        Second
+    }
+
+    public class BlackjackPlayer : Player
+    {
+        // Various fields which depict the state of the players two hands
+        private int firstValue;
+        private bool firstValueConsiderAce;
+
+        private int secondValue;
+        private bool secondValueConsiderAce;
+
+        public bool Bust { get; set; }
+        public bool SecondBust { get; set; }
+        public bool BlackJack { get; set; }
+        public bool SecondBlackJack { get; set; }
+        public bool Double { get; set; }
+        public bool SecondDouble { get; set; }
+
+        public bool IsSplit { get; set; }
+        public Hand SecondHand { get; private set; }
+
+        /// <summary>
+        /// The type of hand that the player is currently interacting with.
+        /// </summary>
+        public HandTypes CurrentHandType { get; set; }
+
+        /// <summary>
+        /// Returns the hand that the player is currently interacting with.
+        /// </summary>
+        public Hand CurrentHand
+        {
+            get
+            {
+                switch (CurrentHandType)
+                {
+                    case HandTypes.First:
+                        return Hand;
+                    case HandTypes.Second:
+                        return SecondHand;
+                    default:
+                        throw new Exception("No hand to return");
+                }
+            }
+        }
+
+        public int FirstValue
+        {
+            get { return firstValue; }
+        }
+        public bool FirstValueConsiderAce
+        {
+            get { return firstValueConsiderAce; }
+        }
+
+        public int SecondValue
+        {
+            get { return secondValue; }
+        }
+        public bool SecondValueConsiderAce
+        {
+            get { return secondValueConsiderAce; }
+        }
+
+        public bool MadeBet { get { return BetAmount > 0; } }
+        public bool IsDoneBetting { get; set; }
+        public float Balance { get; set; }
+        public float BetAmount { get; private set; }
+        public bool IsInsurance { get; set; }
+
+        /// <summary>
+        /// Creates a new blackjack player instance.
+        /// </summary>
+        /// <param name="name">The player's name.</param>
+        /// <param name="game">The game associated with the player.</param>
+        public BlackjackPlayer(string name, CardsFramework.CardsGame game)
+            : base(name, game)
+        {
+            Balance = 500;
+            CurrentHandType = HandTypes.First;
+        }
+
+        /// <summary>
+        /// Calculates the value represented by a specified hand.
+        /// </summary>
+        /// <param name="hand">The hand for which to calculate the value.</param>
+        /// <param name="game">The associated game.</param>
+        /// <param name="value">Will contain the hand's value. If the hand has two
+        /// possible values due to it containing an ace, this will be the lower
+        /// value.</param>
+        /// <param name="considerAce">Whether or not an ace can be considered to
+        /// make the hand have an alternative value.</param>
+        private static void CalulateValue(Hand hand, CardsFramework.CardsGame game,
+            out int value, out bool considerAce)
+        {
+            value = 0;
+            considerAce = false;
+
+            for (int cardIndex = 0; cardIndex < hand.Count; cardIndex++)
+            {
+                value += game.CardValue(hand[cardIndex]);
+
+                if (hand[cardIndex].Value == CardValue.Ace)
+                {
+                    considerAce = true;
+                }
+            }
+
+            if (considerAce && value + 10 > 21)
+            {
+                considerAce = false;
+            }
+        }
+
+        /// <summary>
+        /// Bets a specified amount of money, if the player's balance permits it.
+        /// </summary>
+        /// <param name="amount">The amount to bet.</param>
+        /// <returns>True if the player has enough money to perform the bet, false
+        /// otherwise.</returns>
+        /// <remarks>The player's bet amount and balance are only updated if this
+        /// method returns true.</remarks>
+        public bool Bet(float amount)
+        {
+            if (amount > Balance)
+            {
+                return false;
+            }
+            BetAmount += amount;
+            Balance -= amount;
+            return true;
+        }
+
+        /// <summary>
+        /// Resets the player's bet to 0, returning the current bet amount to 
+        /// the player's balance.
+        /// </summary>
+        public void ClearBet()
+        {
+            Balance += BetAmount;
+            BetAmount = 0;
+        }
+
+        /// <summary>
+        /// Calculates the values of the player's two hands.
+        /// </summary>
+        public void CalculateValues()
+        {
+            CalulateValue(Hand, Game, out firstValue, out firstValueConsiderAce);
+
+            if (SecondHand != null)
+            {
+                CalulateValue(SecondHand, Game, out secondValue,
+                    out secondValueConsiderAce);
+            }
+        }
+
+        /// <summary>
+        /// Reset's the player's various state fields.
+        /// </summary>
+        public void ResetValues()
+        {
+            BlackJack = false;
+            SecondBlackJack = false;
+            Bust = false;
+            SecondBust = false;
+            Double = false;
+            SecondDouble = false;
+            firstValue = 0;
+            firstValueConsiderAce = false;
+            IsSplit = false;
+            secondValue = 0;
+            secondValueConsiderAce = false;
+            BetAmount = 0;
+            IsDoneBetting = false;
+            IsInsurance = false;
+            CurrentHandType = HandTypes.First;
+        }
+
+        /// <summary>
+        /// Initializes the player's second hand.
+        /// </summary>
+        public void InitializeSecondHand()
+        {
+            SecondHand = new Hand();
+        }
+
+        /// <summary>
+        /// Splits the player's current hand into two hands as per the blackjack rules.
+        /// </summary>
+        /// <exception cref="InvalidOperationException">Thrown if performing a split
+        /// is not legal for the current player status.</exception>
+        public void SplitHand()
+        {
+            if (SecondHand == null)
+            {
+                throw new InvalidOperationException("Second hand is not initialized.");
+            }
+
+            if (IsSplit == true)
+            {
+                throw new InvalidOperationException(
+                    "A hand cannot be split more than once.");
+            }
+
+            if (Hand.Count != 2)
+            {
+                throw new InvalidOperationException(
+                    "You must have two cards to perform a split.");
+            }
+
+            if (Hand[0].Value != Hand[1].Value)
+            {
+                throw new InvalidOperationException(
+                    "You can only split when both cards are of identical value.");
+            }
+
+            IsSplit = true;
+
+            // Move the top card in the first hand to the second hand
+            Hand[1].MoveToHand(SecondHand);
+        } 
+    }
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно