Skip to content

Commit d99290d

Browse files
authored
Merge pull request #40 from Mind-Sports-Games/442-backgammon
442 backgammon support undo button
2 parents 0a012ae + 606acf9 commit d99290d

File tree

6 files changed

+79
-6
lines changed

6 files changed

+79
-6
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chessground",
3-
"version": "7.11.1-pstrat2.40",
3+
"version": "7.11.1-pstrat2.41",
44
"description": "playstrategy.org chess ui, forked from lichess.org",
55
"type": "commonjs",
66
"main": "chessground.js",

src/board.ts

+30-3
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@ export function stop(state: HeadlessState): void {
458458
state.liftable.liftDests =
459459
state.animation.current =
460460
undefined;
461+
state.gameButtonsActive = false;
461462
cancelMove(state);
462463
}
463464

@@ -511,6 +512,24 @@ export function areMyDiceAtDomPos(
511512
return (variant === 'backgammon' || variant === 'nackgammon') && correctWidth && correctHeight;
512513
}
513514

515+
export function isButtonAtDomPos(
516+
pos: cg.NumberPair,
517+
orientation: cg.Orientation,
518+
turnPlayerIndex: cg.PlayerIndex,
519+
myPlayerIndex: cg.PlayerIndex,
520+
bounds: ClientRect,
521+
variant: cg.Variant = 'chess'
522+
): boolean {
523+
if (turnPlayerIndex !== myPlayerIndex) return false;
524+
const correctWidth =
525+
(orientation === 'p1' && turnPlayerIndex === 'p2') || (orientation === 'p1vflip' && turnPlayerIndex === 'p1')
526+
? (pos[0] - bounds.left) / bounds.width > 8 / 15 && (pos[0] - bounds.left) / bounds.width < 14 / 15
527+
: (pos[0] - bounds.left) / bounds.width > 1 / 15 && (pos[0] - bounds.left) / bounds.width < 7 / 15;
528+
const correctHeight =
529+
(pos[1] - bounds.top) / bounds.height > 6.5 / 15 && (pos[1] - bounds.top) / bounds.height < 8.5 / 15;
530+
return (variant === 'backgammon' || variant === 'nackgammon') && correctWidth && correctHeight;
531+
}
532+
514533
export function isPocketAtDomPos(
515534
pos: cg.NumberPair,
516535
orientation: cg.Orientation,
@@ -527,10 +546,18 @@ export function isPocketAtDomPos(
527546
}
528547

529548
export function reorderDice(state: HeadlessState): void {
530-
if (state.dice.length === 2 && state.dice[0].isAvailable && state.dice[1].isAvailable) {
531-
state.dice = [state.dice[1], state.dice[0]];
549+
if (state.gameButtonsActive) {
550+
if (state.dice.length === 2 && state.dice[0].isAvailable && state.dice[1].isAvailable) {
551+
state.dice = [state.dice[1], state.dice[0]];
552+
}
553+
callUserFunction(state.events.selectDice, state.dice);
554+
}
555+
}
556+
557+
export function undoButtonPressed(state: HeadlessState): void {
558+
if (state.gameButtonsActive) {
559+
callUserFunction(state.events.undoButton);
532560
}
533-
callUserFunction(state.events.selectDice, state.dice);
534561
}
535562

536563
export function p1Pov(s: HeadlessState): boolean {

src/config.ts

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export interface Config {
1515
coordinates?: boolean; // include coords attributes
1616
boardScores?: boolean; //include board-scores attributes
1717
dice?: cg.Dice[]; // dice to display on the board
18+
canUndo?: boolean; // can user undo thier last action
19+
showUndoButton?: boolean; //show the undo button
20+
gameButtonsActive?: boolean; // can user process game buttons (e.g. swap dice, undo)
1821
autoCastle?: boolean; // immediately complete the castle by moving the rook after king move
1922
viewOnly?: boolean; // don't bind events: the user will never be able to move pieces around
2023
selectOnly?: boolean; // only allow user to select squares/pieces (multiple selection allowed)
@@ -92,6 +95,7 @@ export interface Config {
9295
select?: (key: cg.Key) => void; // called when a square is selected
9396
insert?: (elements: cg.Elements) => void; // when the board DOM has been (re)inserted
9497
selectDice?: (dice: cg.Dice[]) => void; //when the dice have been selected (to swap order)
98+
undoButton?: () => void; //when the undo button hass been selected for backgammon
9599
};
96100
dropmode?: {
97101
active?: boolean;

src/events.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@ import * as draw from './draw';
44
import { cancelDropMode, drop } from './drop';
55
import { eventPosition, isRightButton, backgammonPosDiff } from './util';
66
import * as cg from './types';
7-
import { areMyDiceAtDomPos, getKeyAtDomPos, userMove, userLift, reorderDice } from './board';
7+
import {
8+
areMyDiceAtDomPos,
9+
isButtonAtDomPos,
10+
getKeyAtDomPos,
11+
userMove,
12+
userLift,
13+
reorderDice,
14+
undoButtonPressed,
15+
} from './board';
816
import { Piece } from './types';
917

1018
type MouchBind = (e: cg.MouchEvent) => void;
@@ -89,6 +97,20 @@ function startDragOrDraw(s: State): MouchBind {
8997
stopProcessingClick(e);
9098
return;
9199
}
100+
if (
101+
isButtonAtDomPos(
102+
eventPosition(e)!,
103+
s.orientation,
104+
s.turnPlayerIndex,
105+
s.myPlayerIndex,
106+
s.dom.bounds(),
107+
s.variant
108+
)
109+
) {
110+
undoButtonPressed(s);
111+
stopProcessingClick(e);
112+
return;
113+
}
92114
if (
93115
s.dropmode.active &&
94116
(undefined === squareOccupied(s, e) || s.variant === 'backgammon' || s.variant === 'nackgammon')

src/state.ts

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export interface HeadlessState {
2020
coordinates: boolean; // include coords attributes
2121
boardScores: boolean; //include board-scores attributes
2222
dice: cg.Dice[]; // dice to display on the board
23+
canUndo: boolean; // can user undo their last action (backgammon)
24+
showUndoButton: boolean; // render the undo button (backgammon)
25+
gameButtonsActive: boolean; // can user process game buttons (e.g. swap dice, undo)
2326
autoCastle: boolean; // immediately complete the castle by moving the rook after king move
2427
viewOnly: boolean; // don't bind events: the user will never be able to move pieces around
2528
selectOnly: boolean; // only allow user to select squares/pieces (multiple selection allowed)
@@ -121,6 +124,7 @@ export interface HeadlessState {
121124
select?: (key: cg.Key) => void; // called when a square is selected
122125
insert?: (elements: cg.Elements) => void; // when the board DOM has been (re)inserted
123126
selectDice?: (dice: cg.Dice[]) => void; //when the dice have been selected (to swap order)
127+
undoButton?: () => void; //when the undo button hass been selected for backgammon
124128
};
125129
drawable: Drawable;
126130
exploding?: cg.Exploding;
@@ -149,6 +153,9 @@ export function defaults(): HeadlessState {
149153
coordinates: true,
150154
boardScores: false,
151155
dice: [],
156+
canUndo: false,
157+
showUndoButton: false,
158+
gameButtonsActive: true,
152159
autoCastle: true,
153160
selectedPieces: new Map<cg.Key, cg.Piece>(),
154161
viewOnly: false,

src/wrap.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,12 @@ export function renderWrap(element: HTMLElement, s: HeadlessState, relative: boo
170170
}
171171
}
172172

173-
if (s.dice.length > 0) container.appendChild(renderDice(s.dice, s.turnPlayerIndex));
173+
if (s.dice.length > 0) {
174+
container.appendChild(renderDice(s.dice, s.turnPlayerIndex));
175+
if (s.showUndoButton) {
176+
container.appendChild(renderUndoButton(s.canUndo, s.turnPlayerIndex));
177+
}
178+
}
174179

175180
let ghost: HTMLElement | undefined;
176181
if (s.draggable.showGhost && !relative) {
@@ -236,6 +241,14 @@ function renderDice(dice: Dice[], className: string): HTMLElement {
236241
return el;
237242
}
238243

244+
function renderUndoButton(canUndo: boolean, className: string): HTMLElement {
245+
const el = createEl('cg-buttons', className);
246+
const d: HTMLElement = createEl('cg-button', 'undo ' + (canUndo ? 'available' : 'unavailable'));
247+
d.textContent = 'UNDO';
248+
el.appendChild(d);
249+
return el;
250+
}
251+
239252
function renderCoords(elems: readonly string[], className: string): HTMLElement {
240253
const el = createEl('coords', className);
241254
let f: HTMLElement;

0 commit comments

Comments
 (0)