schachnovelle 1.0.3 → 1.1.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.
- package/package.json +5 -1
- package/server/index.js +0 -0
- package/ui/Board.js +15 -15
- package/ui/Game.js +4 -3
- package/ui/WebPrinter.js +51 -0
- package/ui/index.js +0 -0
- package/ui/plainChalk.js +19 -0
- package/ui/web.js +53 -0
- package/ui/webPrompt.js +59 -0
- package/web.js +5 -0
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schachnovelle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Chess to play on the command line",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./index.js",
|
|
8
|
+
"./web": "./web.js"
|
|
9
|
+
},
|
|
6
10
|
"scripts": {
|
|
7
11
|
"play": "node index.js",
|
|
8
12
|
"serve": "node server/index.js"
|
package/server/index.js
CHANGED
|
File without changes
|
package/ui/Board.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const chalk = require('chalk')
|
|
2
|
-
|
|
3
2
|
const Printer = require('./Printer')
|
|
4
3
|
const Utils = require('./Utils')
|
|
5
4
|
|
|
@@ -20,7 +19,8 @@ class Board {
|
|
|
20
19
|
this.ranks = ranks
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
this.
|
|
22
|
+
this.chalk = options.chalk || chalk
|
|
23
|
+
this.printer = options.printer || new Printer(options.spacing)
|
|
24
24
|
this.utils = new Utils()
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -45,9 +45,9 @@ class Board {
|
|
|
45
45
|
})
|
|
46
46
|
if (this.options.mode === 'color') {
|
|
47
47
|
if (activeWhitePiece) {
|
|
48
|
-
return chalk` {whiteBright ${activeWhitePiece.piece}} `
|
|
48
|
+
return this.chalk` {whiteBright ${activeWhitePiece.piece}} `
|
|
49
49
|
} else if (activeBlackPiece) {
|
|
50
|
-
return chalk` {black ${activeBlackPiece.piece}} `
|
|
50
|
+
return this.chalk` {black ${activeBlackPiece.piece}} `
|
|
51
51
|
}
|
|
52
52
|
return ` `
|
|
53
53
|
} else if (this.options.mode === 'bare') {
|
|
@@ -56,15 +56,15 @@ class Board {
|
|
|
56
56
|
*/
|
|
57
57
|
if (activeWhitePiece) {
|
|
58
58
|
if (activeWhitePiece.type === 'King' && this.white.inCheck) {
|
|
59
|
-
return chalk`{red ${activeWhitePiece.piece}} `
|
|
59
|
+
return this.chalk`{red ${activeWhitePiece.piece}} `
|
|
60
60
|
} else {
|
|
61
|
-
return chalk`{black ${activeWhitePiece.piece}} `
|
|
61
|
+
return this.chalk`{black ${activeWhitePiece.piece}} `
|
|
62
62
|
}
|
|
63
63
|
} else if (activeBlackPiece) {
|
|
64
64
|
if (activeBlackPiece.type === 'King' && this.black.inCheck) {
|
|
65
|
-
return chalk`{red ${activeBlackPiece.piece}} `
|
|
65
|
+
return this.chalk`{red ${activeBlackPiece.piece}} `
|
|
66
66
|
} else {
|
|
67
|
-
return chalk`{black ${activeBlackPiece.piece}} `
|
|
67
|
+
return this.chalk`{black ${activeBlackPiece.piece}} `
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
/**
|
|
@@ -74,9 +74,9 @@ class Board {
|
|
|
74
74
|
const rankParity = this.ranks.indexOf(rank) % 2 === 0 // the rank is odd
|
|
75
75
|
const fileParity = this.files.indexOf(file) % 2 === 0 // the file is odd
|
|
76
76
|
if (rankParity && fileParity || !rankParity && !fileParity) {
|
|
77
|
-
return chalk`{white .} `
|
|
77
|
+
return this.chalk`{white .} `
|
|
78
78
|
} else {
|
|
79
|
-
return chalk`{black .} `
|
|
79
|
+
return this.chalk`{black .} `
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
}
|
|
@@ -174,16 +174,16 @@ class Board {
|
|
|
174
174
|
// if rank is even, start with white
|
|
175
175
|
if (rank % 2 === 0) {
|
|
176
176
|
if (file % 2 === 0) {
|
|
177
|
-
renderRank += chalk.bgKeyword('darkgrey')(this.getPiece(this.files[file], this.ranks[rank]))
|
|
177
|
+
renderRank += this.chalk.bgKeyword('darkgrey')(this.getPiece(this.files[file], this.ranks[rank]))
|
|
178
178
|
} else {
|
|
179
|
-
renderRank += chalk.bgBlackBright(this.getPiece(this.files[file], this.ranks[rank]))
|
|
179
|
+
renderRank += this.chalk.bgBlackBright(this.getPiece(this.files[file], this.ranks[rank]))
|
|
180
180
|
}
|
|
181
181
|
renderRank = this.printer.addSpace('x', renderRank)
|
|
182
182
|
} else {
|
|
183
183
|
if (file % 2 === 0) {
|
|
184
|
-
renderRank += chalk.bgBlackBright(this.getPiece(this.files[file], this.ranks[rank]))
|
|
184
|
+
renderRank += this.chalk.bgBlackBright(this.getPiece(this.files[file], this.ranks[rank]))
|
|
185
185
|
} else {
|
|
186
|
-
renderRank += chalk.bgKeyword('darkgrey')(this.getPiece(this.files[file], this.ranks[rank]))
|
|
186
|
+
renderRank += this.chalk.bgKeyword('darkgrey')(this.getPiece(this.files[file], this.ranks[rank]))
|
|
187
187
|
}
|
|
188
188
|
renderRank = this.printer.addSpace('x', renderRank)
|
|
189
189
|
}
|
|
@@ -208,4 +208,4 @@ class Board {
|
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
module.exports = Board
|
|
211
|
+
module.exports = Board
|
package/ui/Game.js
CHANGED
|
@@ -20,13 +20,14 @@ class Game {
|
|
|
20
20
|
|
|
21
21
|
// Initialize the board
|
|
22
22
|
this.board = new Board(this.white, this.black, {
|
|
23
|
-
mode: "pieces", // possibly add text mode
|
|
23
|
+
mode: options.mode || "pieces", // possibly add text mode
|
|
24
24
|
orientation: this.playingAs,
|
|
25
25
|
spacing: options.spacing,
|
|
26
|
-
|
|
26
|
+
printer: options.printer,
|
|
27
|
+
chalk: options.chalk
|
|
27
28
|
})
|
|
28
29
|
|
|
29
|
-
this.enquirer = new Enquirer()
|
|
30
|
+
this.enquirer = options.enquirer || new Enquirer()
|
|
30
31
|
this.printer = new Printer(options.spacing)
|
|
31
32
|
this.utils = new Utils()
|
|
32
33
|
}
|
package/ui/WebPrinter.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
class WebPrinter {
|
|
2
|
+
constructor (spacing, io) {
|
|
3
|
+
this.spacing = spacing
|
|
4
|
+
this.io = io
|
|
5
|
+
this.tab = ' '
|
|
6
|
+
this.lineCount = 0
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
clearView () {
|
|
10
|
+
if (this.io && this.io.clear) {
|
|
11
|
+
this.io.clear()
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
clearForward () {}
|
|
16
|
+
|
|
17
|
+
printLine (value) {
|
|
18
|
+
if (this.io && this.io.write) {
|
|
19
|
+
this.io.write(value + '\n')
|
|
20
|
+
this.lineCount++
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
print (value) {
|
|
25
|
+
if (this.io && this.io.write) {
|
|
26
|
+
this.io.write(value)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
addSpace (direction, string) {
|
|
31
|
+
if (direction === 'x') {
|
|
32
|
+
for (let i = 0; i < this.spacing; i++) {
|
|
33
|
+
string += ' '
|
|
34
|
+
}
|
|
35
|
+
} else {
|
|
36
|
+
for (let i = 0; i < this.spacing; i++) {
|
|
37
|
+
this.printLine('')
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
addSpaceBefore (string) {
|
|
44
|
+
for (let i = 0; i < this.spacing; i++) {
|
|
45
|
+
string = ' ' + string
|
|
46
|
+
}
|
|
47
|
+
return string
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = WebPrinter
|
package/ui/index.js
CHANGED
|
File without changes
|
package/ui/plainChalk.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const stripChalkMarkup = (value) => {
|
|
2
|
+
return value.replace(/\{[^}\s]*\s/g, '').replace(/\}/g, '')
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const plainChalk = (strings, ...values) => {
|
|
6
|
+
let output = ''
|
|
7
|
+
for (let i = 0; i < strings.length; i++) {
|
|
8
|
+
output += strings[i]
|
|
9
|
+
if (i < values.length) {
|
|
10
|
+
output += values[i]
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return stripChalkMarkup(output)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
plainChalk.bgKeyword = () => (value) => stripChalkMarkup(value)
|
|
17
|
+
plainChalk.bgBlackBright = (value) => stripChalkMarkup(value)
|
|
18
|
+
|
|
19
|
+
module.exports = plainChalk
|
package/ui/web.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const Game = require('./Game')
|
|
2
|
+
const WebPrinter = require('./WebPrinter')
|
|
3
|
+
const createWebPrompt = require('./webPrompt')
|
|
4
|
+
const plainChalk = require('./plainChalk')
|
|
5
|
+
|
|
6
|
+
const spacing = 1
|
|
7
|
+
|
|
8
|
+
const welcomeMessage = (printer) => {
|
|
9
|
+
printer.addSpace('y')
|
|
10
|
+
printer.printLine(printer.addSpaceBefore('S . C . V . E'))
|
|
11
|
+
printer.printLine(printer.addSpaceBefore(' C A H O E L '))
|
|
12
|
+
printer.printLine(printer.addSpaceBefore('. H . N . L .'))
|
|
13
|
+
printer.addSpace('y')
|
|
14
|
+
printer.printLine(printer.addSpaceBefore(' >>Um Gottes Willen! Nicht!<<'))
|
|
15
|
+
printer.addSpace('y')
|
|
16
|
+
printer.printLine(printer.addSpaceBefore(' Public Service Announcement '))
|
|
17
|
+
printer.printLine(printer.addSpaceBefore(' I run best on a white terminal '))
|
|
18
|
+
printer.addSpace('y')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const createWebGame = (io, options = {}) => {
|
|
22
|
+
const prompt = createWebPrompt(io)
|
|
23
|
+
const printer = new WebPrinter(options.spacing || spacing, io)
|
|
24
|
+
|
|
25
|
+
welcomeMessage(printer)
|
|
26
|
+
|
|
27
|
+
prompt.prompt([{
|
|
28
|
+
type: 'select',
|
|
29
|
+
name: 'color',
|
|
30
|
+
message: 'Play as',
|
|
31
|
+
choices: ['white', 'black']
|
|
32
|
+
}]).then((answer) => {
|
|
33
|
+
const game = new Game({
|
|
34
|
+
playingAs: answer.color,
|
|
35
|
+
spacing: options.spacing || spacing,
|
|
36
|
+
mode: 'bare',
|
|
37
|
+
enquirer: prompt,
|
|
38
|
+
printer,
|
|
39
|
+
chalk: plainChalk
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
printer.clearView()
|
|
43
|
+
game.init()
|
|
44
|
+
}).catch((error) => {
|
|
45
|
+
if (io && io.write) {
|
|
46
|
+
io.write(`Error starting game: ${error?.message || error}\n`)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
module.exports = {
|
|
52
|
+
createWebGame
|
|
53
|
+
}
|
package/ui/webPrompt.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const createWebPrompt = (io) => {
|
|
2
|
+
let pendingResolve = null
|
|
3
|
+
|
|
4
|
+
if (io && io.onLine) {
|
|
5
|
+
io.onLine((line) => {
|
|
6
|
+
if (pendingResolve) {
|
|
7
|
+
const resolve = pendingResolve
|
|
8
|
+
pendingResolve = null
|
|
9
|
+
resolve(line)
|
|
10
|
+
}
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const ask = (question) => {
|
|
15
|
+
const choices = question.choices || []
|
|
16
|
+
io.write(`${question.message}\n`)
|
|
17
|
+
choices.forEach((choice, index) => {
|
|
18
|
+
io.write(` ${index + 1}) ${choice}\n`)
|
|
19
|
+
})
|
|
20
|
+
io.write('> ')
|
|
21
|
+
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
const resolveChoice = (line) => {
|
|
24
|
+
const trimmed = `${line}`.trim()
|
|
25
|
+
let selection = choices.find(choice => choice === trimmed)
|
|
26
|
+
if (!selection) {
|
|
27
|
+
const index = Number(trimmed)
|
|
28
|
+
if (index >= 1 && index <= choices.length) {
|
|
29
|
+
selection = choices[index - 1]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!selection) {
|
|
34
|
+
io.write('Invalid choice, try again.\n')
|
|
35
|
+
io.write('> ')
|
|
36
|
+
pendingResolve = resolveChoice
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const result = question.result ? question.result(selection) : selection
|
|
41
|
+
resolve({ [question.name]: result })
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pendingResolve = resolveChoice
|
|
45
|
+
})
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
prompt: async (questions) => {
|
|
50
|
+
if (!Array.isArray(questions) || questions.length === 0) {
|
|
51
|
+
return {}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return ask(questions[0])
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = createWebPrompt
|