diff --git a/css/chess.css b/css/chess.css
index 9d0c762..df14c84 100644
--- a/css/chess.css
+++ b/css/chess.css
@@ -207,6 +207,33 @@ button#settings, button#cb_choose_game {
color: grey;
}
+#cb_times {
+ display: flex;
+ flex-flow: row nowrap;
+ white-space: nowrap;
+ justify-content: stretch;
+ align-items: flex-end;
+ width: 100%;
+ padding-left: 3rem;
+ padding-right: 3rem;
+}
+
+#cb_times.cb-hide-times {
+ visibility: hidden;
+}
+
+#cb_light_time, #cb_dark_time {
+ width: 100%;
+}
+
+#cb_light_time {
+ text-align: left;
+}
+
+#cb_dark_time {
+ text-align: right;
+}
+
#cb_names {
position: relative;
display: flex;
diff --git a/index.html b/index.html
index 7165092..350f75e 100644
--- a/index.html
+++ b/index.html
@@ -167,6 +167,10 @@
+
diff --git a/js/pacosako_ui.js b/js/pacosako_ui.js
index c638c0d..d43c80a 100644
--- a/js/pacosako_ui.js
+++ b/js/pacosako_ui.js
@@ -25,6 +25,7 @@ ElementQueries.listen();
import {Buffer} from 'buffer';
import pako from 'pako';
+import {sprintf} from 'sprintf-js';
/* "Waterdrop" by Porphyr (freesound.org/people/Porphyr) / CC BY 3.0 (creativecommons.org/licenses/by/3.0) */
import Waterdrop from '../mp3/191678__porphyr__waterdrop.mp3';
@@ -254,6 +255,81 @@ $(function (){
return piece;
}
+ function updatePlayerTimes() {
+ let lightTime = 0;
+ let darkTime = 0;
+
+ let moveStartTime = undefined;
+
+ for (const move of visibleGame.moves) {
+ if (!move.meta || !Number.isInteger(move.meta.timestamp)) {
+ lightTime = darkTime = undefined;
+ break;
+ }
+
+ if (move.replaced) {
+ /* not the final move in the chain */
+ continue;
+ }
+
+ /* start counting when the dark player finishes their first move */
+ if (moveStartTime === undefined) {
+ if (move.side === PS.DARK) {
+ moveStartTime = move.meta.timestamp;
+ } else {
+ continue;
+ }
+ }
+
+ const moveTime = move.meta.timestamp - moveStartTime;
+
+ if (moveTime > 0) {
+ if (move.side === PS.LIGHT) {
+ lightTime += moveTime;
+ } else {
+ darkTime += moveTime;
+ }
+ }
+
+ moveStartTime = move.meta.timestamp;
+ }
+
+ if (moveStartTime === undefined) {
+ $('#cb_light_time, #cb_dark_time').text('0:00:00');
+ $('#cb_times').addClass('cb-hide-times');
+ return;
+ }
+
+ if (visibleGame.status === PS.PLAYING) {
+ if (!visibleGame.canRedo) {
+ const currentMoveTime = +new Date() - moveStartTime;
+ if (currentMoveTime > 0) {
+ if (visibleGame.player === PS.LIGHT) {
+ lightTime += currentMoveTime;
+ } else {
+ darkTime += currentMoveTime;
+ }
+ }
+ }
+ }
+
+ $('#cb_times').removeClass('cb-hide-times');
+
+ function formatTime(milliseconds) {
+ let seconds = milliseconds / 1000;
+ const hours = seconds / 3600;
+ seconds %= 3600;
+ const minutes = seconds / 60;
+ seconds %= 60;
+ return sprintf('%d:%02d:%02d', hours, minutes, seconds);
+ }
+
+ $('#cb_light_time').text(formatTime(lightTime));
+ $('#cb_dark_time').text(formatTime(darkTime));
+ }
+
+ setInterval(() => { updatePlayerTimes(); }, 250);
+
function renderBoard(animate) {
$('#cb_board').removeData('dragging_from');
$('#cb_board .cb-piece').remove();
@@ -403,6 +479,8 @@ $(function (){
} else if (game.winner === PS.DARK) {
$('#cb_names').addClass('cb-dark-won');
}
+
+ updatePlayerTimes();
}
function applyTheme(theme) {
@@ -1440,6 +1518,7 @@ $(function (){
$('#header').appendTo('#board_ui');
$('#cb_status').appendTo('#board_ui');
$('#cb_names').appendTo('#board_ui');
+ $('#cb_times').appendTo('#board_ui');
$('#cb_navigate').appendTo('#board_ui');
$('#board_ui').appendTo('#page');
$('#page').removeClass('vertical-layout').addClass('horizontal-layout');
@@ -1448,6 +1527,7 @@ $(function (){
$('#cb_container').appendTo('#board_ui');
$('#cb_status').appendTo('#board_ui');
$('#cb_names').appendTo('#board_ui');
+ $('#cb_times').appendTo('#board_ui');
$('#cb_navigate').appendTo('#board_ui');
$('#board_ui').appendTo('#page');
$('#page').removeClass('horizontal-layout').addClass('vertical-layout');
diff --git a/package-lock.json b/package-lock.json
index 5ccd511..5efe446 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1585,6 +1585,14 @@
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
+ },
+ "dependencies": {
+ "sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+ "dev": true
+ }
}
},
"arr-diff": {
diff --git a/package.json b/package.json
index 57ce815..b6e19b5 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"pako": "^1.0.11",
+ "sprintf-js": "^1.0.3",
"svgo": "^1.3.2",
"svgo-loader": "^2.2.1",
"webpack": "^4.43.0",