@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.
- package/dist/index.d.ts +3 -0
- package/dist/index.js +25 -12
- package/dist/modules/board.d.ts +10 -0
- package/dist/modules/board.js +32 -0
- package/dist/modules/bridge.d.ts +8 -0
- package/dist/modules/bridge.js +10 -0
- package/dist/modules/click.d.ts +8 -0
- package/dist/modules/click.js +14 -0
- package/dist/modules/controller.accept.d.ts +7 -25
- package/dist/modules/controller.accept.js +12 -159
- package/dist/modules/controller.d.ts +4 -6
- package/dist/modules/controller.grid.d.ts +11 -11
- package/dist/modules/controller.grid.js +21 -25
- package/dist/modules/controller.js +8 -26
- package/dist/modules/player.interact.d.ts +9 -0
- package/dist/modules/player.interact.js +33 -0
- package/dist/modules/player.select.d.ts +9 -0
- package/dist/modules/player.select.js +29 -0
- package/dist/modules/status.d.ts +18 -0
- package/dist/modules/status.js +24 -0
- package/dist/modules/view.d.ts +5 -5
- package/dist/modules/view.js +4 -4
- package/dist/types.d.ts +9 -5
- package/dist/utils/checkers.d.ts +20 -9
- package/dist/utils/checkers.js +28 -21
- package/dist/view/index.d.ts +2 -2
- package/dist/view/index.js +12 -12
- package/package.json +12 -2
- package/src/index.ts +25 -12
- package/src/modules/board.ts +47 -0
- package/src/modules/bridge.ts +20 -0
- package/src/modules/click.ts +28 -0
- package/src/modules/controller.accept.ts +20 -189
- package/src/modules/controller.grid.ts +23 -26
- package/src/modules/controller.ts +16 -36
- package/src/modules/player.interact.ts +48 -0
- package/src/modules/player.select.ts +42 -0
- package/src/modules/status.ts +41 -0
- package/src/modules/view.ts +12 -6
- package/src/tests/player.interact.test.ts +56 -0
- package/src/tests/setup.ts +24 -10
- package/src/types.ts +23 -6
- package/src/utils/checkers.ts +50 -31
- package/src/view/index.tsx +22 -23
- package/dist/modules/checkers.d.ts +0 -9
- package/dist/modules/checkers.js +0 -37
- package/dist/utils/ai.d.ts +0 -4
- package/dist/utils/ai.js +0 -27
- package/dist/utils/board.d.ts +0 -32
- package/dist/utils/board.js +0 -199
- package/src/modules/checkers.ts +0 -52
- package/src/tests/ai.test.ts +0 -61
- package/src/tests/board.test.ts +0 -43
- package/src/tests/checkers.test.ts +0 -58
- package/src/utils/ai.ts +0 -31
- package/src/utils/board.ts +0 -252
package/dist/index.d.ts
CHANGED
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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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 {
|
|
3
|
-
import type {
|
|
4
|
-
|
|
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:
|
|
9
|
-
EVENT_HIDE: "vne:
|
|
10
|
-
EVENT_ACCEPT: "vne:
|
|
11
|
-
EVENT_STATE_UPDATE: "vne:
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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.
|
|
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
|
|
67
|
-
if (gridRow == null || gridColumn == null
|
|
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
|
-
|
|
151
|
-
|
|
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 {
|
|
3
|
-
import {
|
|
4
|
-
export declare class
|
|
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:
|
|
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 {
|
|
3
|
-
import { type
|
|
4
|
-
export declare class
|
|
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:
|
|
7
|
-
EVENT_HIDE: "vne:
|
|
8
|
-
EVENT_STATE_UPDATE: "vne:
|
|
9
|
-
EVENT_UPDATE_FAST: "vne:
|
|
10
|
-
EVENT_GRID_NEXT: "vne:
|
|
11
|
-
EVENT_GRID_PREV: "vne:
|
|
12
|
-
EVENT_GRID_CLEAR: "vne:
|
|
13
|
-
EVENT_GRID_UPDATE_ITEMS: "vne:
|
|
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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.
|
|
18
|
-
getMaxColumns = () => this.PARAMS.
|
|
19
|
-
getGridItems = async () => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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.
|
|
6
|
+
CONTROLS_INDEX = this.PARAMS.CHECKERS_VIEW.ZINDEX;
|
|
8
7
|
subscribe = () => {
|
|
9
|
-
this.on(this.EVENTS.
|
|
10
|
-
this.on(this.EVENTS.
|
|
11
|
-
this.on(this.EVENTS.
|
|
12
|
-
this.on(this.EVENTS.
|
|
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
|
+
}
|