@mnbroatch/boardgame.io 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (296) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +102 -0
  3. package/ai/package.json +7 -0
  4. package/client/package.json +7 -0
  5. package/core/package.json +7 -0
  6. package/debug/package.json +7 -0
  7. package/dist/boardgameio.es.js +14238 -0
  8. package/dist/boardgameio.js +14277 -0
  9. package/dist/boardgameio.min.js +16 -0
  10. package/dist/cjs/Debug-9d141c06.js +9586 -0
  11. package/dist/cjs/ai-e0e8a768.js +377 -0
  12. package/dist/cjs/ai.js +20 -0
  13. package/dist/cjs/client-76dec77b.js +258 -0
  14. package/dist/cjs/client-a22d7500.js +524 -0
  15. package/dist/cjs/client.js +26 -0
  16. package/dist/cjs/core.js +52 -0
  17. package/dist/cjs/debug.js +18 -0
  18. package/dist/cjs/filter-player-view-bb02e2f6.js +89 -0
  19. package/dist/cjs/initialize-267fcd69.js +61 -0
  20. package/dist/cjs/internal.js +25 -0
  21. package/dist/cjs/master-2904879d.js +320 -0
  22. package/dist/cjs/master.js +18 -0
  23. package/dist/cjs/multiplayer.js +23 -0
  24. package/dist/cjs/plugin-random-7425844d.js +229 -0
  25. package/dist/cjs/plugins.js +59 -0
  26. package/dist/cjs/react-native.js +182 -0
  27. package/dist/cjs/react.js +727 -0
  28. package/dist/cjs/reducer-16eec232.js +1203 -0
  29. package/dist/cjs/server.js +4087 -0
  30. package/dist/cjs/socketio-7a0837eb.js +478 -0
  31. package/dist/cjs/testing.js +30 -0
  32. package/dist/cjs/transport-b1874dfa.js +37 -0
  33. package/dist/cjs/turn-order-b2ff8740.js +1136 -0
  34. package/dist/cjs/util-fcfd8fb8.js +140 -0
  35. package/dist/esm/Debug-0141fe2d.js +9577 -0
  36. package/dist/esm/ai-5c06e761.js +371 -0
  37. package/dist/esm/ai.js +8 -0
  38. package/dist/esm/client-2e653027.js +522 -0
  39. package/dist/esm/client-5f57c3f2.js +255 -0
  40. package/dist/esm/client.js +16 -0
  41. package/dist/esm/core.js +40 -0
  42. package/dist/esm/debug.js +10 -0
  43. package/dist/esm/filter-player-view-2c6cc96f.js +87 -0
  44. package/dist/esm/initialize-11d626ca.js +59 -0
  45. package/dist/esm/internal.js +10 -0
  46. package/dist/esm/master-fa8f2e43.js +318 -0
  47. package/dist/esm/master.js +10 -0
  48. package/dist/esm/multiplayer.js +14 -0
  49. package/dist/esm/plugin-random-087f861e.js +226 -0
  50. package/dist/esm/plugins.js +55 -0
  51. package/dist/esm/react-native.js +173 -0
  52. package/dist/esm/react.js +716 -0
  53. package/dist/esm/reducer-c46da7e5.js +1198 -0
  54. package/dist/esm/socketio-c22ffa65.js +455 -0
  55. package/dist/esm/testing.js +26 -0
  56. package/dist/esm/transport-ce07b771.js +35 -0
  57. package/dist/esm/turn-order-376d315e.js +1091 -0
  58. package/dist/esm/util-b6147cef.js +135 -0
  59. package/dist/types/packages/ai.d.ts +5 -0
  60. package/dist/types/packages/client.d.ts +3 -0
  61. package/dist/types/packages/core.d.ts +5 -0
  62. package/dist/types/packages/debug.d.ts +2 -0
  63. package/dist/types/packages/internal.d.ts +8 -0
  64. package/dist/types/packages/master.d.ts +2 -0
  65. package/dist/types/packages/multiplayer.d.ts +3 -0
  66. package/dist/types/packages/plugins.d.ts +3 -0
  67. package/dist/types/packages/react-native.d.ts +2 -0
  68. package/dist/types/packages/react.d.ts +3 -0
  69. package/dist/types/packages/server.d.ts +6 -0
  70. package/dist/types/packages/testing.d.ts +1 -0
  71. package/dist/types/src/ai/ai.d.ts +53 -0
  72. package/dist/types/src/ai/ai.test.d.ts +1 -0
  73. package/dist/types/src/ai/bot.d.ts +40 -0
  74. package/dist/types/src/ai/mcts-bot.d.ts +60 -0
  75. package/dist/types/src/ai/random-bot.d.ts +27 -0
  76. package/dist/types/src/client/client.d.ts +104 -0
  77. package/dist/types/src/client/client.test.d.ts +1 -0
  78. package/dist/types/src/client/debug/tests/debug.test.d.ts +1 -0
  79. package/dist/types/src/client/manager.d.ts +61 -0
  80. package/dist/types/src/client/react.d.ts +75 -0
  81. package/dist/types/src/client/react.ssr.test.d.ts +4 -0
  82. package/dist/types/src/client/react.test.d.ts +1 -0
  83. package/dist/types/src/client/transport/dummy.d.ts +18 -0
  84. package/dist/types/src/client/transport/local.d.ts +59 -0
  85. package/dist/types/src/client/transport/local.test.d.ts +1 -0
  86. package/dist/types/src/client/transport/socketio.d.ts +45 -0
  87. package/dist/types/src/client/transport/socketio.test.d.ts +1 -0
  88. package/dist/types/src/client/transport/transport.d.ts +50 -0
  89. package/dist/types/src/client/transport/transport.test.d.ts +1 -0
  90. package/dist/types/src/core/action-creators.d.ts +144 -0
  91. package/dist/types/src/core/action-types.d.ts +10 -0
  92. package/dist/types/src/core/backwards-compatibility.d.ts +12 -0
  93. package/dist/types/src/core/constants.d.ts +6 -0
  94. package/dist/types/src/core/errors.d.ts +15 -0
  95. package/dist/types/src/core/flow.d.ts +28 -0
  96. package/dist/types/src/core/flow.test.d.ts +1 -0
  97. package/dist/types/src/core/game-methods.d.ts +9 -0
  98. package/dist/types/src/core/game.d.ts +26 -0
  99. package/dist/types/src/core/game.test.d.ts +1 -0
  100. package/dist/types/src/core/initialize.d.ts +9 -0
  101. package/dist/types/src/core/logger.d.ts +2 -0
  102. package/dist/types/src/core/player-view.d.ts +7 -0
  103. package/dist/types/src/core/player-view.test.d.ts +1 -0
  104. package/dist/types/src/core/reducer.d.ts +155 -0
  105. package/dist/types/src/core/reducer.test.d.ts +1 -0
  106. package/dist/types/src/core/turn-order.d.ts +179 -0
  107. package/dist/types/src/core/turn-order.test.d.ts +8 -0
  108. package/dist/types/src/lobby/client.d.ts +194 -0
  109. package/dist/types/src/lobby/client.test.d.ts +1 -0
  110. package/dist/types/src/lobby/connection.d.ts +44 -0
  111. package/dist/types/src/lobby/connection.test.d.ts +1 -0
  112. package/dist/types/src/lobby/create-match-form.d.ts +26 -0
  113. package/dist/types/src/lobby/login-form.d.ts +23 -0
  114. package/dist/types/src/lobby/match-instance.d.ts +31 -0
  115. package/dist/types/src/lobby/react.d.ts +113 -0
  116. package/dist/types/src/lobby/react.ssr.test.d.ts +4 -0
  117. package/dist/types/src/lobby/react.test.d.ts +1 -0
  118. package/dist/types/src/master/filter-player-view.d.ts +96 -0
  119. package/dist/types/src/master/filter-player-view.test.d.ts +1 -0
  120. package/dist/types/src/master/master.d.ts +94 -0
  121. package/dist/types/src/master/master.test.d.ts +1 -0
  122. package/dist/types/src/plugins/events/events.d.ts +54 -0
  123. package/dist/types/src/plugins/events/events.test.d.ts +1 -0
  124. package/dist/types/src/plugins/main.d.ts +75 -0
  125. package/dist/types/src/plugins/main.test.d.ts +1 -0
  126. package/dist/types/src/plugins/plugin-events.d.ts +5 -0
  127. package/dist/types/src/plugins/plugin-immer.d.ts +7 -0
  128. package/dist/types/src/plugins/plugin-immer.test.d.ts +1 -0
  129. package/dist/types/src/plugins/plugin-log.d.ts +14 -0
  130. package/dist/types/src/plugins/plugin-log.test.d.ts +1 -0
  131. package/dist/types/src/plugins/plugin-player.d.ts +29 -0
  132. package/dist/types/src/plugins/plugin-player.test.d.ts +1 -0
  133. package/dist/types/src/plugins/plugin-random.d.ts +4 -0
  134. package/dist/types/src/plugins/plugin-serializable.d.ts +7 -0
  135. package/dist/types/src/plugins/plugin-serializable.test.d.ts +1 -0
  136. package/dist/types/src/plugins/random/random.alea.d.ts +19 -0
  137. package/dist/types/src/plugins/random/random.d.ts +54 -0
  138. package/dist/types/src/plugins/random/random.test.d.ts +1 -0
  139. package/dist/types/src/server/api.d.ts +13 -0
  140. package/dist/types/src/server/api.test.d.ts +1 -0
  141. package/dist/types/src/server/auth.d.ts +38 -0
  142. package/dist/types/src/server/auth.test.d.ts +1 -0
  143. package/dist/types/src/server/cors.d.ts +4 -0
  144. package/dist/types/src/server/cors.test.d.ts +1 -0
  145. package/dist/types/src/server/db/base.d.ts +192 -0
  146. package/dist/types/src/server/db/flatfile.d.ts +44 -0
  147. package/dist/types/src/server/db/flatfile.test.d.ts +1 -0
  148. package/dist/types/src/server/db/index.d.ts +4 -0
  149. package/dist/types/src/server/db/index.test.d.ts +1 -0
  150. package/dist/types/src/server/db/inmemory.d.ts +43 -0
  151. package/dist/types/src/server/db/inmemory.test.d.ts +1 -0
  152. package/dist/types/src/server/db/localstorage.d.ts +7 -0
  153. package/dist/types/src/server/db/localstorage.test.d.ts +1 -0
  154. package/dist/types/src/server/index.d.ts +68 -0
  155. package/dist/types/src/server/index.test.d.ts +1 -0
  156. package/dist/types/src/server/transport/pubsub/generic-pub-sub.d.ts +6 -0
  157. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.d.ts +7 -0
  158. package/dist/types/src/server/transport/pubsub/in-memory-pub-sub.test.d.ts +1 -0
  159. package/dist/types/src/server/transport/socketio-simultaneous.test.d.ts +1 -0
  160. package/dist/types/src/server/transport/socketio.d.ts +65 -0
  161. package/dist/types/src/server/transport/socketio.test.d.ts +1 -0
  162. package/dist/types/src/server/util.d.ts +35 -0
  163. package/dist/types/src/testing/mock-random.d.ts +15 -0
  164. package/dist/types/src/testing/mock-random.test.d.ts +1 -0
  165. package/dist/types/src/types.d.ts +387 -0
  166. package/internal/package.json +7 -0
  167. package/master/package.json +7 -0
  168. package/multiplayer/package.json +7 -0
  169. package/package.json +211 -0
  170. package/plugins/package.json +7 -0
  171. package/react/package.json +7 -0
  172. package/react-native/package.json +7 -0
  173. package/server/package.json +6 -0
  174. package/src/ai/ai.test.ts +433 -0
  175. package/src/ai/ai.ts +84 -0
  176. package/src/ai/bot.ts +122 -0
  177. package/src/ai/mcts-bot.ts +331 -0
  178. package/src/ai/random-bot.ts +20 -0
  179. package/src/client/client.test.ts +993 -0
  180. package/src/client/client.ts +588 -0
  181. package/src/client/debug/Debug.svelte +239 -0
  182. package/src/client/debug/Menu.svelte +65 -0
  183. package/src/client/debug/ai/AI.svelte +215 -0
  184. package/src/client/debug/ai/Options.svelte +48 -0
  185. package/src/client/debug/info/Info.svelte +22 -0
  186. package/src/client/debug/info/Item.svelte +24 -0
  187. package/src/client/debug/log/Log.svelte +157 -0
  188. package/src/client/debug/log/LogEvent.svelte +149 -0
  189. package/src/client/debug/log/LogMetadata.svelte +7 -0
  190. package/src/client/debug/log/PhaseMarker.svelte +27 -0
  191. package/src/client/debug/log/TurnMarker.svelte +23 -0
  192. package/src/client/debug/main/ClientSwitcher.svelte +59 -0
  193. package/src/client/debug/main/Controls.svelte +58 -0
  194. package/src/client/debug/main/Hotkey.svelte +84 -0
  195. package/src/client/debug/main/InteractiveFunction.svelte +85 -0
  196. package/src/client/debug/main/Main.svelte +121 -0
  197. package/src/client/debug/main/Move.svelte +68 -0
  198. package/src/client/debug/main/PlayerInfo.svelte +70 -0
  199. package/src/client/debug/mcts/Action.svelte +22 -0
  200. package/src/client/debug/mcts/MCTS.svelte +78 -0
  201. package/src/client/debug/mcts/Table.svelte +98 -0
  202. package/src/client/debug/tests/JSONTree.mock.svelte +3 -0
  203. package/src/client/debug/tests/debug.test.ts +183 -0
  204. package/src/client/debug/utils/shortcuts.js +50 -0
  205. package/src/client/debug/utils/shortcuts.test.js +49 -0
  206. package/src/client/manager.ts +177 -0
  207. package/src/client/react-native.js +136 -0
  208. package/src/client/react-native.test.js +229 -0
  209. package/src/client/react.ssr.test.tsx +24 -0
  210. package/src/client/react.test.tsx +213 -0
  211. package/src/client/react.tsx +192 -0
  212. package/src/client/transport/dummy.ts +19 -0
  213. package/src/client/transport/local.test.ts +353 -0
  214. package/src/client/transport/local.ts +230 -0
  215. package/src/client/transport/socketio.test.ts +328 -0
  216. package/src/client/transport/socketio.ts +210 -0
  217. package/src/client/transport/transport.test.ts +27 -0
  218. package/src/client/transport/transport.ts +95 -0
  219. package/src/core/action-creators.ts +159 -0
  220. package/src/core/action-types.ts +18 -0
  221. package/src/core/backwards-compatibility.ts +23 -0
  222. package/src/core/constants.ts +6 -0
  223. package/src/core/errors.ts +35 -0
  224. package/src/core/flow.test.ts +2433 -0
  225. package/src/core/flow.ts +897 -0
  226. package/src/core/game-methods.ts +9 -0
  227. package/src/core/game.test.ts +286 -0
  228. package/src/core/game.ts +114 -0
  229. package/src/core/initialize.ts +77 -0
  230. package/src/core/logger.test.js +90 -0
  231. package/src/core/logger.ts +18 -0
  232. package/src/core/player-view.test.ts +50 -0
  233. package/src/core/player-view.ts +39 -0
  234. package/src/core/reducer.test.ts +991 -0
  235. package/src/core/reducer.ts +532 -0
  236. package/src/core/turn-order.test.ts +1123 -0
  237. package/src/core/turn-order.ts +473 -0
  238. package/src/lobby/client.test.ts +385 -0
  239. package/src/lobby/client.ts +358 -0
  240. package/src/lobby/connection.test.ts +207 -0
  241. package/src/lobby/connection.ts +162 -0
  242. package/src/lobby/create-match-form.tsx +122 -0
  243. package/src/lobby/login-form.tsx +75 -0
  244. package/src/lobby/match-instance.tsx +135 -0
  245. package/src/lobby/react.ssr.test.tsx +22 -0
  246. package/src/lobby/react.test.tsx +594 -0
  247. package/src/lobby/react.tsx +402 -0
  248. package/src/master/filter-player-view.test.ts +381 -0
  249. package/src/master/filter-player-view.ts +102 -0
  250. package/src/master/master.test.ts +1068 -0
  251. package/src/master/master.ts +492 -0
  252. package/src/plugins/events/events.test.ts +108 -0
  253. package/src/plugins/events/events.ts +209 -0
  254. package/src/plugins/main.test.ts +411 -0
  255. package/src/plugins/main.ts +314 -0
  256. package/src/plugins/plugin-events.ts +40 -0
  257. package/src/plugins/plugin-immer.test.ts +86 -0
  258. package/src/plugins/plugin-immer.ts +37 -0
  259. package/src/plugins/plugin-log.test.ts +37 -0
  260. package/src/plugins/plugin-log.ts +40 -0
  261. package/src/plugins/plugin-player.test.ts +172 -0
  262. package/src/plugins/plugin-player.ts +100 -0
  263. package/src/plugins/plugin-random.ts +40 -0
  264. package/src/plugins/plugin-serializable.test.ts +40 -0
  265. package/src/plugins/plugin-serializable.ts +55 -0
  266. package/src/plugins/random/random.alea.ts +109 -0
  267. package/src/plugins/random/random.test.ts +167 -0
  268. package/src/plugins/random/random.ts +198 -0
  269. package/src/server/api.test.ts +1699 -0
  270. package/src/server/api.ts +527 -0
  271. package/src/server/auth.test.ts +275 -0
  272. package/src/server/auth.ts +89 -0
  273. package/src/server/cors.test.ts +121 -0
  274. package/src/server/cors.ts +7 -0
  275. package/src/server/db/base.ts +296 -0
  276. package/src/server/db/flatfile.test.ts +221 -0
  277. package/src/server/db/flatfile.ts +228 -0
  278. package/src/server/db/index.test.ts +8 -0
  279. package/src/server/db/index.ts +12 -0
  280. package/src/server/db/inmemory.test.ts +143 -0
  281. package/src/server/db/inmemory.ts +143 -0
  282. package/src/server/db/localstorage.test.ts +73 -0
  283. package/src/server/db/localstorage.ts +44 -0
  284. package/src/server/index.test.ts +265 -0
  285. package/src/server/index.ts +175 -0
  286. package/src/server/transport/pubsub/generic-pub-sub.ts +11 -0
  287. package/src/server/transport/pubsub/in-memory-pub-sub.test.ts +47 -0
  288. package/src/server/transport/pubsub/in-memory-pub-sub.ts +28 -0
  289. package/src/server/transport/socketio-simultaneous.test.ts +603 -0
  290. package/src/server/transport/socketio.test.ts +303 -0
  291. package/src/server/transport/socketio.ts +279 -0
  292. package/src/server/util.ts +85 -0
  293. package/src/testing/mock-random.test.ts +45 -0
  294. package/src/testing/mock-random.ts +27 -0
  295. package/src/types.ts +511 -0
  296. package/testing/package.json +7 -0
