crosswords/js_client/grid.js

395 lines
11 KiB
JavaScript

import { html, css, LitElement, unsafeCSS } from 'https://unpkg.com/lit-element/lit-element.js?module';
import './infoBox.js'
import { GridElement, GridLetter, GridBox, gridType } from './gridBoxes.js'
import './solutionBox.js'
export class CrosswordGrid extends LitElement {
static get styles() {
return css`
body {
background-color: black;
text-align: center;
}
table {
position: relative;
top: 7em;
border-spacing: 0px;
border-style: solid;
border-color: black;
border-width: 1em;
text-align: center;
margin-left: auto;
margin-right: auto;
}
td {
padding: 0px;
}
`;
}
static get properties() {
return {
id: { type: String },
width: { type: Number },
height: { type: Number },
infobox_id: { type: String }
};
}
constructor() {
super();
this.width = 10;
this.height = 10;
this.grid = [];
this.json_grid = null;
this.num_hints = 0;
this.lastMoveVertical = false;
this.infobox = null;
this.serverConnection = null;
this.solution_locations = [];
this.solutionBox = null;
this.gridCount = 0;
}
setSolutionBox(solBox) {
this.solutionBox = solBox;
if (self.solution_locations)
solBox.length = self.solution_locations.length;
}
getSolutionIndex(x, y) {
var i = 0;
for (i = 0; i < this.solution_locations.length; i++) {
if (this.solution_locations[i][0] == y && this.solution_locations[i][1] == x) {
return i;
}
}
return -1;
}
createGridByJson(json_grid) {
this.num_hints = 0;
this.json_grid = json_grid;
this.grid = [];
const width = json_grid.w;
const height = json_grid.h;
this.gridCount += 1;
this.solution_locations = json_grid.solution
if (this.solutionBox) {
this.solutionBox.length = this.solution_locations.length;
this.solutionBox.requestUpdate();
console.log("update box");
}
var y;
var x;
for (y = 0; y < height; y++) {
var row = [];
for (x = 0; x < width; x++) {
const json_cell = json_grid.grid[y][x];
const cell_type = json_cell.cell_type;
switch (cell_type) {
case "empty": {
row.push(new GridElement(x, y, this, gridType.EMPTY));
break;
}
case "hint": {
row.push(new GridElement(x, y, this, gridType.HINT));
break;
}
case "letter": {
row.push(new GridElement(x, y, this, gridType.LETTER));
break;
}
};
}
this.grid.push(row);
}
this.width = width;
this.height = height;
this.requestUpdate();
}
focusNextCellHorizontal(x, y, skip_revealed = false) {
if (x + 1 < this.width && this.grid[y][x + 1].getGridType() === gridType.LETTER) {
if (this.grid[y][x].getGridType() === gridType.LETTER) {
//this.grid[y][x].getGridLetter().blur();
}
if (skip_revealed && this.grid[y][x + 1].getGridLetter().revealed) {
return this.focusNextCellHorizontal(x + 1, y, true);
}
this.grid[y][x + 1].getGridLetter().focus(x, y);
return true;
}
return false;
}
focusPrevCellHorizontal(x, y, skip_revealed = false) {
if (x - 1 >= 0 && this.grid[y][x - 1].getGridType() === gridType.LETTER) {
if (this.grid[y][x].getGridType() === gridType.LETTER) {
//this.grid[y][x].getGridLetter().blur();
}
if (skip_revealed && this.grid[y][x - 1].getGridLetter().revealed) {
return this.focusPrevCellHorizontal(x - 1, y, true);
}
this.grid[y][x - 1].getGridLetter().focus();
return true;
}
return false;
}
focusNextCellVertical(x, y, skip_revealed = false) {
if (y + 1 < this.height && this.grid[y + 1][x].getGridType() === gridType.LETTER) {
if (this.grid[y][x].getGridType() === gridType.LETTER) {
//this.grid[y][x].getGridLetter().blur();
}
if (skip_revealed && this.grid[y + 1][x].getGridLetter().revealed) {
return this.focusNextCellVertical(x, y + 1, true);
}
this.grid[y + 1][x].getGridLetter().focus(x, y);
return true;
}
return false;
}
focusPrevCellVertical(x, y, skip_revealed = false) {
if (y - 1 >= 0 && this.grid[y - 1][x].getGridType() === gridType.LETTER) {
if (this.grid[y][x].getGridType() === gridType.LETTER) {
//this.grid[y][x].getGridLetter().blur();
}
if (skip_revealed && this.grid[y - 1][x].getGridLetter().revealed) {
return this.focusPrevCellVertical(x, y - 1, true);
}
this.grid[y - 1][x].getGridLetter().focus();
return true;
}
return false;
}
focusNextCell(x, y) {
if (this.lastMoveVertical) {
if (this.focusNextCellVertical(x, y, true)) {
return;
}
if (this.focusNextCellHorizontal(x, y, true)) {
this.lastMoveVertical = false;
}
}
else {
if (this.focusNextCellHorizontal(x, y, true)) {
return;
}
if (this.focusNextCellVertical(x, y, true)) {
this.lastMoveVertical = true;
}
}
}
focusPrevCell(x, y, lastX = -1, lastY = -1) {
if (lastX > 0 && lastY > 0) {
this.grid[lastY][lastX].getGridLetter().focus();
return;
}
if (this.lastMoveVertical) {
if (this.focusPrevCellVertical(x, y, true)) {
return;
}
if (this.focusPrevCellHorizontal(x, y, true)) {
this.lastMoveVertical = false;
}
}
else {
if (this.focusPrevCellHorizontal(x, y, true)) {
return;
}
if (this.focusPrevCellVertical(x, y, true)) {
this.lastMoveVertical = true;
}
}
}
getGridElement(x, y) {
return this.grid[y][x];
}
update(props) {
if (props.has("width") || props.has("height")) {
//
}
if (props.has("infobox_id")) {
this.infobox = document.getElementById(this.infobox_id);
}
super.update()
}
updateHints(x, y) {
var cell = this.grid[y][x];
if (cell.getGridType() != gridType.LETTER) {
console.error("cannot get hints for non letter cell");
}
//get horizontal hint:
var upper_end = cell;
while (upper_end.getGridType() === gridType.LETTER) {
upper_end = this.grid[upper_end.y - 1][x]
}
var left_end = cell;
while (left_end.getGridType() === gridType.LETTER) {
left_end = this.grid[y][left_end.x - 1]
}
var hHint = "";
var vHint = "";
if (left_end.getGridType() === gridType.HINT) {
var box = left_end.getHintBox();
if (box.hasHorizontalHint()) {
hHint = `${box.hint_id}: ${box.horizontal_hint}`;
}
}
if (upper_end.getGridType() === gridType.HINT) {
var box = upper_end.getHintBox()
if (box.hasVerticalHint()) {
vHint = `${box.hint_id}: ${box.vertical_hint}`;
}
}
this.infobox.horizontal_hint = hHint;
this.infobox.vertical_hint = vHint;
}
renderCell(el) {
switch (el.type) {
case gridType.LETTER: {
return html`<grid-letter grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' ></grid-letter>`;
}
case gridType.EMPTY: {
return html`<grid-box grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' ></grid-box>`;
}
case gridType.HINT: {
var vertical_hint = this.json_grid.grid[el.y][el.x].vertical_hint;
var horizontal_hint = this.json_grid.grid[el.y][el.x].horizontal_hint;
if (!vertical_hint) {
vertical_hint = "";
}
if (!horizontal_hint) {
horizontal_hint = "";
}
this.num_hints += 1;
return html`
<hint-box grid_id='${this.id}' gridCount='${this.gridCount}' x='${el.x}' y='${el.y}' horizontal_hint='${horizontal_hint}' vertical_hint='${vertical_hint}' hint_id=${this.num_hints}></hint-box>
`;
}
}
}
updateLetter(x, y, letter, revealed) {
var cell = this.grid[y][x];
if (cell.getGridType() != gridType.LETTER) {
console.error("received bad message");
}
cell.getGridLetter().updateLetter(letter, revealed)
if (cell.getGridLetter().solutionIndex >= 0) {
this.setSolutionLetter(
cell.getGridLetter().solutionIndex,
letter,
revealed
);
}
}
registerServerConnection(connection) {
this.serverConnection = connection
}
sendMessage(msg) {
if (!this.serverConnection) {
console.error("no server connection registered")
}
this.serverConnection.sendMessage(msg)
}
setSolutionLetter(solutionNumber, letter, revealed = false) {
this.solutionBox.setLetter(solutionNumber, letter, revealed);
const x = this.solution_locations[solutionNumber][1];
const y = this.solution_locations[solutionNumber][0];
console.log("update solution letter");
var old_val = this.grid[y][x].getGridLetter().value;
this.grid[y][x].getGridLetter().value = letter;
if (old_val != letter && !revealed) {
this.sendMessage({
'type': 'update',
'x': x,
'y': y,
'letter': letter
});
}
}
render() {
this.num_hints = 0;
console.log("refreshing grid");
var solution_length = 0;
if (this.solution_locations) {
solution_length = this.solution_locations.length;
}
return html`
<table>
${this.grid.map((row) => html`<tr>${row.map((el) => html`<td>${this.renderCell(el)}</td>`)}</tr>`)}
</table>
<solution-box id="solution-box", grid_id="${this.id}", length="${solution_length}" ></solution-box>
`;
}
}
customElements.define('crossword-grid', CrosswordGrid);