@vnejs/plugins.views.screens.checkers 0.2.2 → 0.2.4

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 (56) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.js +25 -12
  3. package/dist/modules/board.d.ts +10 -0
  4. package/dist/modules/board.js +32 -0
  5. package/dist/modules/bridge.d.ts +8 -0
  6. package/dist/modules/bridge.js +10 -0
  7. package/dist/modules/click.d.ts +8 -0
  8. package/dist/modules/click.js +14 -0
  9. package/dist/modules/controller.accept.d.ts +7 -25
  10. package/dist/modules/controller.accept.js +12 -159
  11. package/dist/modules/controller.d.ts +4 -6
  12. package/dist/modules/controller.grid.d.ts +11 -11
  13. package/dist/modules/controller.grid.js +21 -25
  14. package/dist/modules/controller.js +8 -26
  15. package/dist/modules/player.interact.d.ts +9 -0
  16. package/dist/modules/player.interact.js +33 -0
  17. package/dist/modules/player.select.d.ts +9 -0
  18. package/dist/modules/player.select.js +29 -0
  19. package/dist/modules/status.d.ts +18 -0
  20. package/dist/modules/status.js +24 -0
  21. package/dist/modules/view.d.ts +5 -5
  22. package/dist/modules/view.js +4 -4
  23. package/dist/types.d.ts +9 -5
  24. package/dist/utils/checkers.d.ts +20 -9
  25. package/dist/utils/checkers.js +28 -21
  26. package/dist/view/index.d.ts +2 -2
  27. package/dist/view/index.js +12 -12
  28. package/package.json +12 -2
  29. package/src/index.ts +25 -12
  30. package/src/modules/board.ts +47 -0
  31. package/src/modules/bridge.ts +20 -0
  32. package/src/modules/click.ts +28 -0
  33. package/src/modules/controller.accept.ts +20 -189
  34. package/src/modules/controller.grid.ts +23 -26
  35. package/src/modules/controller.ts +16 -36
  36. package/src/modules/player.interact.ts +48 -0
  37. package/src/modules/player.select.ts +42 -0
  38. package/src/modules/status.ts +41 -0
  39. package/src/modules/view.ts +12 -6
  40. package/src/tests/player.interact.test.ts +56 -0
  41. package/src/tests/setup.ts +24 -10
  42. package/src/types.ts +23 -6
  43. package/src/utils/checkers.ts +50 -31
  44. package/src/view/index.tsx +22 -23
  45. package/dist/modules/checkers.d.ts +0 -9
  46. package/dist/modules/checkers.js +0 -37
  47. package/dist/utils/ai.d.ts +0 -4
  48. package/dist/utils/ai.js +0 -27
  49. package/dist/utils/board.d.ts +0 -32
  50. package/dist/utils/board.js +0 -199
  51. package/src/modules/checkers.ts +0 -52
  52. package/src/tests/ai.test.ts +0 -61
  53. package/src/tests/board.test.ts +0 -43
  54. package/src/tests/checkers.test.ts +0 -58
  55. package/src/utils/ai.ts +0 -31
  56. package/src/utils/board.ts +0 -252
package/dist/index.d.ts CHANGED
@@ -1 +1,4 @@
1
+ import "@vnejs/contracts.common.grid";
2
+ import "@vnejs/contracts.common.turn";
3
+ import "@vnejs/contracts.game.checkers";
1
4
  import "@vnejs/contracts.views.screens.checkers";
package/dist/index.js CHANGED
@@ -1,15 +1,28 @@
1
+ import "@vnejs/contracts.common.grid";
2
+ import "@vnejs/contracts.common.turn";
3
+ import "@vnejs/contracts.game.checkers";
1
4
  import "@vnejs/contracts.views.screens.checkers";
2
5
  import { regPlugin } from "@vnejs/shared";