@@ -0,0 +1,473 @@
1
+ /*
2
+ * Copyright 2017 The boardgame.io Authors
3
+ *
4
+ * Use of this source code is governed by a MIT-style
5
+ * license that can be found in the LICENSE file or at
6
+ * https://opensource.org/licenses/MIT.
7
+ */
8
+
9
+ import * as logging from './logger';
10
+ import * as plugin from '../plugins/main';
11
+ import type {
12
+ Ctx,
13
+ StageArg,
14
+ ActivePlayersArg,
15
+ PlayerID,
16
+ State,
17
+ TurnConfig,
18
+ FnContext,
19
+ } from '../types';
20
+ import { supportDeprecatedMoveLimit } from './backwards-compatibility';
21
+
22
+ export function SetActivePlayers(ctx: Ctx, arg: ActivePlayersArg): Ctx {
23
+ let activePlayers: typeof ctx.activePlayers = {};
24
+ let _prevActivePlayers: typeof ctx._prevActivePlayers = [];
25
+ let _nextActivePlayers: ActivePlayersArg | null = null;
26
+ let _activePlayersMinMoves = {};
27
+ let _activePlayersMaxMoves = {};
28
+
29
+ if (Array.isArray(arg)) {
30
+ // support a simple array of player IDs as active players
31
+ const value = {};
32
+ arg.forEach((v) => (value[v] = Stage.NULL));
33
+ activePlayers = value;
34
+ } else {
35
+ // process active players argument object
36
+
37
+ // stages previously did not enforce minMoves, this behaviour is kept intentionally
38
+ supportDeprecatedMoveLimit(arg);
39
+
40
+ if (arg.next) {
41
+ _nextActivePlayers = arg.next;
42
+ }
43
+
44
+ if (arg.revert) {
45
+ _prevActivePlayers = [
46
+ ...ctx._prevActivePlayers,
47
+ {
48
+ activePlayers: ctx.activePlayers,
49
+ _activePlayersMinMoves: ctx._activePlayersMinMoves,
50
+ _activePlayersMaxMoves: ctx._activePlayersMaxMoves,
51
+ _activePlayersNumMoves: ctx._activePlayersNumMoves,
52
+ },
53
+ ];
54
+ }
55
+
56
+ if (arg.currentPlayer !== undefined) {
57
+ ApplyActivePlayerArgument(
58
+ activePlayers,
59
+ _activePlayersMinMoves,
60
+ _activePlayersMaxMoves,
61
+ ctx.currentPlayer,
62
+ arg.currentPlayer
63
+ );
64
+ }
65
+
66
+ if (arg.others !== undefined) {
67
+ for (let i = 0; i < ctx.playOrder.length; i++) {
68
+ const id = ctx.playOrder[i];
69
+ if (id !== ctx.currentPlayer) {
70
+ ApplyActivePlayerArgument(
71
+ activePlayers,
72
+ _activePlayersMinMoves,
73
+ _activePlayersMaxMoves,
74
+ id,
75
+ arg.others
76
+ );
77
+ }
78
+ }
79
+ }
80
+
81
+ if (arg.all !== undefined) {
82
+ for (let i = 0; i < ctx.playOrder.length; i++) {
83
+ const id = ctx.playOrder[i];
84
+ ApplyActivePlayerArgument(
85
+ activePlayers,
86
+ _activePlayersMinMoves,
87
+ _activePlayersMaxMoves,
88
+ id,
89
+ arg.all
90
+ );
91
+ }
92
+ }
93
+
94
+ if (arg.value) {
95
+ for (const id in arg.value) {
96
+ ApplyActivePlayerArgument(
97
+ activePlayers,
98
+ _activePlayersMinMoves,
99
+ _activePlayersMaxMoves,
100
+ id,
101
+ arg.value[id]
102
+ );
103
+ }
104
+ }
105
+
106
+ if (arg.minMoves) {
107
+ for (const id in activePlayers) {
108
+ if (_activePlayersMinMoves[id] === undefined) {
109
+ _activePlayersMinMoves[id] = arg.minMoves;
110
+ }
111
+ }
112
+ }
113
+
114
+ if (arg.maxMoves) {
115
+ for (const id in activePlayers) {
116
+ if (_activePlayersMaxMoves[id] === undefined) {
117
+ _activePlayersMaxMoves[id] = arg.maxMoves;
118
+ }
119
+ }
120
+ }
121
+ }
122
+
123
+ if (Object.keys(activePlayers).length === 0) {
124
+ activePlayers = null;
125
+ }
126
+
127
+ if (Object.keys(_activePlayersMinMoves).length === 0) {
128
+ _activePlayersMinMoves = null;
129
+ }
130
+
131
+ if (Object.keys(_activePlayersMaxMoves).length === 0) {
132
+ _activePlayersMaxMoves = null;
133
+ }
134
+
135
+ const _activePlayersNumMoves = {};
136
+ for (const id in activePlayers) {
137
+ _activePlayersNumMoves[id] = 0;
138
+ }
139
+
140
+ return {
141
+ ...ctx,
142
+ activePlayers,
143
+ _activePlayersMinMoves,
144
+ _activePlayersMaxMoves,
145
+ _activePlayersNumMoves,
146
+ _prevActivePlayers,
147
+ _nextActivePlayers,
148
+ };
149
+ }
150
+
151
+ /**
152
+ * Update activePlayers, setting it to previous, next or null values
153
+ * when it becomes empty.
154
+ * @param ctx
155
+ */
156
+ export function UpdateActivePlayersOnceEmpty(ctx: Ctx) {
157
+ let {
158
+ activePlayers,
159
+ _activePlayersMinMoves,
160
+ _activePlayersMaxMoves,
161
+ _activePlayersNumMoves,
162
+ _prevActivePlayers,
163
+ _nextActivePlayers,
164
+ } = ctx;
165
+
166
+ if (activePlayers && Object.keys(activePlayers).length === 0) {
167
+ if (_nextActivePlayers) {
168
+ ctx = SetActivePlayers(ctx, _nextActivePlayers);
169
+ ({
170
+ activePlayers,
171
+ _activePlayersMinMoves,
172
+ _activePlayersMaxMoves,
173
+ _activePlayersNumMoves,
174
+ _prevActivePlayers,
175
+ } = ctx);
176
+ } else if (_prevActivePlayers.length > 0) {
177
+ const lastIndex = _prevActivePlayers.length - 1;
178
+ ({
179
+ activePlayers,
180
+ _activePlayersMinMoves,
181
+ _activePlayersMaxMoves,
182
+ _activePlayersNumMoves,
183
+ } = _prevActivePlayers[lastIndex]);
184
+ _prevActivePlayers = _prevActivePlayers.slice(0, lastIndex);
185
+ } else {
186
+ activePlayers = null;
187
+ _activePlayersMinMoves = null;
188
+ _activePlayersMaxMoves = null;
189
+ }
190
+ }
191
+
192
+ return {
193
+ ...ctx,
194
+ activePlayers,
195
+ _activePlayersMinMoves,
196
+ _activePlayersMaxMoves,
197
+ _activePlayersNumMoves,
198
+ _prevActivePlayers,
199
+ };
200
+ }
201
+
202
+ /**
203
+ * Apply an active player argument to the given player ID
204
+ * @param {Object} activePlayers
205
+ * @param {Object} _activePlayersMinMoves
206
+ * @param {Object} _activePlayersMaxMoves
207
+ * @param {String} playerID The player to apply the parameter to
208
+ * @param {(String|Object)} arg An active player argument
209
+ */
210
+ function ApplyActivePlayerArgument(
211
+ activePlayers: Ctx['activePlayers'],
212
+ _activePlayersMinMoves: Ctx['_activePlayersMinMoves'],
213
+ _activePlayersMaxMoves: Ctx['_activePlayersMaxMoves'],
214
+ playerID: PlayerID,
215
+ arg: StageArg
216
+ ) {
217
+ if (typeof arg !== 'object' || arg === Stage.NULL) {
218
+ arg = { stage: arg as string | null };
219
+ }
220
+
221
+ if (arg.stage !== undefined) {
222
+ // stages previously did not enforce minMoves, this behaviour is kept intentionally
223
+ supportDeprecatedMoveLimit(arg);
224
+
225
+ activePlayers[playerID] = arg.stage;
226
+ if (arg.minMoves) _activePlayersMinMoves[playerID] = arg.minMoves;
227
+ if (arg.maxMoves) _activePlayersMaxMoves[playerID] = arg.maxMoves;
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Converts a playOrderPos index into its value in playOrder.
233
+ * @param {Array} playOrder - An array of player ID's.
234
+ * @param {number} playOrderPos - An index into the above.
235
+ */
236
+ function getCurrentPlayer(
237
+ playOrder: Ctx['playOrder'],
238
+ playOrderPos: Ctx['playOrderPos']
239
+ ) {
240
+ // convert to string in case playOrder is set to number[]
241
+ return playOrder[playOrderPos] + '';
242
+ }
243
+
244
+ /**
245
+ * Called at the start of a turn to initialize turn order state.
246
+ *
247
+ * TODO: This is called inside StartTurn, which is called from
248
+ * both UpdateTurn and StartPhase (so it's called at the beginning
249
+ * of a new phase as well as between turns). We should probably
250
+ * split it into two.
251
+ */
252
+ export function InitTurnOrderState(state: State, turn: TurnConfig) {
253
+ let { G, ctx } = state;
254
+ const { numPlayers } = ctx;
255
+ const pluginAPIs = plugin.GetAPIs(state);
256
+ const context = { ...pluginAPIs, G, ctx };
257
+ const order = turn.order;
258
+
259
+ let playOrder = [...Array.from({ length: numPlayers })].map((_, i) => i + '');
260
+ if (order.playOrder !== undefined) {
261
+ playOrder = order.playOrder(context);
262
+ }
263
+
264
+ const playOrderPos = order.first(context);
265
+ const posType = typeof playOrderPos;
266
+ if (posType !== 'number') {
267
+ logging.error(
268
+ `invalid value returned by turn.order.first — expected number got ${posType} “${playOrderPos}”.`
269
+ );
270
+ }
271
+ const currentPlayer = getCurrentPlayer(playOrder, playOrderPos);
272
+
273
+ ctx = { ...ctx, currentPlayer, playOrderPos, playOrder };
274
+ ctx = SetActivePlayers(ctx, turn.activePlayers || {});
275
+
276
+ return ctx;
277
+ }
278
+
279
+ /**
280
+ * Called at the end of each turn to update the turn order state.
281
+ * @param {object} G - The game object G.
282
+ * @param {object} ctx - The game object ctx.
283
+ * @param {object} turn - A turn object for this phase.
284
+ * @param {string} endTurnArg - An optional argument to endTurn that
285
+ may specify the next player.
286
+ */
287
+ export function UpdateTurnOrderState(
288
+ state: State,
289
+ currentPlayer: PlayerID,
290
+ turn: TurnConfig,
291
+ endTurnArg?: true | { remove?: any; next?: string }
292
+ ) {
293
+ const order = turn.order;
294
+
295
+ let { G, ctx } = state;
296
+ let playOrderPos = ctx.playOrderPos;
297
+ let endPhase = false;
298
+
299
+ if (endTurnArg && endTurnArg !== true) {
300
+ if (typeof endTurnArg !== 'object') {
301
+ logging.error(`invalid argument to endTurn: ${endTurnArg}`);
302
+ }
303
+
304
+ Object.keys(endTurnArg).forEach((arg) => {
305
+ switch (arg) {
306
+ case 'remove':
307
+ currentPlayer = getCurrentPlayer(ctx.playOrder, playOrderPos);
308
+ break;
309
+ case 'next':
310
+ playOrderPos = ctx.playOrder.indexOf(endTurnArg.next);
311
+ currentPlayer = endTurnArg.next;
312
+ break;
313
+ default:
314
+ logging.error(`invalid argument to endTurn: ${arg}`);
315
+ }
316
+ });
317
+ } else {
318
+ const pluginAPIs = plugin.GetAPIs(state);
319
+ const context = { ...pluginAPIs, G, ctx };
320
+ const t = order.next(context);
321
+ const type = typeof t;
322
+ if (t !== undefined && type !== 'number') {
323
+ logging.error(
324
+ `invalid value returned by turn.order.next — expected number or undefined got ${type} “${t}”.`
325
+ );
326
+ }
327
+
328
+ if (t === undefined) {
329
+ endPhase = true;
330
+ } else {
331
+ playOrderPos = t;
332
+ currentPlayer = getCurrentPlayer(ctx.playOrder, playOrderPos);
333
+ }
334
+ }
335
+
336
+ ctx = {
337
+ ...ctx,
338
+ playOrderPos,
339
+ currentPlayer,
340
+ };
341
+
342
+ return { endPhase, ctx };
343
+ }
344
+
345
+ /**
346
+ * Set of different turn orders possible in a phase.
347
+ * These are meant to be passed to the `turn` setting
348
+ * in the flow objects.
349
+ *
350
+ * Each object defines the first player when the phase / game
351
+ * begins, and also a function `next` to determine who the
352
+ * next player is when the turn ends.
353
+ *
354
+ * The phase ends if next() returns undefined.
355
+ */
356
+ export const TurnOrder = {
357
+ /**
358
+ * DEFAULT
359
+ *
360
+ * The default round-robin turn order.
361
+ */
362
+ DEFAULT: {
363
+ first: ({ ctx }: FnContext) =>
364
+ ctx.turn === 0
365
+ ? ctx.playOrderPos
366
+ : (ctx.playOrderPos + 1) % ctx.playOrder.length,
367
+ next: ({ ctx }: FnContext) => (ctx.playOrderPos + 1) % ctx.playOrder.length,
368
+ },
369
+
370
+ /**
371
+ * RESET
372
+ *
373
+ * Similar to DEFAULT, but starts from 0 each time.
374
+ */
375
+ RESET: {
376
+ first: () => 0,
377
+ next: ({ ctx }: FnContext) => (ctx.playOrderPos + 1) % ctx.playOrder.length,
378
+ },
379
+
380
+ /**
381
+ * CONTINUE
382
+ *
383
+ * Similar to DEFAULT, but starts with the player who ended the last phase.
384
+ */
385
+ CONTINUE: {
386
+ first: ({ ctx }: FnContext) => ctx.playOrderPos,
387
+ next: ({ ctx }: FnContext) => (ctx.playOrderPos + 1) % ctx.playOrder.length,
388
+ },
389
+
390
+ /**
391
+ * ONCE
392
+ *
393
+ * Another round-robin turn order, but goes around just once.
394
+ * The phase ends after all players have played.
395
+ */
396
+ ONCE: {
397
+ first: () => 0,
398
+ next: ({ ctx }: FnContext) => {
399
+ if (ctx.playOrderPos < ctx.playOrder.length - 1) {
400
+ return ctx.playOrderPos + 1;
401
+ }
402
+ },
403
+ },
404
+
405
+ /**
406
+ * CUSTOM
407
+ *
408
+ * Identical to DEFAULT, but also sets playOrder at the
409
+ * beginning of the phase.
410
+ *
411
+ * @param {Array} playOrder - The play order.
412
+ */
413
+ CUSTOM: (playOrder: string[]) => ({
414
+ playOrder: () => playOrder,
415
+ first: () => 0,
416
+ next: ({ ctx }: FnContext) => (ctx.playOrderPos + 1) % ctx.playOrder.length,
417
+ }),
418
+
419
+ /**
420
+ * CUSTOM_FROM
421
+ *
422
+ * Identical to DEFAULT, but also sets playOrder at the
423
+ * beginning of the phase to a value specified by a field
424
+ * in G.
425
+ *
426
+ * @param {string} playOrderField - Field in G.
427
+ */
428
+ CUSTOM_FROM: (playOrderField: string) => ({
429
+ playOrder: ({ G }: FnContext) => G[playOrderField],
430
+ first: () => 0,
431
+ next: ({ ctx }: FnContext) => (ctx.playOrderPos + 1) % ctx.playOrder.length,
432
+ }),
433
+ };
434
+
435
+ export const Stage = {
436
+ NULL: null,
437
+ };
438
+
439
+ export const ActivePlayers = {
440
+ /**
441
+ * ALL
442
+ *
443
+ * The turn stays with one player, but any player can play (in any order)
444
+ * until the phase ends.
445
+ */
446
+ ALL: { all: Stage.NULL },
447
+
448
+ /**
449
+ * ALL_ONCE
450
+ *
451
+ * The turn stays with one player, but any player can play (once, and in any order).
452
+ * This is typically used in a phase where you want to elicit a response
453
+ * from every player in the game.
454
+ */
455
+ ALL_ONCE: { all: Stage.NULL, minMoves: 1, maxMoves: 1 },
456
+
457
+ /**
458
+ * OTHERS
459
+ *
460
+ * The turn stays with one player, and every *other* player can play (in any order)
461
+ * until the phase ends.
462
+ */
463
+ OTHERS: { others: Stage.NULL },
464
+
465
+ /**
466
+ * OTHERS_ONCE
467
+ *
468
+ * The turn stays with one player, and every *other* player can play (once, and in any order).
469
+ * This is typically used in a phase where you want to elicit a response
470
+ * from every *other* player in the game.
471
+ */
472
+ OTHERS_ONCE: { others: Stage.NULL, minMoves: 1, maxMoves: 1 },
473
+ };