Skip to content

Commit

Permalink
Adding puzzle functionality, issue #2
Browse files Browse the repository at this point in the history
  • Loading branch information
ppeloton authored and mliebelt committed Apr 23, 2024
1 parent 3a611a0 commit 6bfd16e
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 6 deletions.
5 changes: 4 additions & 1 deletion examples/base/puzzle.html
Expand Up @@ -32,8 +32,11 @@
continues the attack.}) 23... Ke7 $2 (23... Re6 {stops the attack.}) 24. Qg8\
Bf8 25. Qg5+ Kf7 26. Rf1+ Ke8 27. Qg8 {\
The players were ready for dinner in time.}';

var hints = {'r1b2k2/pp2q1b1/2p4r/3ppp2/2B1PP2/2N3Q1/PPP3PP/3R1RK1': ["Do not take the pawn", "Return the bishop"]}
var cfg = { position: 'r1b2k2/pp2q1b1/2pp3r/4pp2/2B1P3/2N3Q1/PPP2PPP/3R1RK1 w - - 0 17',
pgn: pgn, locale: 'en', pieceStyle: 'merida', headers: false, theme: 'brown' };
pgn: pgn, locale: 'en', pieceStyle: 'merida', headers: false, theme: 'brown',
hints: hints };
var board = PGNV.pgnPuzzle('board', cfg);
</script>
</body>
Expand Down
1 change: 1 addition & 0 deletions examples/base/readme.md
Expand Up @@ -6,5 +6,6 @@
* [View](view.html): Allow to view a chess game, play the moves
* [Print](print.html): Gives a print representation with multiple boards in it, but no interactive view
* [Edit](edit.html): A variant to `View` that even allows to adapt the games (not finished yet).
* [Puzzle](puzzle.html): Lets you guess the next move

See the documentation of the current version on [github pages](http://mliebelt.github.io/pgn-viewer/) for examples, documentation of the API and some background.
13 changes: 13 additions & 0 deletions src/css/pgnvjs.css
Expand Up @@ -468,6 +468,19 @@
font-size: 80%;
}

/*
puzzle mode
*/

.pgnvjs textarea.hints {
grid-row: 6/6;
display: flex;
font-family: monospace;
width: 96%;
height: 100px;
padding: 2px;
}

/**
CHESSGROUND changes.
*/
Expand Down
6 changes: 6 additions & 0 deletions src/fontawesome/css/all.css
Expand Up @@ -222,6 +222,12 @@ readers do not read off random characters that represent icons */
.fa-step-forward:before {
content: "\f051"; }

.fa-question:before {
content: "\3f"; }

.fa-lightbulb:before {
content: "\f0eb"; }

.sr-only {
border: 0;
clip: rect(0, 0, 0, 0);
Expand Down
3 changes: 3 additions & 0 deletions src/locales/en.ts
Expand Up @@ -25,6 +25,9 @@ const en: BaseTranslation = {
"buttons:nags": "NAGs menu",
"buttons:pgn": "Display PGN of current game",
"buttons:hidePGN": "Hide the displayed PGN",
"buttons:getHint": "Give a hint",
"buttons:makeMove": "Show the next move",
"buttons:showSolution": "Show the whole solution",
"nag:$0": "null annotation",
"nag:$1": "good move",
"nag:$1_menu": "Good move",
Expand Down
122 changes: 119 additions & 3 deletions src/pgnv.ts
Expand Up @@ -81,15 +81,18 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
movesId: boardId + 'Moves',
buttonsId: boardId + 'Button',
fenId: boardId + "Fen",
colorMarkerId: boardId + 'ColorMarker'
colorMarkerId: boardId + 'ColorMarker',
hintsId: boardId + "Hints",
}
}
that.configuration = Object.assign(Object.assign(defaults, PgnBaseDefaults), configuration)
that.mypgn = new PgnReader(that.configuration)

const timer = new Timer(10)
const moveDelay = 400; //delay to play reply in puzzle mode

let chess = that.mypgn.chess // Use the same instance from chess.src
let hintsShown:number = 0;
let theme = that.configuration.theme || Theme.Default
function hasMode (mode:PgnViewerMode) {
return that.configuration.mode === mode
Expand Down Expand Up @@ -141,6 +144,28 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
that.errorDiv.appendChild(node)
}

/*
helper functions for hints in puzzle mode
*/
function showHint(h:string) {
let hintsView:HTMLTextAreaElement = document.getElementById(id('hintsId')) as HTMLTextAreaElement;
if (hintsView) {
if (hintsShown > 0){
hintsView.value += "\n"
}
hintsView.value += h
}
hintsShown++;
}

function resetHints(){
let hintsView:HTMLTextAreaElement = document.getElementById(id('hintsId')) as HTMLTextAreaElement
if (hintsView) {
hintsView.value = "";
hintsShown = 0;
}
}