3
- import { CONSTANTS, PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.views.screens.checkers";
4
- import { CheckersController } from "./modules/controller.js";
5
- import { CheckersControllerAccept } from "./modules/controller.accept.js";
6
- import { CheckersControllerGrid } from "./modules/controller.grid.js";
7
- import { Checkers } from "./modules/checkers.js";
8
- import { CheckersView } from "./modules/view.js";
9
- regPlugin(PLUGIN_NAME, { constants: CONSTANTS, events: SUBSCRIBE_EVENTS, params: PARAMS }, [
10
- CheckersController,
11
- CheckersControllerGrid,
12
- CheckersControllerAccept,
13
- Checkers,
14
- CheckersView,
6
+ import { PARAMS, PLUGIN_NAME, SUBSCRIBE_EVENTS } from "@vnejs/contracts.views.screens.checkers";
7
+ import { CheckersViewBoard } from "./modules/board.js";
8
+ import { CheckersViewBridge } from "./modules/bridge.js";
9
+ import { CheckersViewClick } from "./modules/click.js";
10
+ import { CheckersViewController } from "./modules/controller.js";
11
+ import { CheckersViewControllerAccept } from "./modules/controller.accept.js";
12
+ import { CheckersViewControllerGrid } from "./modules/controller.grid.js";
13
+ import { CheckersViewPlayerInteract } from "./modules/player.interact.js";
14
+ import { CheckersViewPlayerSelect } from "./modules/player.select.js";
15
+ import { CheckersViewStatus } from "./modules/status.js";
16
+ import { CheckersViewView } from "./modules/view.js";
17
+ regPlugin(PLUGIN_NAME, { events: SUBSCRIBE_EVENTS, params: PARAMS }, [
18
+ CheckersViewBridge,
19
+ CheckersViewController,
20
+ CheckersViewControllerGrid,
21
+ CheckersViewControllerAccept,
22
+ CheckersViewPlayerInteract,
23
+ CheckersViewPlayerSelect,
24
+ CheckersViewClick,
25
+ CheckersViewBoard,
26
+ CheckersViewStatus,
27
+ CheckersViewView,
15
28
  ]);
@@ -0,0 +1,10 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { GridChangedPayload, GridUnsetPayload } from "@vnejs/contracts.common.grid";
3
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
4
+ import { type CheckersViewState } from "../utils/checkers.js";
5
+ export declare class CheckersViewBoard extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
6
+ name: string;
7
+ subscribe: () => void;
8
+ onGridChanged: (payload?: GridChangedPayload) => Promise<void>;
9
+ onGridUnset: ({ id }?: GridUnsetPayload) => Promise<void>;
10
+ }
@@ -0,0 +1,32 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import { buildGridItems, emptyBoard, fromGridChanged } from "../utils/checkers.js";
3
+ export class CheckersViewBoard extends ModuleCore {
4
+ name = "checkers_view.board";
5
+ subscribe = () => {
6
+ this.on(this.EVENTS.GRID.CHANGED, this.onGridChanged);
7
+ this.on(this.EVENTS.GRID.UNSET, this.onGridUnset);
8
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
9
+ };
10
+ onGridChanged = async (payload = {}) => {
11
+ if (payload.id !== this.CONST.CHECKERS.GRID_ID)
12
+ return;
13
+ const mirror = fromGridChanged(payload);
14
+ const board = mirror.board ?? this.state.board ?? emptyBoard();
15
+ const gridItems = buildGridItems({ board, gridRow: this.state.gridRow ?? null, gridColumn: this.state.gridColumn ?? null });
16
+ await this.emit(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, { ...mirror, board, gridItems });
17
+ await this.emit(this.EVENTS.CHECKERS_VIEW.UPDATE_FAST);
18
+ };
19
+ onGridUnset = async ({ id } = {}) => {
20
+ if (id !== this.CONST.CHECKERS.GRID_ID)
21
+ return;
22
+ const board = emptyBoard();
23
+ const gridItems = buildGridItems({ board, gridRow: this.state.gridRow ?? null, gridColumn: this.state.gridColumn ?? null });
24
+ await this.emit(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, {
25
+ board,
26
+ selected: null,
27
+ legalMoves: [],
28
+ gridItems,
29
+ });
30
+ await this.emit(this.EVENTS.CHECKERS_VIEW.UPDATE_FAST);
31
+ };
32
+ }
@@ -0,0 +1,8 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
3
+ export declare class CheckersViewBridge extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams> {
4
+ name: string;
5
+ subscribe: () => void;
6
+ onCheckersShow: () => Promise<unknown[]> | undefined;
7
+ onCheckersHide: () => Promise<unknown[]> | undefined;
8
+ }
@@ -0,0 +1,10 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ export class CheckersViewBridge extends ModuleCore {
3
+ name = "checkers_view.bridge";
4
+ subscribe = () => {
5
+ this.on(this.EVENTS.CHECKERS.SHOW, this.onCheckersShow);
6
+ this.on(this.EVENTS.CHECKERS.HIDE, this.onCheckersHide);
7
+ };
8
+ onCheckersShow = () => this.emit(this.EVENTS.CHECKERS_VIEW.SHOW);
9
+ onCheckersHide = () => this.emit(this.EVENTS.CHECKERS_VIEW.HIDE);
10
+ }
@@ -0,0 +1,8 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
3
+ import type { CheckersClickPayload, CheckersViewState } from "../utils/checkers.js";
4
+ export declare class CheckersViewClick extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
5
+ name: string;
6
+ subscribe: () => void;
7
+ onClick: ({ row, column }?: CheckersClickPayload) => Promise<void>;
8
+ }
@@ -0,0 +1,14 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ export class CheckersViewClick extends ModuleCore {
3
+ name = "checkers_view.click";
4
+ subscribe = () => {
5
+ this.on(this.EVENTS.CHECKERS_VIEW.CLICK, this.onClick);
6
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
7
+ };
8
+ onClick = async ({ row, column } = {}) => {
9
+ if (this.shared.checkersInteractDisableSources.isNotEmpty() || row == null || column == null)
10
+ return;
11
+ await this.emit(this.EVENTS.CHECKERS_VIEW.GRID_CLEAR);
12
+ this.emit(this.EVENTS.CHECKERS_VIEW.PLAYER_INTERACT, { row, column });
13
+ };
14
+ }
@@ -1,30 +1,12 @@
1
1
  import { ModuleControllerAccept } from "@vnejs/module.controller.accept";
2
- import type { CheckersAiType } from "@vnejs/contracts.views.screens.checkers";
3
- import type { CheckersPluginConstants, CheckersPluginEvents, CheckersPluginParams, CheckersPluginSettings } from "../types.js";
4
- import { type CheckersPos } from "../utils/board.js";
5
- import { type CheckersCellClickPayload, type CheckersPluginState } from "../utils/checkers.js";
6
- export declare class CheckersControllerAccept extends ModuleControllerAccept<CheckersPluginEvents, CheckersPluginConstants, CheckersPluginSettings, CheckersPluginParams, CheckersPluginState> {
2
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
3
+ import type { CheckersViewState } from "../utils/checkers.js";
4
+ export declare class CheckersViewControllerAccept extends ModuleControllerAccept<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
7
5
  name: string;
8
- EVENT_SHOW: "vne:checkers:show";
9
- EVENT_HIDE: "vne:checkers:hide";
10
- EVENT_ACCEPT: "vne:checkers:accept";
11
- EVENT_STATE_UPDATE: "vne:checkers:state_update";
6
+ EVENT_SHOW: "vne:checkers_view:show";
7
+ EVENT_HIDE: "vne:checkers_view:hide";
8
+ EVENT_ACCEPT: "vne:checkers_view:accept";
9
+ EVENT_STATE_UPDATE: "vne:checkers_view:state_update";
12
10
  CONTROLS_ZINDEX: number;
13
- subscribe: () => void;
14
- onShow: () => undefined;
15
- onShowAndMaybeAi: () => Promise<void>;
16
- onHide: () => Promise<unknown[]> | undefined;
17
- controllerFor: (turn: NonNullable<CheckersPluginState["turn"]>) => CheckersAiType;
18
- isHumanTurn: () => boolean;
19
- onCellClick: ({ row, column }?: CheckersCellClickPayload) => Promise<void>;
20
11
  onAccept: () => Promise<void>;
21
- onAiTurn: () => Promise<void>;
22
- playMove: (from: CheckersPos, to: CheckersPos, { scheduleAi }?: {
23
- scheduleAi?: boolean;
24
- }) => Promise<boolean>;
25
- emitBoardState: (patch: Partial<CheckersPluginState> & {
26
- board?: CheckersPluginState["board"];
27
- selected?: CheckersPluginState["selected"];
28
- legalMoves?: CheckersPluginState["legalMoves"];
29
- }) => Promise<void>;
30
12
  }
@@ -1,165 +1,18 @@
1
1
  import { ModuleControllerAccept } from "@vnejs/module.controller.accept";
2
- import { applyMove, findMove, getAllMoves, getWinner, oppositeColor, samePos } from "../utils/board.js";
3
- import { pickMove } from "../utils/ai.js";
4
- import { buildGridItems, statusForTurn } from "../utils/checkers.js";
5
- export class CheckersControllerAccept extends ModuleControllerAccept {
6
- name = "checkers.controller.accept";
7
- EVENT_SHOW = this.EVENTS.CHECKERS.SHOW;
8
- EVENT_HIDE = this.EVENTS.CHECKERS.HIDE;
9
- EVENT_ACCEPT = this.EVENTS.CHECKERS.ACCEPT;
10
- EVENT_STATE_UPDATE = this.EVENTS.CHECKERS.STATE_UPDATE;
11
- CONTROLS_ZINDEX = this.PARAMS.CHECKERS.ZINDEX;
12
- subscribe = () => {
13
- this.on(this.EVENT_SHOW, this.onShow);
14
- this.on(this.EVENT_HIDE, this.onHide);
15
- this.on(this.EVENT_ACCEPT, this.onAccept);
16
- if (this.EVENT_STATE_UPDATE)
17
- this.on(this.EVENT_STATE_UPDATE, this.updateState);
18
- this.on(this.EVENTS.CHECKERS.CELL_CLICK, this.onCellClick);
19
- this.on(this.EVENTS.CHECKERS.AI_TURN, this.onAiTurn);
20
- };
21
- onShow = () => void this.onShowAndMaybeAi();
22
- onShowAndMaybeAi = async () => {
23
- await this.emit(this.EVENTS.CONTROLS.PUSH, {
24
- key: this.name,
25
- controls: this.CONTROLS,
26
- index: this.CONTROLS_ZINDEX + 1,
27
- checkNext: true,
28
- });
29
- // SHOW handlers run in parallel with controller.beforeShow — wait for board.
30
- await this.waitCheck(() => Boolean(this.state.board && this.state.turn));
31
- await this.onAiTurn();
32
- };
33
- onHide = () => {
34
- this.shared.checkersAiBusy = false;
35
- this.setDefaultState();
36
- return this.emit(this.EVENTS.CONTROLS.POP, { key: this.name });
37
- };
38
- controllerFor = (turn) => (this.state.ai?.[turn] ?? this.shared.checkersAi?.[turn] ?? this.CONST.CHECKERS.AI_TYPES.PLAYER);
39
- isHumanTurn = () => {
40
- const turn = this.state.turn;
41
- if (!turn)
42
- return false;
43
- return this.controllerFor(turn) === this.CONST.CHECKERS.AI_TYPES.PLAYER;
44
- };
45
- onCellClick = async ({ row, column } = {}) => {
46
- if (this.shared.checkersAiBusy || !this.isHumanTurn())
47
- return;
48
- if (row == null || column == null)
49
- return;
50
- await this.emit(this.EVENTS.CHECKERS.STATE_UPDATE, {
51
- gridRow: row,
52
- gridColumn: column,
53
- });
54
- await this.emit(this.EVENTS.CHECKERS.UPDATE_FAST);
55
- await this.onAccept();
56
- };
2
+ export class CheckersViewControllerAccept extends ModuleControllerAccept {
3
+ name = "checkers_view.controller.accept";
4
+ EVENT_SHOW = this.EVENTS.CHECKERS_VIEW.SHOW;
5
+ EVENT_HIDE = this.EVENTS.CHECKERS_VIEW.HIDE;
6
+ EVENT_ACCEPT = this.EVENTS.CHECKERS_VIEW.ACCEPT;
7
+ EVENT_STATE_UPDATE = this.EVENTS.CHECKERS_VIEW.STATE_UPDATE;
8
+ CONTROLS_ZINDEX = this.PARAMS.CHECKERS_VIEW.ZINDEX;
57
9
  onAccept = async () => {
58
- if (this.shared.checkersAiBusy)
59
- return;
60
- if (this.state.winner) {
61
- await this.emit(this.EVENTS.CHECKERS.FINISH);
62
- return;
63
- }
64
- if (!this.isHumanTurn())
10
+ if (this.shared.checkersInteractDisableSources.isNotEmpty())
65
11
  return;
66
- const { gridRow, gridColumn, board, turn, selected } = this.state;
67
- if (gridRow == null || gridColumn == null || !board || !turn)
68
- return;
69
- const focus = { row: gridRow, column: gridColumn };
70
- const piece = board[focus.row]?.[focus.column] ?? null;
71
- if (selected && findMove(this.state.legalMoves ?? [], selected, focus)) {
72
- await this.playMove(selected, focus);
73
- return;
74
- }
75
- if (piece && piece.color === turn) {
76
- const all = getAllMoves(board, turn);
77
- const legalMoves = all.filter((move) => samePos(move.from, focus));
78
- if (legalMoves.length === 0)
79
- return;
80
- const nextSelected = selected && samePos(selected, focus) ? null : focus;
81
- const nextLegal = nextSelected ? legalMoves : [];
82
- await this.emitBoardState({
83
- selected: nextSelected,
84
- legalMoves: nextLegal,
85
- });
86
- return;
87
- }
88
- if (selected) {
89
- await this.emitBoardState({ selected: null, legalMoves: [] });
90
- }
91
- };
92
- onAiTurn = async () => {
93
- if (this.state.winner || !this.state.board || !this.state.turn)
94
- return;
95
- if (this.isHumanTurn())
96
- return;
97
- if (this.shared.checkersAiBusy)
98
- return;
99
- this.shared.checkersAiBusy = true;
100
- try {
101
- while (!this.state.winner && this.state.board && this.state.turn && !this.isHumanTurn()) {
102
- await this.waitTimeout(this.PARAMS.CHECKERS.AI_DELAY);
103
- const { board, turn } = this.state;
104
- if (!board || !turn || this.state.winner)
105
- break;
106
- const move = pickMove(board, turn, this.controllerFor(turn));
107
- if (!move)
108
- break;
109
- const played = await this.playMove(move.from, move.to, { scheduleAi: false });
110
- if (!played)
111
- break;
112
- }
113
- }
114
- finally {
115
- this.shared.checkersAiBusy = false;
116
- }
117
- };
118
- playMove = async (from, to, { scheduleAi = true } = {}) => {
119
- const { board, turn } = this.state;
120
- if (!board || !turn)
121
- return false;
122
- // Always resolve against current legal moves — `legalMoves: []` after a move is truthy and must not win over getAllMoves.
123
- const move = findMove(getAllMoves(board, turn), from, to);
124
- if (!move)
125
- return false;
126
- const nextBoard = applyMove(board, move);
127
- const nextTurn = oppositeColor(turn);
128
- const winner = getWinner(nextBoard, nextTurn);
129
- await this.emitBoardState({
130
- board: nextBoard,
131
- turn: nextTurn,
132
- selected: null,
133
- legalMoves: [],
134
- winner,
135
- statusText: statusForTurn(nextTurn, winner),
136
- });
137
- if (winner) {
138
- await this.waitTimeout(this.PARAMS.CHECKERS.TRANSITION);
139
- await this.emit(this.EVENTS.CHECKERS.FINISH);
140
- return true;
141
- }
142
- if (scheduleAi)
143
- await this.onAiTurn();
144
- return true;
145
- };
146
- emitBoardState = async (patch) => {
147
- const board = patch.board ?? this.state.board;
148
- if (!board)
12
+ const { gridRow, gridColumn } = this.state;
13
+ if (gridRow == null || gridColumn == null)
149
14
  return;
150
- const selected = patch.selected !== undefined ? patch.selected : this.state.selected;
151
- const legalMoves = patch.legalMoves !== undefined ? patch.legalMoves : this.state.legalMoves;
152
- const gridItems = buildGridItems({
153
- board,
154
- selected: selected ?? null,
155
- legalMoves: legalMoves ?? [],
156
- gridRow: this.state.gridRow ?? null,
157
- gridColumn: this.state.gridColumn ?? null,
158
- });
159
- await this.emit(this.EVENTS.CHECKERS.STATE_UPDATE, {
160
- ...patch,
161
- gridItems,
162
- });
163
- await this.emit(this.EVENTS.CHECKERS.UPDATE_FAST);
15
+ await this.emit(this.EVENTS.CHECKERS_VIEW.GRID_CLEAR);
16
+ this.emit(this.EVENTS.CHECKERS_VIEW.PLAYER_INTERACT, { row: gridRow, column: gridColumn });
164
17
  };
165
18
  }
@@ -1,13 +1,11 @@
1
1
  import { ModuleController } from "@vnejs/module.components";
2
- import type { CheckersPluginConstants, CheckersPluginEvents, CheckersPluginParams, CheckersPluginSettings } from "../types.js";
3
- import { type CheckersPluginState } from "../utils/checkers.js";
4
- export declare class CheckersController extends ModuleController<CheckersPluginEvents, CheckersPluginConstants, CheckersPluginSettings, CheckersPluginParams, CheckersPluginState> {
2
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
3
+ import type { CheckersViewState } from "../utils/checkers.js";
4
+ export declare class CheckersViewController extends ModuleController<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
5
5
  name: string;
6
- EVENT_UPDATE_VIEW: "vne:checkers:update";
6
+ EVENT_UPDATE_VIEW: "vne:checkers_view:update";
7
7
  CONTROLS: {};
8
8
  CONTROLS_INDEX: number;
9
9
  subscribe: () => void;
10
- beforeShow: () => Promise<void>;
11
10
  afterHide: () => void;
12
- onFinish: () => Promise<void>;
13
11
  }
@@ -1,16 +1,16 @@
1
1
  import { ModuleControllerArrowsGrid } from "@vnejs/module.controller.arrows.grid";
2
- import type { CheckersPluginConstants, CheckersPluginEvents, CheckersPluginParams, CheckersPluginSettings } from "../types.js";
3
- import { type CheckersPluginState } from "../utils/checkers.js";
4
- export declare class CheckersControllerGrid extends ModuleControllerArrowsGrid<CheckersPluginEvents, CheckersPluginConstants, CheckersPluginSettings, CheckersPluginParams, CheckersPluginState> {
2
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
3
+ import { type CheckersViewState } from "../utils/checkers.js";
4
+ export declare class CheckersViewControllerGrid extends ModuleControllerArrowsGrid<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
5
5
  name: string;
6
- EVENT_SHOW: "vne:checkers:show";
7
- EVENT_HIDE: "vne:checkers:hide";
8
- EVENT_STATE_UPDATE: "vne:checkers:state_update";
9
- EVENT_UPDATE_FAST: "vne:checkers:update_fast";
10
- EVENT_GRID_NEXT: "vne:checkers:grid_next";
11
- EVENT_GRID_PREV: "vne:checkers:grid_prev";
12
- EVENT_GRID_CLEAR: "vne:checkers:grid_clear";
13
- EVENT_GRID_UPDATE_ITEMS: "vne:checkers:grid_update_items";
6
+ EVENT_SHOW: "vne:checkers_view:show";
7
+ EVENT_HIDE: "vne:checkers_view:hide";
8
+ EVENT_STATE_UPDATE: "vne:checkers_view:state_update";
9
+ EVENT_UPDATE_FAST: "vne:checkers_view:update_fast";
10
+ EVENT_GRID_NEXT: "vne:checkers_view:grid_next";
11
+ EVENT_GRID_PREV: "vne:checkers_view:grid_prev";
12
+ EVENT_GRID_CLEAR: "vne:checkers_view:grid_clear";
13
+ EVENT_GRID_UPDATE_ITEMS: "vne:checkers_view:grid_update_items";
14
14
  CONTROLS_ZINDEX: number;
15
15
  isDisableGridChangeHorizontal: boolean;
16
16
  isDisableGridChangeVertical: boolean;
@@ -1,29 +1,25 @@
1
1
  import { ModuleControllerArrowsGrid } from "@vnejs/module.controller.arrows.grid";
2
- import { buildGridItems } from "../utils/checkers.js";
3
- import { createInitialBoard } from "../utils/board.js";
4
- export class CheckersControllerGrid extends ModuleControllerArrowsGrid {
5
- name = "checkers.controller.grid";
6
- EVENT_SHOW = this.EVENTS.CHECKERS.SHOW;
7
- EVENT_HIDE = this.EVENTS.CHECKERS.HIDE;
8
- EVENT_STATE_UPDATE = this.EVENTS.CHECKERS.STATE_UPDATE;
9
- EVENT_UPDATE_FAST = this.EVENTS.CHECKERS.UPDATE_FAST;
10
- EVENT_GRID_NEXT = this.EVENTS.CHECKERS.GRID_NEXT;
11
- EVENT_GRID_PREV = this.EVENTS.CHECKERS.GRID_PREV;
12
- EVENT_GRID_CLEAR = this.EVENTS.CHECKERS.GRID_CLEAR;
13
- EVENT_GRID_UPDATE_ITEMS = this.EVENTS.CHECKERS.GRID_UPDATE_ITEMS;
14
- CONTROLS_ZINDEX = this.PARAMS.CHECKERS.ZINDEX;
2
+ import { buildGridItems, emptyBoard } from "../utils/checkers.js";
3
+ export class CheckersViewControllerGrid extends ModuleControllerArrowsGrid {
4
+ name = "checkers_view.controller.grid";
5
+ EVENT_SHOW = this.EVENTS.CHECKERS_VIEW.SHOW;
6
+ EVENT_HIDE = this.EVENTS.CHECKERS_VIEW.HIDE;
7
+ EVENT_STATE_UPDATE = this.EVENTS.CHECKERS_VIEW.STATE_UPDATE;
8
+ EVENT_UPDATE_FAST = this.EVENTS.CHECKERS_VIEW.UPDATE_FAST;
9
+ EVENT_GRID_NEXT = this.EVENTS.CHECKERS_VIEW.GRID_NEXT;
10
+ EVENT_GRID_PREV = this.EVENTS.CHECKERS_VIEW.GRID_PREV;
11
+ EVENT_GRID_CLEAR = this.EVENTS.CHECKERS_VIEW.GRID_CLEAR;
12
+ EVENT_GRID_UPDATE_ITEMS = this.EVENTS.CHECKERS_VIEW.GRID_UPDATE_ITEMS;
13
+ CONTROLS_ZINDEX = this.PARAMS.CHECKERS_VIEW.ZINDEX;
15
14
  isDisableGridChangeHorizontal = true;
16
15
  isDisableGridChangeVertical = true;
17
- getMaxRows = () => this.PARAMS.CHECKERS.ROWS;
18
- getMaxColumns = () => this.PARAMS.CHECKERS.COLUMNS;
19
- getGridItems = async () => {
20
- const board = this.state.board ?? createInitialBoard();
21
- return buildGridItems({
22
- board,
23
- selected: this.state.selected ?? null,
24
- legalMoves: this.state.legalMoves ?? [],
25
- gridRow: this.state.gridRow ?? null,
26
- gridColumn: this.state.gridColumn ?? null,
27
- });
28
- };
16
+ getMaxRows = () => this.PARAMS.CHECKERS_VIEW.ROWS;
17
+ getMaxColumns = () => this.PARAMS.CHECKERS_VIEW.COLUMNS;
18
+ getGridItems = async () => buildGridItems({
19
+ board: this.state.board ?? emptyBoard(),
20
+ selected: this.state.selected ?? null,
21
+ legalMoves: this.state.legalMoves ?? [],
22
+ gridRow: this.state.gridRow ?? null,
23
+ gridColumn: this.state.gridColumn ?? null,
24
+ });
29
25
  }
@@ -1,34 +1,16 @@
1
1
  import { ModuleController } from "@vnejs/module.components";
2
- import { createInitialCheckersState } from "../utils/checkers.js";
3
- export class CheckersController extends ModuleController {
4
- name = "checkers.controller";
5
- EVENT_UPDATE_VIEW = this.EVENTS.CHECKERS.UPDATE;
2
+ export class CheckersViewController extends ModuleController {
3
+ name = "checkers_view.controller";
4
+ EVENT_UPDATE_VIEW = this.EVENTS.CHECKERS_VIEW.UPDATE;
6
5
  CONTROLS = {};
7
- CONTROLS_INDEX = this.PARAMS.CHECKERS.ZINDEX;
6
+ CONTROLS_INDEX = this.PARAMS.CHECKERS_VIEW.ZINDEX;
8
7
  subscribe = () => {
9
- this.on(this.EVENTS.CHECKERS.SHOW, this.onShow);
10
- this.on(this.EVENTS.CHECKERS.HIDE, this.onHide);
11
- this.on(this.EVENTS.CHECKERS.STATE_UPDATE, this.updateState);
12
- this.on(this.EVENTS.CHECKERS.UPDATE_FAST, this.updateViewFast);
13
- this.on(this.EVENTS.CHECKERS.FINISH, this.onFinish);
14
- };
15
- beforeShow = async () => {
16
- this.shared.checkersAiBusy = false;
17
- const initial = createInitialCheckersState();
18
- const ai = {
19
- white: this.shared.checkersAi?.white ?? this.CONST.CHECKERS.AI_TYPES.PLAYER,
20
- black: this.shared.checkersAi?.black ?? this.CONST.CHECKERS.AI_TYPES.PLAYER,
21
- };
22
- await this.emit(this.EVENTS.CHECKERS.STATE_UPDATE, { ...initial, ai });
23
- await this.emit(this.EVENTS.CHECKERS.GRID_UPDATE_ITEMS);
8
+ this.on(this.EVENTS.CHECKERS_VIEW.SHOW, this.onShow);
9
+ this.on(this.EVENTS.CHECKERS_VIEW.HIDE, this.onHide);
10
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
11
+ this.on(this.EVENTS.CHECKERS_VIEW.UPDATE_FAST, this.updateViewFast);
24
12
  };
25
13
  afterHide = () => {
26
- this.shared.checkersAiBusy = false;
27
14
  this.setDefaultState();
28
15
  };
29
- onFinish = async () => {
30
- this.shared.checkersAiBusy = false;
31
- await this.emit(this.EVENTS.CHECKERS.HIDE);
32
- this.emitNext();
33
- };
34
16
  }
@@ -0,0 +1,9 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { CheckersPlayerInteractPayload } from "@vnejs/contracts.views.screens.checkers";
3
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
4
+ import { type CheckersViewState } from "../utils/checkers.js";
5
+ export declare class CheckersViewPlayerInteract extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
6
+ name: string;
7
+ subscribe: () => void;
8
+ onPlayerInteract: ({ row, column }?: CheckersPlayerInteractPayload) => Promise<undefined>;
9
+ }
@@ -0,0 +1,33 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import { samePos } from "../utils/checkers.js";
3
+ export class CheckersViewPlayerInteract extends ModuleCore {
4
+ name = "checkers_view.player.interact";
5
+ subscribe = () => {
6
+ this.on(this.EVENTS.CHECKERS_VIEW.PLAYER_INTERACT, this.onPlayerInteract);
7
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
8
+ };
9
+ onPlayerInteract = async ({ row, column } = {}) => {
10
+ const { board, turn, selected } = this.state;
11
+ if (row == null || column == null || !board || !turn)
12
+ return;
13
+ const focus = { row, column };
14
+ const piece = board[focus.row]?.[focus.column] ?? null;
15
+ const legalFromState = this.state.legalMoves ?? [];
16
+ const move = selected && legalFromState.find((m) => samePos(m.from, selected) && samePos(m.to, focus));
17
+ if (move)
18
+ return void this.emitOne(this.EVENTS.CHECKERS.MOVE_PLAY, { move, controllerType: this.CONST.AI.PLAYER_TYPE });
19
+ if (piece && piece.color === turn) {
20
+ const result = (await this.emitOne(this.EVENTS.CHECKERS.MOVES_GET, { board, turn }));
21
+ const legalMoves = (result?.moves ?? []).filter((m) => samePos(m.from, focus));
22
+ if (legalMoves.length === 0)
23
+ return;
24
+ const nextSelected = selected && samePos(selected, focus) ? null : focus;
25
+ return void this.emit(this.EVENTS.CHECKERS_VIEW.PLAYER_SELECT, {
26
+ selected: nextSelected,
27
+ legalMoves: nextSelected ? legalMoves : [],
28
+ });
29
+ }
30
+ if (selected)
31
+ return void this.emit(this.EVENTS.CHECKERS_VIEW.PLAYER_SELECT, { selected: null, legalMoves: [] });
32
+ };
33
+ }
@@ -0,0 +1,9 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { CheckersPlayerSelectPayload } from "@vnejs/contracts.views.screens.checkers";
3
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
4
+ import { type CheckersViewState } from "../utils/checkers.js";
5
+ export declare class CheckersViewPlayerSelect extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
6
+ name: string;
7
+ subscribe: () => void;
8
+ onPlayerSelect: ({ selected, legalMoves }?: CheckersPlayerSelectPayload) => Promise<void>;
9
+ }
@@ -0,0 +1,29 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import { buildGridItems } from "../utils/checkers.js";
3
+ export class CheckersViewPlayerSelect extends ModuleCore {
4
+ name = "checkers_view.player.select";
5
+ subscribe = () => {
6
+ this.on(this.EVENTS.CHECKERS_VIEW.PLAYER_SELECT, this.onPlayerSelect);
7
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
8
+ };
9
+ onPlayerSelect = async ({ selected = null, legalMoves = [] } = {}) => {
10
+ const board = this.state.board;
11
+ if (!board)
12
+ return;
13
+ const nextSelected = selected;
14
+ const nextLegalMoves = legalMoves;
15
+ const gridItems = buildGridItems({
16
+ board,
17
+ selected: nextSelected,
18
+ legalMoves: nextLegalMoves,
19
+ gridRow: this.state.gridRow ?? null,
20
+ gridColumn: this.state.gridColumn ?? null,
21
+ });
22
+ await this.emit(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, {
23
+ selected: nextSelected,
24
+ legalMoves: nextLegalMoves,
25
+ gridItems,
26
+ });
27
+ await this.emit(this.EVENTS.CHECKERS_VIEW.UPDATE_FAST);
28
+ };
29
+ }
@@ -0,0 +1,18 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import type { TurnsChangedPayload, TurnsUnsetPayload } from "@vnejs/contracts.common.turn";
3
+ import type { CheckersFinishPayload } from "@vnejs/contracts.game.checkers";
4
+ import type { CheckersViewPluginConstants, CheckersViewPluginEvents, CheckersViewPluginParams, CheckersViewPluginSettings } from "../types.js";
5
+ import { type CheckersColor, type CheckersViewState } from "../utils/checkers.js";
6
+ export declare class CheckersViewStatus extends ModuleCore<CheckersViewPluginEvents, CheckersViewPluginConstants, CheckersViewPluginSettings, CheckersViewPluginParams, CheckersViewState> {
7
+ name: string;
8
+ subscribe: () => void;
9
+ applyStatus: ({ turn, winner, clearSelection }: {
10
+ turn?: CheckersColor;
11
+ winner: CheckersColor | null;
12
+ clearSelection?: boolean;
13
+ }) => Promise<void>;
14
+ onTurnsChanged: ({ id, owner }?: TurnsChangedPayload) => false | Promise<void>;
15
+ onTurnsUnset: ({ id }?: TurnsUnsetPayload) => false | Promise<void>;
16
+ onFinish: ({ winner }?: CheckersFinishPayload) => Promise<void>;
17
+ onShow: () => Promise<void>;
18
+ }
@@ -0,0 +1,24 @@
1
+ import { ModuleCore } from "@vnejs/module.core";
2
+ import { statusForTurn } from "../utils/checkers.js";
3
+ export class CheckersViewStatus extends ModuleCore {
4
+ name = "checkers_view.status";
5
+ subscribe = () => {
6
+ this.on(this.EVENTS.TURNS.CHANGED, this.onTurnsChanged);
7
+ this.on(this.EVENTS.TURNS.UNSET, this.onTurnsUnset);
8
+ this.on(this.EVENTS.CHECKERS.FINISH, this.onFinish);
9
+ this.on(this.EVENTS.CHECKERS.SHOW, this.onShow);
10
+ this.on(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, this.updateState);
11
+ };
12
+ applyStatus = async ({ turn, winner, clearSelection = false }) => {
13
+ const next = { turn, winner, statusText: statusForTurn(turn, winner) };
14
+ if (clearSelection)
15
+ Object.assign(next, { selected: null, legalMoves: [] });
16
+ await this.emit(this.EVENTS.CHECKERS_VIEW.STATE_UPDATE, next);
17
+ await this.emit(this.EVENTS.CHECKERS_VIEW.UPDATE_FAST);
18
+ };
19
+ onTurnsChanged = ({ id, owner } = {}) => id === this.CONST.CHECKERS.TURN_ID &&
20
+ this.applyStatus({ turn: owner, winner: this.state.winner ?? null, clearSelection: true });
21
+ onTurnsUnset = ({ id } = {}) => id === this.CONST.CHECKERS.TURN_ID && this.applyStatus({ turn: undefined, winner: this.state.winner ?? null, clearSelection: true });
22
+ onFinish = ({ winner } = {}) => this.applyStatus({ turn: this.state.turn, winner: (winner ?? null) });
23
+ onShow = () => this.applyStatus({ turn: this.state.turn, winner: null });
24
+ }