@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,377 @@
1
+ 'use strict';
2
+
3
+ require('setimmediate');
4
+ var reducer = require('./reducer-16eec232.js');
5
+ var turnOrder = require('./turn-order-b2ff8740.js');
6
+ var pluginRandom = require('./plugin-random-7425844d.js');
7
+
8
+ /*
9
+ * Copyright 2018 The boardgame.io Authors
10
+ *
11
+ * Use of this source code is governed by a MIT-style
12
+ * license that can be found in the LICENSE file or at
13
+ * https://opensource.org/licenses/MIT.
14
+ */
15
+ /**
16
+ * Base class that bots can extend.
17
+ */
18
+ class Bot {
19
+ constructor({ enumerate, seed, }) {
20
+ this.enumerateFn = enumerate;
21
+ this.seed = seed;
22
+ this.iterationCounter = 0;
23
+ this._opts = {};
24
+ }
25
+ addOpt({ key, range, initial, }) {
26
+ this._opts[key] = {
27
+ range,
28
+ value: initial,
29
+ };
30
+ }
31
+ getOpt(key) {
32
+ return this._opts[key].value;
33
+ }
34
+ setOpt(key, value) {
35
+ if (key in this._opts) {
36
+ this._opts[key].value = value;
37
+ }
38
+ }
39
+ opts() {
40
+ return this._opts;
41
+ }
42
+ enumerate(G, ctx, playerID) {
43
+ const actions = this.enumerateFn(G, ctx, playerID);
44
+ return actions.map((a) => {
45
+ if ('payload' in a) {
46
+ return a;
47
+ }
48
+ if ('move' in a) {
49
+ return turnOrder.makeMove(a.move, a.args, playerID);
50
+ }
51
+ if ('event' in a) {
52
+ return turnOrder.gameEvent(a.event, a.args, playerID);
53
+ }
54
+ });
55
+ }
56
+ random(arg) {
57
+ let number;
58
+ if (this.seed !== undefined) {
59
+ const seed = this.prngstate ? '' : this.seed;
60
+ const rand = pluginRandom.alea(seed, this.prngstate);
61
+ number = rand();
62
+ this.prngstate = rand.state();
63
+ }
64
+ else {
65
+ number = Math.random();
66
+ }
67
+ if (arg) {
68
+ if (Array.isArray(arg)) {
69
+ const id = Math.floor(number * arg.length);
70
+ return arg[id];
71
+ }
72
+ else {
73
+ return Math.floor(number * arg);
74
+ }
75
+ }
76
+ return number;
77
+ }
78
+ }
79
+
80
+ /*
81
+ * Copyright 2018 The boardgame.io Authors
82
+ *
83
+ * Use of this source code is governed by a MIT-style
84
+ * license that can be found in the LICENSE file or at
85
+ * https://opensource.org/licenses/MIT.
86
+ */
87
+ /**
88
+ * The number of iterations to run before yielding to
89
+ * the JS event loop (in async mode).
90
+ */
91
+ const CHUNK_SIZE = 25;
92
+ /**
93
+ * Bot that uses Monte-Carlo Tree Search to find promising moves.
94
+ */
95
+ class MCTSBot extends Bot {
96
+ constructor({ enumerate, seed, objectives, game, iterations, playoutDepth, iterationCallback, }) {
97
+ super({ enumerate, seed });
98
+ if (objectives === undefined) {
99
+ objectives = () => ({});
100
+ }
101
+ this.objectives = objectives;
102
+ this.iterationCallback = iterationCallback || (() => { });
103
+ this.reducer = reducer.CreateGameReducer({ game });
104
+ this.iterations = iterations;
105
+ this.playoutDepth = playoutDepth;
106
+ this.addOpt({
107
+ key: 'async',
108
+ initial: false,
109
+ });
110
+ this.addOpt({
111
+ key: 'iterations',
112
+ initial: typeof iterations === 'number' ? iterations : 1000,
113
+ range: { min: 1, max: 2000 },
114
+ });
115
+ this.addOpt({
116
+ key: 'playoutDepth',
117
+ initial: typeof playoutDepth === 'number' ? playoutDepth : 50,
118
+ range: { min: 1, max: 100 },
119
+ });
120
+ }
121
+ createNode({ state, parentAction, parent, playerID, }) {
122
+ const { G, ctx } = state;
123
+ let actions = [];
124
+ let objectives = [];
125
+ if (playerID !== undefined) {
126
+ actions = this.enumerate(G, ctx, playerID);
127
+ objectives = this.objectives(G, ctx, playerID);
128
+ }
129
+ else if (ctx.activePlayers) {
130
+ for (const playerID in ctx.activePlayers) {
131
+ actions.push(...this.enumerate(G, ctx, playerID));
132
+ objectives.push(this.objectives(G, ctx, playerID));
133
+ }
134
+ }
135
+ else {
136
+ actions = this.enumerate(G, ctx, ctx.currentPlayer);
137
+ objectives = this.objectives(G, ctx, ctx.currentPlayer);
138
+ }
139
+ return {
140
+ state,
141
+ parent,
142
+ parentAction,
143
+ actions,
144
+ objectives,
145
+ children: [],
146
+ visits: 0,
147
+ value: 0,
148
+ };
149
+ }
150
+ select(node) {
151
+ // This node has unvisited children.
152
+ if (node.actions.length > 0) {
153
+ return node;
154
+ }
155
+ // This is a terminal node.
156
+ if (node.children.length === 0) {
157
+ return node;
158
+ }
159
+ let selectedChild = null;
160
+ let best = 0;
161
+ for (const child of node.children) {
162
+ const childVisits = child.visits + Number.EPSILON;
163
+ const uct = child.value / childVisits +
164
+ Math.sqrt((2 * Math.log(node.visits)) / childVisits);
165
+ if (selectedChild == null || uct > best) {
166
+ best = uct;
167
+ selectedChild = child;
168
+ }
169
+ }
170
+ return this.select(selectedChild);
171
+ }
172
+ expand(node) {
173
+ const actions = node.actions;
174
+ if (actions.length === 0 || node.state.ctx.gameover !== undefined) {
175
+ return node;
176
+ }
177
+ const id = this.random(actions.length);
178
+ const action = actions[id];
179
+ node.actions.splice(id, 1);
180
+ const childState = this.reducer(node.state, action);
181
+ const childNode = this.createNode({
182
+ state: childState,
183
+ parentAction: action,
184
+ parent: node,
185
+ });
186
+ node.children.push(childNode);
187
+ return childNode;
188
+ }
189
+ playout({ state }) {
190
+ let playoutDepth = this.getOpt('playoutDepth');
191
+ if (typeof this.playoutDepth === 'function') {
192
+ playoutDepth = this.playoutDepth(state.G, state.ctx);
193
+ }
194
+ for (let i = 0; i < playoutDepth && state.ctx.gameover === undefined; i++) {
195
+ const { G, ctx } = state;
196
+ let playerID = ctx.currentPlayer;
197
+ if (ctx.activePlayers) {
198
+ playerID = Object.keys(ctx.activePlayers)[0];
199
+ }
200
+ const moves = this.enumerate(G, ctx, playerID);
201
+ // Check if any objectives are met.
202
+ const objectives = this.objectives(G, ctx, playerID);
203
+ const score = Object.keys(objectives).reduce((score, key) => {
204
+ const objective = objectives[key];
205
+ if (objective.checker(G, ctx)) {
206
+ return score + objective.weight;
207
+ }
208
+ return score;
209
+ }, 0);
210
+ // If so, stop and return the score.
211
+ if (score > 0) {
212
+ return { score };
213
+ }
214
+ if (!moves || moves.length === 0) {
215
+ return undefined;
216
+ }
217
+ const id = this.random(moves.length);
218
+ const childState = this.reducer(state, moves[id]);
219
+ state = childState;
220
+ }
221
+ return state.ctx.gameover;
222
+ }
223
+ backpropagate(node, result = {}) {
224
+ node.visits++;
225
+ if (result.score !== undefined) {
226
+ node.value += result.score;
227
+ }
228
+ if (result.draw === true) {
229
+ node.value += 0.5;
230
+ }
231
+ if (node.parentAction &&
232
+ result.winner === node.parentAction.payload.playerID) {
233
+ node.value++;
234
+ }
235
+ if (node.parent) {
236
+ this.backpropagate(node.parent, result);
237
+ }
238
+ }
239
+ play(state, playerID) {
240
+ const root = this.createNode({ state, playerID });
241
+ let numIterations = this.getOpt('iterations');
242
+ if (typeof this.iterations === 'function') {
243
+ numIterations = this.iterations(state.G, state.ctx);
244
+ }
245
+ const getResult = () => {
246
+ let selectedChild = null;
247
+ for (const child of root.children) {
248
+ if (selectedChild == null || child.visits > selectedChild.visits) {
249
+ selectedChild = child;
250
+ }
251
+ }
252
+ const action = selectedChild && selectedChild.parentAction;
253
+ const metadata = root;
254
+ return { action, metadata };
255
+ };
256
+ return new Promise((resolve) => {
257
+ const iteration = () => {
258
+ for (let i = 0; i < CHUNK_SIZE && this.iterationCounter < numIterations; i++) {
259
+ const leaf = this.select(root);
260
+ const child = this.expand(leaf);
261
+ const result = this.playout(child);
262
+ this.backpropagate(child, result);
263
+ this.iterationCounter++;
264
+ }
265
+ this.iterationCallback({
266
+ iterationCounter: this.iterationCounter,
267
+ numIterations,
268
+ metadata: root,
269
+ });
270
+ };
271
+ this.iterationCounter = 0;
272
+ if (this.getOpt('async')) {
273
+ const asyncIteration = () => {
274
+ if (this.iterationCounter < numIterations) {
275
+ iteration();
276
+ setImmediate(asyncIteration);
277
+ }
278
+ else {
279
+ resolve(getResult());
280
+ }
281
+ };
282
+ asyncIteration();
283
+ }
284
+ else {
285
+ while (this.iterationCounter < numIterations) {
286
+ iteration();
287
+ }
288
+ resolve(getResult());
289
+ }
290
+ });
291
+ }
292
+ }
293
+
294
+ /*
295
+ * Copyright 2018 The boardgame.io Authors
296
+ *
297
+ * Use of this source code is governed by a MIT-style
298
+ * license that can be found in the LICENSE file or at
299
+ * https://opensource.org/licenses/MIT.
300
+ */
301
+ /**
302
+ * Bot that picks a move at random.
303
+ */
304
+ class RandomBot extends Bot {
305
+ play({ G, ctx }, playerID) {
306
+ const moves = this.enumerate(G, ctx, playerID);
307
+ return Promise.resolve({ action: this.random(moves) });
308
+ }
309
+ }
310
+
311
+ /*
312
+ * Copyright 2018 The boardgame.io Authors
313
+ *
314
+ * Use of this source code is governed by a MIT-style
315
+ * license that can be found in the LICENSE file or at
316
+ * https://opensource.org/licenses/MIT.
317
+ */
318
+ /**
319
+ * Make a single move on the client with a bot.
320
+ *
321
+ * @param {...object} client - The game client.
322
+ * @param {...object} bot - The bot.
323
+ */
324
+ async function Step(client, bot) {
325
+ const state = client.store.getState();
326
+ let playerID = state.ctx.currentPlayer;
327
+ if (state.ctx.activePlayers) {
328
+ playerID = Object.keys(state.ctx.activePlayers)[0];
329
+ }
330
+ const { action, metadata } = await bot.play(state, playerID);
331
+ if (action) {
332
+ const a = {
333
+ ...action,
334
+ payload: {
335
+ ...action.payload,
336
+ metadata,
337
+ },
338
+ };
339
+ client.store.dispatch(a);
340
+ return a;
341
+ }
342
+ }
343
+ /**
344
+ * Simulates the game till the end or a max depth.
345
+ *
346
+ * @param {...object} game - The game object.
347
+ * @param {...object} bots - An array of bots.
348
+ * @param {...object} state - The game state to start from.
349
+ */
350
+ async function Simulate({ game, bots, state, depth, }) {
351
+ if (depth === undefined)
352
+ depth = 10000;
353
+ const reducer$1 = reducer.CreateGameReducer({ game });
354
+ let metadata = null;
355
+ let iter = 0;
356
+ while (state.ctx.gameover === undefined && iter < depth) {
357
+ let playerID = state.ctx.currentPlayer;
358
+ if (state.ctx.activePlayers) {
359
+ playerID = Object.keys(state.ctx.activePlayers)[0];
360
+ }
361
+ const bot = bots instanceof Bot ? bots : bots[playerID];
362
+ const t = await bot.play(state, playerID);
363
+ if (!t.action) {
364
+ break;
365
+ }
366
+ metadata = t.metadata;
367
+ state = reducer$1(state, t.action);
368
+ iter++;
369
+ }
370
+ return { state, metadata };
371
+ }
372
+
373
+ exports.Bot = Bot;
374
+ exports.MCTSBot = MCTSBot;
375
+ exports.RandomBot = RandomBot;
376
+ exports.Simulate = Simulate;
377
+ exports.Step = Step;
package/dist/cjs/ai.js ADDED
@@ -0,0 +1,20 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var ai = require('./ai-e0e8a768.js');
6
+ require('setimmediate');
7
+ require('./reducer-16eec232.js');
8
+ require('./turn-order-b2ff8740.js');
9
+ require('immer');
10
+ require('./plugin-random-7425844d.js');
11
+ require('lodash.isplainobject');
12
+ require('rfc6902');
13
+
14
+
15
+
16
+ exports.Bot = ai.Bot;
17
+ exports.MCTSBot = ai.MCTSBot;
18
+ exports.RandomBot = ai.RandomBot;
19
+ exports.Simulate = ai.Simulate;
20
+ exports.Step = ai.Step;
@@ -0,0 +1,258 @@
1
+ 'use strict';
2
+
3
+ const assertString = (str, label) => {
4
+ if (!str || typeof str !== 'string') {
5
+ throw new Error(`Expected ${label} string, got "${str}".`);
6
+ }
7
+ };
8
+ const assertGameName = (name) => assertString(name, 'game name');
9
+ const assertMatchID = (id) => assertString(id, 'match ID');
10
+ const validateBody = (body, schema) => {
11
+ if (!body)
12
+ throw new Error(`Expected body, got “${body}”.`);
13
+ for (const key in schema) {
14
+ const propSchema = schema[key];
15
+ const types = Array.isArray(propSchema) ? propSchema : [propSchema];
16
+ const received = body[key];
17
+ if (!types.includes(typeof received)) {
18
+ const union = types.join('|');
19
+ throw new TypeError(`Expected body.${key} to be of type ${union}, got “${received}”.`);
20
+ }
21
+ }
22
+ };
23
+ class LobbyClientError extends Error {
24
+ constructor(message, details) {
25
+ super(message);
26
+ this.details = details;
27
+ }
28
+ }
29
+ /**
30
+ * Create a boardgame.io Lobby API client.
31
+ * @param server The API’s base URL, e.g. `http://localhost:8000`.
32
+ */
33
+ class LobbyClient {
34
+ constructor({ server = '' } = {}) {
35
+ // strip trailing slash if passed
36
+ this.server = server.replace(/\/$/, '');
37
+ }
38
+ async request(route, init) {
39
+ const response = await fetch(this.server + route, init);
40
+ if (!response.ok) {
41
+ let details;
42
+ try {
43
+ details = await response.clone().json();
44
+ }
45
+ catch {
46
+ try {
47
+ details = await response.text();
48
+ }
49
+ catch (error) {
50
+ details = error.message;
51
+ }
52
+ }
53
+ throw new LobbyClientError(`HTTP status ${response.status}`, details);
54
+ }
55
+ return response.json();
56
+ }
57
+ async post(route, opts) {
58
+ let init = {
59
+ method: 'post',
60
+ body: JSON.stringify(opts.body),
61
+ headers: { 'Content-Type': 'application/json' },
62
+ };
63
+ if (opts.init)
64
+ init = {
65
+ ...init,
66
+ ...opts.init,
67
+ headers: { ...init.headers, ...opts.init.headers },
68
+ };
69
+ return this.request(route, init);
70
+ }
71
+ /**
72
+ * Get a list of the game names available on this server.
73
+ * @param init Optional RequestInit interface to override defaults.
74
+ * @return Array of game names.
75
+ *
76
+ * @example
77
+ * lobbyClient.listGames()
78
+ * .then(console.log); // => ['chess', 'tic-tac-toe']
79
+ */
80
+ async listGames(init) {
81
+ return this.request('/games', init);
82
+ }
83
+ /**
84
+ * Get a list of the matches for a specific game type on the server.
85
+ * @param gameName The game to list for, e.g. 'tic-tac-toe'.
86
+ * @param where Options to filter matches by update time or gameover state
87
+ * @param init Optional RequestInit interface to override defaults.
88
+ * @return Array of match metadata objects.
89
+ *
90
+ * @example
91
+ * lobbyClient.listMatches('tic-tac-toe', where: { isGameover: false })
92
+ * .then(data => console.log(data.matches));
93
+ * // => [
94
+ * // {
95
+ * // matchID: 'xyz',
96
+ * // gameName: 'tic-tac-toe',
97
+ * // players: [{ id: 0, name: 'Alice' }, { id: 1 }]
98
+ * // },
99
+ * // ...
100
+ * // ]
101
+ */
102
+ async listMatches(gameName, where, init) {
103
+ assertGameName(gameName);
104
+ let query = '';
105
+ if (where) {
106
+ const queries = [];
107
+ const { isGameover, updatedBefore, updatedAfter } = where;
108
+ if (isGameover !== undefined)
109
+ queries.push(`isGameover=${isGameover}`);
110
+ if (updatedBefore)
111
+ queries.push(`updatedBefore=${updatedBefore}`);
112
+ if (updatedAfter)
113
+ queries.push(`updatedAfter=${updatedAfter}`);
114
+ if (queries.length > 0)
115
+ query = '?' + queries.join('&');
116
+ }
117
+ return this.request(`/games/${gameName}${query}`, init);
118
+ }
119
+ /**
120
+ * Get metadata for a specific match.
121
+ * @param gameName The match’s game type, e.g. 'tic-tac-toe'.
122
+ * @param matchID Match ID for the match to fetch.
123
+ * @param init Optional RequestInit interface to override defaults.
124
+ * @return A match metadata object.
125
+ *
126
+ * @example
127
+ * lobbyClient.getMatch('tic-tac-toe', 'xyz').then(console.log);
128
+ * // => {
129
+ * // matchID: 'xyz',
130
+ * // gameName: 'tic-tac-toe',
131
+ * // players: [{ id: 0, name: 'Alice' }, { id: 1 }]
132
+ * // }
133
+ */
134
+ async getMatch(gameName, matchID, init) {
135
+ assertGameName(gameName);
136
+ assertMatchID(matchID);
137
+ return this.request(`/games/${gameName}/${matchID}`, init);
138
+ }
139
+ /**
140
+ * Create a new match for a specific game type.
141
+ * @param gameName The game to create a match for, e.g. 'tic-tac-toe'.
142
+ * @param body Options required to configure match creation.
143
+ * @param init Optional RequestInit interface to override defaults.
144
+ * @return An object containing the created `matchID`.
145
+ *
146
+ * @example
147
+ * lobbyClient.createMatch('tic-tac-toe', { numPlayers: 2 })
148
+ * .then(console.log);
149
+ * // => { matchID: 'xyz' }
150
+ */
151
+ async createMatch(gameName, body, init) {
152
+ assertGameName(gameName);
153
+ validateBody(body, { numPlayers: 'number' });
154
+ return this.post(`/games/${gameName}/create`, { body, init });
155
+ }
156
+ /**
157
+ * Join a match using its matchID.
158
+ * @param gameName The match’s game type, e.g. 'tic-tac-toe'.
159
+ * @param matchID Match ID for the match to join.
160
+ * @param body Options required to join match.
161
+ * @param init Optional RequestInit interface to override defaults.
162
+ * @return Object containing `playerCredentials` for the player who joined.
163
+ *
164
+ * @example
165
+ * lobbyClient.joinMatch('tic-tac-toe', 'xyz', {
166
+ * playerID: '1',
167
+ * playerName: 'Bob',
168
+ * }).then(console.log);
169
+ * // => { playerID: '1', playerCredentials: 'random-string' }
170
+ */
171
+ async joinMatch(gameName, matchID, body, init) {
172
+ assertGameName(gameName);
173
+ assertMatchID(matchID);
174
+ validateBody(body, {
175
+ playerID: ['string', 'undefined'],
176
+ playerName: 'string',
177
+ });
178
+ return this.post(`/games/${gameName}/${matchID}/join`, { body, init });
179
+ }
180
+ /**
181
+ * Leave a previously joined match.
182
+ * @param gameName The match’s game type, e.g. 'tic-tac-toe'.
183
+ * @param matchID Match ID for the match to leave.
184
+ * @param body Options required to leave match.
185
+ * @param init Optional RequestInit interface to override defaults.
186
+ * @return Promise resolves if successful.
187
+ *
188
+ * @example
189
+ * lobbyClient.leaveMatch('tic-tac-toe', 'xyz', {
190
+ * playerID: '1',
191
+ * credentials: 'credentials-returned-when-joining',
192
+ * })
193
+ * .then(() => console.log('Left match.'))
194
+ * .catch(error => console.error('Error leaving match', error));
195
+ */
196
+ async leaveMatch(gameName, matchID, body, init) {
197
+ assertGameName(gameName);
198
+ assertMatchID(matchID);
199
+ validateBody(body, { playerID: 'string', credentials: 'string' });
200
+ await this.post(`/games/${gameName}/${matchID}/leave`, { body, init });
201
+ }
202
+ /**
203
+ * Update a player’s name or custom metadata.
204
+ * @param gameName The match’s game type, e.g. 'tic-tac-toe'.
205
+ * @param matchID Match ID for the match to update.
206
+ * @param body Options required to update player.
207
+ * @param init Optional RequestInit interface to override defaults.
208
+ * @return Promise resolves if successful.
209
+ *
210
+ * @example
211
+ * lobbyClient.updatePlayer('tic-tac-toe', 'xyz', {
212
+ * playerID: '0',
213
+ * credentials: 'credentials-returned-when-joining',
214
+ * newName: 'Al',
215
+ * })
216
+ * .then(() => console.log('Updated player data.'))
217
+ * .catch(error => console.error('Error updating data', error));
218
+ */
219
+ async updatePlayer(gameName, matchID, body, init) {
220
+ assertGameName(gameName);
221
+ assertMatchID(matchID);
222
+ validateBody(body, { playerID: 'string', credentials: 'string' });
223
+ await this.post(`/games/${gameName}/${matchID}/update`, { body, init });
224
+ }
225
+ /**
226
+ * Create a new match based on the configuration of the current match.
227
+ * @param gameName The match’s game type, e.g. 'tic-tac-toe'.
228
+ * @param matchID Match ID for the match to play again.
229
+ * @param body Options required to configure match.
230
+ * @param init Optional RequestInit interface to override defaults.
231
+ * @return Object containing `nextMatchID`.
232
+ *
233
+ * @example
234
+ * lobbyClient.playAgain('tic-tac-toe', 'xyz', {
235
+ * playerID: '0',
236
+ * credentials: 'credentials-returned-when-joining',
237
+ * })
238
+ * .then(({ nextMatchID }) => {
239
+ * return lobbyClient.joinMatch('tic-tac-toe', nextMatchID, {
240
+ * playerID: '0',
241
+ * playerName: 'Al',
242
+ * })
243
+ * })
244
+ * .then({ playerCredentials } => {
245
+ * console.log(playerCredentials);
246
+ * })
247
+ * .catch(console.error);
248
+ */
249
+ async playAgain(gameName, matchID, body, init) {
250
+ assertGameName(gameName);
251
+ assertMatchID(matchID);
252
+ validateBody(body, { playerID: 'string', credentials: 'string' });
253
+ return this.post(`/games/${gameName}/${matchID}/playAgain`, { body, init });
254
+ }
255
+ }
256
+
257
+ exports.LobbyClient = LobbyClient;
258
+ exports.LobbyClientError = LobbyClientError;