/**
* Adds a class to an element.
*/
Expand Down Expand Up @@ -349,9 +374,17 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {

if (playMove){
let fen = that.mypgn.getMove(moveIndex).fen
makeMove(that.currentMove, moveIndex, fen)

setTimeout(() => {
makeMove(that.currentMove, moveIndex, fen);
resetHints();
regenerateMoves(that.mypgn.getMoves());
}, moveDelay)

} else {
regenerateMoves(that.mypgn.getMoves())
}
regenerateMoves(that.mypgn.getMoves())

} else {
let col = move.turn == 'w' ? 'black' : 'white'

Expand Down Expand Up @@ -455,6 +488,14 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
})
}

//generate puzzle buttons
function generatePuzzleButtons(buttonDiv:HTMLElement) {
[["getHint", "fa-lightbulb"], ["makeMove", "fa-step-forward"],
["showSolution", "fa-question"]].forEach(function (entry: [string, string]) {
addButton(entry, buttonDiv)
})
}

// Generate 3 rows, similar to lichess in studies
function generateNagMenu(nagEle:HTMLElement) {
function generateRow(array:number[], rowClass:string, nagEle:HTMLElement) {
Expand Down Expand Up @@ -563,6 +604,10 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
theme, topInnerBoardDiv)
}
}
if (hasMode(PgnViewerMode.Puzzle)){
const buttonsBoardDiv = createEle("div", id('buttonsId'), "buttons", theme, divBoard)
generatePuzzleButtons(buttonsBoardDiv)
}
updateUI(null)

/** Fen */
Expand Down Expand Up @@ -593,6 +638,12 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
}
}

/** hints Div */
if (hasMode(PgnViewerMode.Puzzle)) {
createEle("textarea", id('hintsId'), "hints",
null, divBoard)
}

/** Edit Divs TODO Redo those */
if (hasMode(PgnViewerMode.Edit)) {
const editButtonsDiv = createEle("div", "edit" + id('buttonsId'), "edit", theme, divBoard)
Expand Down Expand Up @@ -1494,6 +1545,71 @@ let pgnBase = function (boardId:string, configuration:PgnViewerConfiguration) {
firstMove()
})

addEventListener(id('buttonsId') + 'makeMove', 'click', function () {
let next = -1
if ((typeof that.currentMove == 'undefined') || (that.currentMove === null)) {
if (that.mypgn.getMoves().length === 0) return // no next move
next = 0
} else {
next = that.mypgn.getMove(that.currentMove).next
if (typeof next == 'undefined') return
}
let myMove = that.mypgn.getMove(next);
manualMove(myMove.notation["notation"])
})

addEventListener(id('buttonsId') + 'showSolution', 'click', function() {

function playMovesToEnd(){
if ((typeof that.currentMove == 'undefined') || (that.currentMove === null)) {
if (that.mypgn.getMoves().length === 0){
movesLeft = false
return movesLeft
} else {
next = 0
manualMove(that.mypgn.getMove(next).notation["notation"])
movesLeft = true
return movesLeft
}

} else {
next = that.mypgn.getMove(that.currentMove).next
if (typeof next == 'undefined'){
movesLeft = false
return movesLeft
} else {
manualMove(that.mypgn.getMove(next).notation["notation"])
movesLeft = true
return movesLeft
}
}
}
let movesLeft = true
let next = -1

let nIntervId;
nIntervId = setInterval(() => {
movesLeft = playMovesToEnd()
if (!movesLeft){
clearInterval(nIntervId);
}
}, 400)
})

addEventListener(id('buttonsId') + 'getHint', 'click', function() {
const currentFen: string = that.board.getFen()
if (that.configuration.hints != undefined && that.configuration.hints[currentFen] != undefined){
if (that.configuration.hints[currentFen].length > hintsShown){
showHint(that.configuration.hints[currentFen][hintsShown])
} else if (that.configuration.hints[currentFen].length == hintsShown) {
showHint("No more hints")
}
} else if (hintsShown == 0){
showHint("There are no hints")
}

})

function lastMove() {
let moved = false
do {
Expand Down
5 changes: 3 additions & 2 deletions src/types.ts
Expand Up @@ -88,10 +88,11 @@ export type PgnViewerConfiguration = {
coordsFontSize?: string,
coordsFactor?:number,
coordinates?:boolean, // TODO Should be part of Config (only). How to share configuration?
notation?:'short'|'long'
notation?:'short'|'long',
hints?: Map<string, string[]>
}

export type PgnViewerID = 'bottomHeaderId' | 'topHeaderId' | 'innerBoardId' | 'movesId' | 'buttonsId' | 'fenId' | 'colorMarkerId'
export type PgnViewerID = 'bottomHeaderId' | 'topHeaderId' | 'innerBoardId' | 'movesId' | 'buttonsId' | 'fenId' | 'colorMarkerId' | 'hintsId'

export type PrimitiveMove = {
from: Field,
Expand Down

0 comments on commit 6bfd16e

Please sign in to comment.