- render(h) {
- let [sizeX,sizeY] = VariantRules.size;
- // Precompute hints squares to facilitate rendering
- let hintSquares = doubleArray(sizeX, sizeY, false);
- this.possibleMoves.forEach(m => { hintSquares[m.end.x][m.end.y] = true; });
- // Also precompute in-check squares
- let incheckSq = doubleArray(sizeX, sizeY, false);
- this.incheck.forEach(sq => { incheckSq[sq[0]][sq[1]] = true; });
- let elementArray = [];
- let square00 = document.getElementById("sq-0-0");
- let squareWidth = !!square00
- ? parseFloat(window.getComputedStyle(square00).width.slice(0,-2))
- : 0;
- const playingHuman = (this.mode == "human");
- const playingComp = (this.mode == "computer");
- let actionArray = [
- h('button',
- {
- on: {
- click: () => {
- if (this.mode == "human")
- return; //no newgame while playing
- if (this.seek)
- delete localStorage["newgame"]; //cancel game seek
- else
- {
- localStorage["newgame"] = variant;
- this.newGame("human");
- }
- this.seek = !this.seek;
- }
- },
- attrs: { "aria-label": 'New game VS human' },
- 'class': {
- "tooltip": true,
- "seek": this.seek,
- "playing": playingHuman,
- },
- },
- [h('i', { 'class': { "material-icons": true } }, "accessibility")]),
- h('button',
- {
- on: {
- click: () => {
- if (this.mode == "human")
- return; //no newgame while playing
- this.newGame("computer");
- }
- },
- attrs: { "aria-label": 'New game VS computer' },
- 'class': {
- "tooltip":true,
- "playing": playingComp,
- },
- },
- [h('i', { 'class': { "material-icons": true } }, "computer")])
- ];
- if (!!this.vr)
- {
- if (this.mode == "human")
- {
- let connectedIndic = h(
- 'div',
- {
- "class": {
- "connected": this.oppConnected,
- "disconnected": !this.oppConnected,
- },
- }
- );
- elementArray.push(connectedIndic);
- }
- let choices = h('div',
- {
- attrs: { "id": "choices" },
- 'class': { 'row': true },
- style: {
- //"position": "relative",
- "display": this.choices.length>0?"block":"none",
- "top": "-" + ((sizeY/2)*squareWidth+squareWidth/2) + "px",
- "width": (this.choices.length * squareWidth) + "px",
- "height": squareWidth + "px",
- },
- },
- this.choices.map( m => { //a "choice" is a move
- return h('div',
- {
- 'class': { 'board': true },
- style: {
- 'width': (100/this.choices.length) + "%",
- 'padding-bottom': (100/this.choices.length) + "%",
- },
- },
- [h('img',
- {
- attrs: { "src": '/images/pieces/' + VariantRules.getPpath(m.appear[0].c+m.appear[0].p) + '.svg' },
- 'class': { 'choice-piece': true, 'board': true },
- on: { "click": e => { this.play(m); this.choices=[]; } },
- })
- ]
- );
- })
- );
- // Create board element (+ reserves if needed by variant or mode)
- let gameDiv = h('div',
- {
- 'class': { 'game': true },
- },
- [_.range(sizeX).map(i => {
- let ci = this.mycolor=='w' ? i : sizeX-i-1;
- return h(
- 'div',
- {
- 'class': {
- 'row': true,
- },
- style: { 'opacity': this.choices.length>0?"0.5":"1" },
- },
- _.range(sizeY).map(j => {
- let cj = this.mycolor=='w' ? j : sizeY-j-1;
- let elems = [];
- if (this.vr.board[ci][cj] != VariantRules.EMPTY)
- {
- elems.push(
- h(
- 'img',
- {
- 'class': {
- 'piece': true,
- 'ghost': !!this.selectedPiece && this.selectedPiece.parentNode.id == "sq-"+ci+"-"+cj,
- },
- attrs: {
- src: "/images/pieces/" + VariantRules.getPpath(this.vr.board[ci][cj]) + ".svg",
- },
- }
- )
- );
- }
- if (hintSquares[ci][cj])
- {
- elems.push(
- h(
- 'img',
- {
- 'class': {
- 'mark-square': true,
- },
- attrs: {
- src: "/images/mark.svg",
- },
- }
- )
- );
- }
- const lm = this.vr.lastMove;
- const highlight = !!lm && _.isMatch(lm.end, {x:ci,y:cj});
- return h(
- 'div',
- {
- 'class': {
- 'board': true,
- 'light-square': !highlight && (i+j)%2==0,
- 'dark-square': !highlight && (i+j)%2==1,
- 'highlight': highlight,
- 'incheck': incheckSq[ci][cj],
- },
- attrs: {
- id: this.getSquareId({x:ci,y:cj}),
- },
- },
- elems
- );
- })
- );
- }), choices]
- );
- actionArray.push(
- h('button',
- {
- on: { click: this.resign },
- attrs: { "aria-label": 'Resign' },
- 'class': { "tooltip":true },
- },
- [h('i', { 'class': { "material-icons": true } }, "flag")])
- );
- elementArray.push(gameDiv);
- // if (!!vr.reserve)
- // {
- // let reserve = h('div',
- // {'class':{'game':true}}, [
- // h('div',
- // { 'class': { 'row': true }},
- // [
- // h('div',
- // {'class':{'board':true}},
- // [h('img',{'class':{"piece":true},attrs:{"src":"/images/pieces/wb.svg"}})]
- // )
- // ]
- // )
- // ],
- // );
- // elementArray.push(reserve);
- // }
- let eogMessage = "Unfinished";
- switch (this.score)
- {
- case "1-0":
- eogMessage = "White win";
- break;
- case "0-1":
- eogMessage = "Black win";
- break;
- case "1/2":
- eogMessage = "Draw";
- break;
- }
- let elemsOfEog =
- [
- h('label',
- {
- attrs: { "for": "modal-control" },
- "class": { "modal-close": true },
- }
- ),
- h('h3',
- {
- "class": { "section": true },
- domProps: { innerHTML: eogMessage },
- }
- )
- ];
- if (this.score != "*")
- {
- elemsOfEog.push(
- h('p', //'textarea', //TODO: selectable!
- {
- domProps: { innerHTML: this.vr.getPGN(this.mycolor, this.score, this.fenStart) },
- //attrs: { "readonly": true },
- }
- )
- );
- }
- const modalEog = [
- h('input',
- {
- attrs: { "id": "modal-control", type: "checkbox" },
- "class": { "modal": true },
- }),
- h('div',
- {
- attrs: { "role": "dialog", "aria-labelledby": "dialog-title" },
- },
- [
- h('div',
- {
- "class": { "card": true, "smallpad": true },
- },
- elemsOfEog
- )
- ]
- )
- ];
- elementArray = elementArray.concat(modalEog);
- }
- const modalNewgame = [
- h('input',
- {
- attrs: { "id": "modal-control2", type: "checkbox" },
- "class": { "modal": true },
- }),
- h('div',
- {
- attrs: { "role": "dialog", "aria-labelledby": "dialog-title" },
- },
- [
- h('div',
- {
- "class": { "card": true, "smallpad": true },
- },
- [
- h('label',
- {
- attrs: { "id": "close-newgame", "for": "modal-control2" },
- "class": { "modal-close": true },
- }
- ),
- h('h3',
- {
- "class": { "section": true },
- domProps: { innerHTML: "New game" },
- }
- ),
- h('p',
- {
- "class": { "section": true },
- domProps: { innerHTML: "Waiting for opponent..." },
- }
- )
- ]
- )
- ]
- )
- ];
- elementArray = elementArray.concat(modalNewgame);
- const actions = h('div',
- {
- attrs: { "id": "actions" },
- 'class': { 'text-center': true },
- },
- actionArray
- );
- elementArray.push(actions);
- return h(
- 'div',
- {
- 'class': {
- "col-sm-12":true,
- "col-md-8":true,
- "col-md-offset-2":true,
- "col-lg-6":true,
- "col-lg-offset-3":true,
- },
- // NOTE: click = mousedown + mouseup --> what about smartphone?!
- on: {
- mousedown: this.mousedown,
- mousemove: this.mousemove,
- mouseup: this.mouseup,
- touchdown: this.mousedown,
- touchmove: this.mousemove,
- touchup: this.mouseup,
- },
- },
- elementArray
- );