schachnovelle 1.0.0-beta-6 → 1.1.0
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/CHANGELOG.md +23 -0
- package/README.md +8 -4
- package/index.js +1 -39
- package/package.json +19 -3
- package/server/api.js +132 -0
- package/server/index.js +436 -11
- package/ui/Board.js +52 -16
- package/ui/Fen.js +5 -0
- package/ui/Game.js +648 -176
- package/ui/LichessGame.js +11 -0
- package/ui/Printer.js +27 -2
- package/ui/Side.js +91 -0
- package/ui/Utils.js +12 -2
- package/ui/index.js +91 -35
- package/ui/moves.js +0 -0
- package/views/error.pug +6 -0
- package/views/index.pug +6 -0
- package/views/layout.pug +6 -0
- package/views/welcome.pug +6 -0
- package/.env +0 -4
- package/lichess/index.js +0 -6
- package/tests/consoletest.js +0 -53
- package/tests/controller/index.js +0 -16
- package/tests/processes.js +0 -57
- package/yarn-error.log +0 -367
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
|
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
|
+
and this project (tries to) adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
<!-- ### Added
|
|
9
|
+
### Changed
|
|
10
|
+
### Removed -->
|
|
11
|
+
|
|
12
|
+
## [1.0.1] - 2020-12-16
|
|
13
|
+
### Added
|
|
14
|
+
- Changelog
|
|
15
|
+
|
|
16
|
+
## [1.0.0] - 2020-12-16
|
|
17
|
+
### Added
|
|
18
|
+
- Promotion to different pieces
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Clear the console instead of adding to the end of the line
|
|
22
|
+
|
|
23
|
+
### Removed
|
package/README.md
CHANGED
|
@@ -23,10 +23,14 @@ or npm
|
|
|
23
23
|
...And play!
|
|
24
24
|
|
|
25
25
|
## Features
|
|
26
|
-
|
|
26
|
+
There is no check detection yet. Play with your head! For now...
|
|
27
27
|
|
|
28
|
-
You can play against yourself or a friend on the same keyboard.
|
|
28
|
+
You can play against yourself or a friend on the same keyboard.
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
## Roadmap
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
I'm slowly working on connecting this to the [lichess](https://lichess.org/) API, so you can play others from the comfort of the command line!
|
|
33
|
+
|
|
34
|
+
## Changelog
|
|
35
|
+
|
|
36
|
+
_[Changelog](CHANGELOG.md)_
|
package/index.js
CHANGED
|
@@ -1,42 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const { spawn, exec } = require('child_process');
|
|
3
|
-
|
|
4
2
|
const ui = require('./ui')
|
|
5
3
|
|
|
6
|
-
ui.init()
|
|
7
|
-
// const server = spawn('node', ['server'])
|
|
8
|
-
// const ui = spawn('node', ['ui'])
|
|
9
|
-
|
|
10
|
-
// server.stdout.on('data', (data) => {
|
|
11
|
-
// console.log(`server: ${data}`);
|
|
12
|
-
// });
|
|
13
|
-
|
|
14
|
-
// server.stderr.on('data', (data) => {
|
|
15
|
-
// console.error(`server error: ${data}`);
|
|
16
|
-
// });
|
|
17
|
-
|
|
18
|
-
// server.on('exit', (code, signal) => {
|
|
19
|
-
// console.log(`child process exited with code ${code} and signal ${signal}`);
|
|
20
|
-
// })
|
|
21
|
-
|
|
22
|
-
// server.on('close', (code) => {
|
|
23
|
-
// console.log(`child process exited with code ${code}`);
|
|
24
|
-
// });
|
|
25
|
-
|
|
26
|
-
// ui.stdout.on('data', (data) => {
|
|
27
|
-
// console.log(data);
|
|
28
|
-
// });
|
|
29
|
-
|
|
30
|
-
// ui.stderr.on('data', (data) => {
|
|
31
|
-
// console.error(`ui error: ${data}`);
|
|
32
|
-
// });
|
|
33
|
-
|
|
34
|
-
// ui.on('exit', (code, signal) => {
|
|
35
|
-
// console.log(`ui process exited with code ${code} and signal ${signal}`);
|
|
36
|
-
// })
|
|
37
|
-
|
|
38
|
-
// ui.on('close', (code) => {
|
|
39
|
-
// console.log(`ui exited with code ${code}`);
|
|
40
|
-
// });
|
|
41
|
-
|
|
42
|
-
|
|
4
|
+
ui.init()
|
package/package.json
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "schachnovelle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Chess to play on the command line",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"play": "node index.js",
|
|
8
|
+
"serve": "node server/index.js"
|
|
9
|
+
},
|
|
6
10
|
"bin": {
|
|
7
|
-
"schachnovelle": "index.js"
|
|
11
|
+
"schachnovelle": "index.js",
|
|
12
|
+
"schachnovelle.server": "server/index.js"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=14.15.0"
|
|
8
16
|
},
|
|
17
|
+
"engineStrict": true,
|
|
9
18
|
"author": "Manus <manusnijhoff@gmail.com>",
|
|
10
19
|
"license": "MIT",
|
|
11
20
|
"dependencies": {
|
|
21
|
+
"axios": "^0.20.0",
|
|
12
22
|
"chalk": "^4.0.0",
|
|
13
23
|
"dotenv": "^8.2.0",
|
|
14
24
|
"enquirer": "^2.3.5",
|
|
15
25
|
"express": "^4.17.1",
|
|
16
|
-
"
|
|
26
|
+
"express-session": "^1.17.1",
|
|
27
|
+
"memorystore": "^1.6.4",
|
|
28
|
+
"ndjson": "^2.0.0",
|
|
29
|
+
"node-fetch": "^2.6.0",
|
|
30
|
+
"open": "^7.3.0",
|
|
31
|
+
"pug": "^3.0.0",
|
|
32
|
+
"simple-oauth2": "^4.1.0"
|
|
17
33
|
}
|
|
18
34
|
}
|
package/server/api.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const axios = require('axios')
|
|
2
|
+
const https = require('https')
|
|
3
|
+
const ndjson = require('ndjson')
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* get the user's information
|
|
9
|
+
* @param {*} token
|
|
10
|
+
*/
|
|
11
|
+
getUserInfo (token) {
|
|
12
|
+
return new Promise((resolve, reject) => {
|
|
13
|
+
axios.get('/api/account', {
|
|
14
|
+
baseURL: 'https://lichess.org/',
|
|
15
|
+
headers: { 'Authorization': 'Bearer ' + token.access_token }
|
|
16
|
+
})
|
|
17
|
+
.then((response) => {
|
|
18
|
+
resolve(response)
|
|
19
|
+
})
|
|
20
|
+
.catch((error) => {
|
|
21
|
+
reject(error)
|
|
22
|
+
})
|
|
23
|
+
})
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create an event stream
|
|
28
|
+
* @param {*} token
|
|
29
|
+
*/
|
|
30
|
+
createEventStream (token) {
|
|
31
|
+
const options = {
|
|
32
|
+
headers: {
|
|
33
|
+
'Authorization': 'Bearer ' + token.access_token
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return new Promise((resolve, reject) => {
|
|
38
|
+
const req = https.get('https://lichess.org/api/stream/event', options)
|
|
39
|
+
|
|
40
|
+
req
|
|
41
|
+
.on('response', (stream) => {
|
|
42
|
+
const { statusCode } = stream
|
|
43
|
+
|
|
44
|
+
if (statusCode >= 200 && statusCode < 300) {
|
|
45
|
+
resolve(stream)
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.on('error', (error) => {
|
|
49
|
+
reject(error)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
createGameStream (token, gameId) {
|
|
55
|
+
const options = {
|
|
56
|
+
headers: {
|
|
57
|
+
'Authorization': 'Bearer ' + token.access_token
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return new Promise((resolve, reject) => {
|
|
62
|
+
const req = https.get(`https://lichess.org/api/board/game/stream/${gameId}`, options)
|
|
63
|
+
|
|
64
|
+
req
|
|
65
|
+
.on('response', (stream) => {
|
|
66
|
+
const { statusCode } = stream
|
|
67
|
+
|
|
68
|
+
if (statusCode >= 200 && statusCode < 300) {
|
|
69
|
+
resolve(stream)
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.on('error', (error) => {
|
|
73
|
+
reject(error)
|
|
74
|
+
})
|
|
75
|
+
})
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
// Commence play after the user has been identified
|
|
79
|
+
startPlay (req, res) {
|
|
80
|
+
return new Promise(async (resolve, reject) => {
|
|
81
|
+
try {
|
|
82
|
+
const stream = await this.createEventStream(req.session.accessToken)
|
|
83
|
+
stream
|
|
84
|
+
.pipe(ndjson.parse())
|
|
85
|
+
.on('data', (data) => {
|
|
86
|
+
// Always write the data type to the stream
|
|
87
|
+
process.stdout.write(data.type)
|
|
88
|
+
|
|
89
|
+
// Hook into events from event stream!
|
|
90
|
+
if (data.type === 'gameStart') {
|
|
91
|
+
req.session.currentGame = data.game
|
|
92
|
+
this.openGameStream(req)
|
|
93
|
+
} else {
|
|
94
|
+
console.log('!!! unhandled data type !!!')
|
|
95
|
+
console.log(data)
|
|
96
|
+
console.log('!!! end unhandled data type !!!')
|
|
97
|
+
}
|
|
98
|
+
})
|
|
99
|
+
} catch (error) {
|
|
100
|
+
reject(error)
|
|
101
|
+
} finally {
|
|
102
|
+
resolve({ status: 200 })
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
// Tryout to follow a game
|
|
108
|
+
async openGameStream (req) {
|
|
109
|
+
try {
|
|
110
|
+
const stream = await this.createGameStream(req.session.accessToken, req.session.currentGame.id)
|
|
111
|
+
|
|
112
|
+
stream
|
|
113
|
+
.pipe(ndjson.parse())
|
|
114
|
+
.on('data', (data) => {
|
|
115
|
+
// Write data type to stdout
|
|
116
|
+
process.stdout.write(data.type)
|
|
117
|
+
|
|
118
|
+
if (data.type === 'gameFull') {
|
|
119
|
+
req.session.currentGame.data = data
|
|
120
|
+
} else if (data.type === 'gameState') {
|
|
121
|
+
req.session.currentGame.data.gameState = data
|
|
122
|
+
} else {
|
|
123
|
+
console.log('UNUSED DATA TYPE', data.type)
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.error(error)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
}
|
package/server/index.js
CHANGED
|
@@ -1,19 +1,444 @@
|
|
|
1
1
|
require('dotenv').config()
|
|
2
2
|
|
|
3
|
+
//
|
|
4
|
+
//
|
|
5
|
+
// Imports
|
|
3
6
|
const express = require('express')
|
|
4
|
-
|
|
5
|
-
const
|
|
7
|
+
// Storage
|
|
8
|
+
const open = require('open')
|
|
9
|
+
const session = require('express-session')
|
|
10
|
+
const MemoryStore = require('memorystore')(session)
|
|
11
|
+
// Lichess
|
|
12
|
+
const lichess = require('./api')
|
|
6
13
|
|
|
7
|
-
app.
|
|
14
|
+
/* Create your lichess OAuth app on https://lichess.org/account/oauth/app/create
|
|
15
|
+
* Homepage URL: http://localhost:3000
|
|
16
|
+
* Callback URL: http://localhost:3000/callback
|
|
17
|
+
*/
|
|
8
18
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
//
|
|
22
|
+
//
|
|
23
|
+
// Server + Auth config
|
|
24
|
+
const port = 3000
|
|
25
|
+
const host = process.env.NODE_ENV === 'production' ? 'https://schachnovelle.online' : 'http://localhost'
|
|
26
|
+
const clientId = process.env.LICHESS_ID
|
|
27
|
+
const clientSecret = process.env.LICHESS_SECRET
|
|
28
|
+
const redirectUri = `http://localhost:${port}/callback`
|
|
29
|
+
|
|
30
|
+
// Scopes
|
|
31
|
+
const scopes = [
|
|
32
|
+
'preference:read',
|
|
33
|
+
'challenge:read',
|
|
34
|
+
'board:play',
|
|
35
|
+
'bot:play'
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
//
|
|
41
|
+
//
|
|
42
|
+
// Lichess
|
|
43
|
+
const tokenHost = 'https://oauth.lichess.org/';
|
|
44
|
+
const tokenPath = '/oauth';
|
|
45
|
+
const authorizePath = '/oauth/authorize';
|
|
46
|
+
|
|
47
|
+
const oAuthConfig = {
|
|
48
|
+
client: {
|
|
49
|
+
id: clientId,
|
|
50
|
+
secret: clientSecret
|
|
51
|
+
},
|
|
52
|
+
auth: {
|
|
53
|
+
tokenHost,
|
|
54
|
+
tokenPath,
|
|
55
|
+
authorizePath
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const { AuthorizationCode } = require('simple-oauth2')
|
|
60
|
+
const client = new AuthorizationCode(oAuthConfig)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
//
|
|
65
|
+
//
|
|
66
|
+
// Initialize the server
|
|
67
|
+
const app = express();
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
//
|
|
72
|
+
//
|
|
73
|
+
// Set things
|
|
74
|
+
app.set('view engine', 'pug')
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
//
|
|
79
|
+
//
|
|
80
|
+
// Session
|
|
81
|
+
app.use(session({
|
|
82
|
+
cookie: { maxAge: 86400000 },
|
|
83
|
+
store: new MemoryStore({
|
|
84
|
+
checkPeriod: 86400000 // prune expired entries every 24h
|
|
85
|
+
}),
|
|
86
|
+
resave: false,
|
|
87
|
+
secret: 'keyboard cat',
|
|
88
|
+
saveUninitialized: true
|
|
89
|
+
}))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
//
|
|
94
|
+
//
|
|
95
|
+
// Show the "log in with lichess" button
|
|
96
|
+
app.get('/', (req, res) => {
|
|
97
|
+
if (req.session.userInfo) {
|
|
98
|
+
res.redirect('/welcome')
|
|
99
|
+
} else {
|
|
100
|
+
res.render('../views/index')
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
//
|
|
107
|
+
//
|
|
108
|
+
// Initial page redirecting to Lichess
|
|
109
|
+
app.get('/auth', (req, res) => {
|
|
110
|
+
const state = Math.random().toString(36).substring(2)
|
|
111
|
+
|
|
112
|
+
const authorizationUri = client.authorizeURL({
|
|
113
|
+
redirect_uri: redirectUri,
|
|
114
|
+
scope: scopes.join(' '),
|
|
115
|
+
state
|
|
14
116
|
})
|
|
117
|
+
|
|
118
|
+
res.redirect(authorizationUri)
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
//
|
|
123
|
+
//
|
|
124
|
+
// callback page
|
|
125
|
+
app.get('/callback', async (req, res) => {
|
|
126
|
+
const tokenParams = {
|
|
127
|
+
code: req.query.code,
|
|
128
|
+
redirect_uri: redirectUri,
|
|
129
|
+
scope: scopes.join(' ')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const result = await client.getToken(tokenParams)
|
|
134
|
+
const accessToken = client.createToken(result)
|
|
135
|
+
|
|
136
|
+
// Save token to the session
|
|
137
|
+
req.session.accessToken = accessToken.token.token
|
|
138
|
+
|
|
139
|
+
res.redirect('/welcome')
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.log('Access Token Error', error.message)
|
|
142
|
+
}
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
//
|
|
148
|
+
//
|
|
149
|
+
// Welcome page
|
|
150
|
+
app.get('/welcome', async (req, res) => {
|
|
151
|
+
if (req.session.accessToken) {
|
|
152
|
+
try {
|
|
153
|
+
const userInfo = await lichess.getUserInfo(req.session.accessToken)
|
|
154
|
+
req.session.userInfo = userInfo.data
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error(error)
|
|
157
|
+
} finally {
|
|
158
|
+
if (req.session.userInfo) {
|
|
159
|
+
lichess.startPlay(req, res)
|
|
160
|
+
.then((response) => {
|
|
161
|
+
if (response.status === 200) {
|
|
162
|
+
// This goes to the UI
|
|
163
|
+
process.stdout.write('streamReady')
|
|
164
|
+
// This to the browser
|
|
165
|
+
res.render('../views/welcome', { user: req.session.userInfo })
|
|
166
|
+
} else {
|
|
167
|
+
res.render('../views/error', response)
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
.catch((error) => {
|
|
171
|
+
console.error(error)
|
|
172
|
+
res.render('../views/error', error)
|
|
173
|
+
})
|
|
174
|
+
} else {
|
|
175
|
+
res.render('../views/error')
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
} else {
|
|
180
|
+
res.redirect('/')
|
|
181
|
+
}
|
|
15
182
|
})
|
|
16
183
|
|
|
17
|
-
app.listen(port, () => {
|
|
18
|
-
|
|
19
|
-
})
|
|
184
|
+
app.listen(port, async () => {
|
|
185
|
+
await open(`${host}:${port}`)
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
// SAMPLE DATA
|
|
191
|
+
|
|
192
|
+
// { type: 'gameStart', game: { id: 'Wmv3QOtD' } }
|
|
193
|
+
// {
|
|
194
|
+
// id: 'Wmv3QOtD',
|
|
195
|
+
// variant: { key: 'standard', name: 'Standard', short: 'Std' },
|
|
196
|
+
// clock: { initial: 600000, increment: 3000 },
|
|
197
|
+
// speed: 'rapid',
|
|
198
|
+
// perf: { name: 'Rapid' },
|
|
199
|
+
// rated: false,
|
|
200
|
+
// createdAt: 1612916752568,
|
|
201
|
+
// white: { id: 'manegame', name: 'manegame', title: null, rating: 1155 },
|
|
202
|
+
// black: {
|
|
203
|
+
// id: 'schachnovelle-online',
|
|
204
|
+
// name: 'schachnovelle-online',
|
|
205
|
+
// title: null,
|
|
206
|
+
// rating: 1500,
|
|
207
|
+
// provisional: true
|
|
208
|
+
// },
|
|
209
|
+
// initialFen: 'startpos',
|
|
210
|
+
// type: 'gameFull',
|
|
211
|
+
// state: {
|
|
212
|
+
// type: 'gameState',
|
|
213
|
+
// moves: '',
|
|
214
|
+
// wtime: 600000,
|
|
215
|
+
// btime: 600000,
|
|
216
|
+
// winc: 3000,
|
|
217
|
+
// binc: 3000,
|
|
218
|
+
// wdraw: false,
|
|
219
|
+
// bdraw: false,
|
|
220
|
+
// status: 'started'
|
|
221
|
+
// }
|
|
222
|
+
// }
|
|
223
|
+
// {
|
|
224
|
+
// type: 'gameState',
|
|
225
|
+
// moves: 'e2e4',
|
|
226
|
+
// wtime: 600000,
|
|
227
|
+
// btime: 600000,
|
|
228
|
+
// winc: 3000,
|
|
229
|
+
// binc: 3000,
|
|
230
|
+
// wdraw: false,
|
|
231
|
+
// bdraw: false,
|
|
232
|
+
// status: 'started'
|
|
233
|
+
// }
|
|
234
|
+
// {
|
|
235
|
+
// type: 'gameState',
|
|
236
|
+
// moves: 'e2e4 e7e5',
|
|
237
|
+
// wtime: 600000,
|
|
238
|
+
// btime: 600000,
|
|
239
|
+
// winc: 3000,
|
|
240
|
+
// binc: 3000,
|
|
241
|
+
// wdraw: false,
|
|
242
|
+
// bdraw: false,
|
|
243
|
+
// status: 'started'
|
|
244
|
+
// }
|
|
245
|
+
// {
|
|
246
|
+
// type: 'gameState',
|
|
247
|
+
// moves: 'e2e4 e7e5 g1f3',
|
|
248
|
+
// wtime: 599590,
|
|
249
|
+
// btime: 600000,
|
|
250
|
+
// winc: 3000,
|
|
251
|
+
// binc: 3000,
|
|
252
|
+
// wdraw: false,
|
|
253
|
+
// bdraw: false,
|
|
254
|
+
// status: 'started'
|
|
255
|
+
// }
|
|
256
|
+
// {
|
|
257
|
+
// type: 'gameState',
|
|
258
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6',
|
|
259
|
+
// wtime: 599590,
|
|
260
|
+
// btime: 597200,
|
|
261
|
+
// winc: 3000,
|
|
262
|
+
// binc: 3000,
|
|
263
|
+
// wdraw: false,
|
|
264
|
+
// bdraw: false,
|
|
265
|
+
// status: 'started'
|
|
266
|
+
// }
|
|
267
|
+
// {
|
|
268
|
+
// type: 'gameState',
|
|
269
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4',
|
|
270
|
+
// wtime: 598580,
|
|
271
|
+
// btime: 597200,
|
|
272
|
+
// winc: 3000,
|
|
273
|
+
// binc: 3000,
|
|
274
|
+
// wdraw: false,
|
|
275
|
+
// bdraw: false,
|
|
276
|
+
// status: 'started'
|
|
277
|
+
// }
|
|
278
|
+
// {
|
|
279
|
+
// type: 'gameState',
|
|
280
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5',
|
|
281
|
+
// wtime: 598580,
|
|
282
|
+
// btime: 595560,
|
|
283
|
+
// winc: 3000,
|
|
284
|
+
// binc: 3000,
|
|
285
|
+
// wdraw: false,
|
|
286
|
+
// bdraw: false,
|
|
287
|
+
// status: 'started'
|
|
288
|
+
// }
|
|
289
|
+
// {
|
|
290
|
+
// type: 'gameState',
|
|
291
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5',
|
|
292
|
+
// wtime: 592540,
|
|
293
|
+
// btime: 595560,
|
|
294
|
+
// winc: 3000,
|
|
295
|
+
// binc: 3000,
|
|
296
|
+
// wdraw: false,
|
|
297
|
+
// bdraw: false,
|
|
298
|
+
// status: 'started'
|
|
299
|
+
// }
|
|
300
|
+
// {
|
|
301
|
+
// type: 'gameState',
|
|
302
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5',
|
|
303
|
+
// wtime: 592540,
|
|
304
|
+
// btime: 595370,
|
|
305
|
+
// winc: 3000,
|
|
306
|
+
// binc: 3000,
|
|
307
|
+
// wdraw: false,
|
|
308
|
+
// bdraw: false,
|
|
309
|
+
// status: 'started'
|
|
310
|
+
// }
|
|
311
|
+
// {
|
|
312
|
+
// type: 'gameState',
|
|
313
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5',
|
|
314
|
+
// wtime: 591460,
|
|
315
|
+
// btime: 595370,
|
|
316
|
+
// winc: 3000,
|
|
317
|
+
// binc: 3000,
|
|
318
|
+
// wdraw: false,
|
|
319
|
+
// bdraw: false,
|
|
320
|
+
// status: 'started'
|
|
321
|
+
// }
|
|
322
|
+
// {
|
|
323
|
+
// type: 'gameState',
|
|
324
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4',
|
|
325
|
+
// wtime: 591460,
|
|
326
|
+
// btime: 594720,
|
|
327
|
+
// winc: 3000,
|
|
328
|
+
// binc: 3000,
|
|
329
|
+
// wdraw: false,
|
|
330
|
+
// bdraw: false,
|
|
331
|
+
// status: 'started'
|
|
332
|
+
// }
|
|
333
|
+
// {
|
|
334
|
+
// type: 'gameState',
|
|
335
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3',
|
|
336
|
+
// wtime: 578720,
|
|
337
|
+
// btime: 594720,
|
|
338
|
+
// winc: 3000,
|
|
339
|
+
// binc: 3000,
|
|
340
|
+
// wdraw: false,
|
|
341
|
+
// bdraw: false,
|
|
342
|
+
// status: 'started'
|
|
343
|
+
// }
|
|
344
|
+
// {
|
|
345
|
+
// type: 'gameState',
|
|
346
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2',
|
|
347
|
+
// wtime: 578720,
|
|
348
|
+
// btime: 597720,
|
|
349
|
+
// winc: 3000,
|
|
350
|
+
// binc: 3000,
|
|
351
|
+
// wdraw: false,
|
|
352
|
+
// bdraw: false,
|
|
353
|
+
// status: 'started'
|
|
354
|
+
// }
|
|
355
|
+
// {
|
|
356
|
+
// type: 'gameState',
|
|
357
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1',
|
|
358
|
+
// wtime: 565650,
|
|
359
|
+
// btime: 597720,
|
|
360
|
+
// winc: 3000,
|
|
361
|
+
// binc: 3000,
|
|
362
|
+
// wdraw: false,
|
|
363
|
+
// bdraw: false,
|
|
364
|
+
// status: 'started'
|
|
365
|
+
// }
|
|
366
|
+
// {
|
|
367
|
+
// type: 'gameState',
|
|
368
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3',
|
|
369
|
+
// wtime: 565650,
|
|
370
|
+
// btime: 595360,
|
|
371
|
+
// winc: 3000,
|
|
372
|
+
// binc: 3000,
|
|
373
|
+
// wdraw: false,
|
|
374
|
+
// bdraw: false,
|
|
375
|
+
// status: 'started'
|
|
376
|
+
// }
|
|
377
|
+
// {
|
|
378
|
+
// type: 'gameState',
|
|
379
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3',
|
|
380
|
+
// wtime: 556810,
|
|
381
|
+
// btime: 595360,
|
|
382
|
+
// winc: 3000,
|
|
383
|
+
// binc: 3000,
|
|
384
|
+
// wdraw: false,
|
|
385
|
+
// bdraw: false,
|
|
386
|
+
// status: 'started'
|
|
387
|
+
// }
|
|
388
|
+
// {
|
|
389
|
+
// type: 'gameState',
|
|
390
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3 c8h3',
|
|
391
|
+
// wtime: 556810,
|
|
392
|
+
// btime: 587450,
|
|
393
|
+
// winc: 3000,
|
|
394
|
+
// binc: 3000,
|
|
395
|
+
// wdraw: false,
|
|
396
|
+
// bdraw: false,
|
|
397
|
+
// status: 'started'
|
|
398
|
+
// }
|
|
399
|
+
// {
|
|
400
|
+
// type: 'gameState',
|
|
401
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3 c8h3 f1g1',
|
|
402
|
+
// wtime: 547270,
|
|
403
|
+
// btime: 587450,
|
|
404
|
+
// winc: 3000,
|
|
405
|
+
// binc: 3000,
|
|
406
|
+
// wdraw: false,
|
|
407
|
+
// bdraw: false,
|
|
408
|
+
// status: 'started'
|
|
409
|
+
// }
|
|
410
|
+
// {
|
|
411
|
+
// type: 'gameState',
|
|
412
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3 c8h3 f1g1 h3g2',
|
|
413
|
+
// wtime: 547270,
|
|
414
|
+
// btime: 581970,
|
|
415
|
+
// winc: 3000,
|
|
416
|
+
// binc: 3000,
|
|
417
|
+
// wdraw: false,
|
|
418
|
+
// bdraw: false,
|
|
419
|
+
// status: 'started'
|
|
420
|
+
// }
|
|
421
|
+
// {
|
|
422
|
+
// type: 'gameState',
|
|
423
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3 c8h3 f1g1 h3g2 b2b3',
|
|
424
|
+
// wtime: 543850,
|
|
425
|
+
// btime: 581970,
|
|
426
|
+
// winc: 3000,
|
|
427
|
+
// binc: 3000,
|
|
428
|
+
// wdraw: false,
|
|
429
|
+
// bdraw: false,
|
|
430
|
+
// status: 'started'
|
|
431
|
+
// }
|
|
432
|
+
// { type: 'gameFinish', game: { id: 'Wmv3QOtD' } }
|
|
433
|
+
// {
|
|
434
|
+
// type: 'gameState',
|
|
435
|
+
// moves: 'e2e4 e7e5 g1f3 c7c6 f1c4 d7d5 c4d5 c6d5 f3e5 d5e4 g2g3 d8d2 e1f1 e4e3 c2c3 c8h3 f1g1 h3g2 b2b3 d2f2',
|
|
436
|
+
// wtime: 543850,
|
|
437
|
+
// btime: 574250,
|
|
438
|
+
// winc: 3000,
|
|
439
|
+
// binc: 3000,
|
|
440
|
+
// wdraw: false,
|
|
441
|
+
// bdraw: false,
|
|
442
|
+
// status: 'mate',
|
|
443
|
+
// winner: 'black'
|
|
444
|
+
// }
|