Render the Go board and connect it to the core #42
|
@ -0,0 +1 @@
|
||||||
|
export const assertNever = (_: never) => {};
|
|
@ -1,19 +1,25 @@
|
||||||
import { BoardElement, Color } from "core-types";
|
import { BoardElement, Color, Size, CoreRequest } from "core-types";
|
||||||
|
import { assertNever } from "../assertNever";
|
||||||
|
|
||||||
const MARGIN = 20;
|
const MARGIN = 20;
|
||||||
const BOARD_WIDTH = 800;
|
const BOARD_WIDTH = 800;
|
||||||
const BOARD_HEIGHT = 800;
|
const BOARD_HEIGHT = 800;
|
||||||
|
|
||||||
type Pixel = { x: number; y: number };
|
type Pixel = { x: number; y: number };
|
||||||
type Address = { column: number; row: number };
|
type Coordinate = { column: number; row: number };
|
||||||
|
|
||||||
|
export interface GoBoardProps {
|
||||||
|
board: BoardElement;
|
||||||
|
onClick: (_: CoreRequest) => void;
|
||||||
|
}
|
||||||
|
|
||||||
export class GoBoard {
|
export class GoBoard {
|
||||||
private board: BoardElement;
|
private board: BoardElement;
|
||||||
private pen: Pen;
|
private pen: Pen;
|
||||||
private cursorLocation: Address | null;
|
private cursorLocation: Coordinate | null;
|
||||||
canvas: HTMLCanvasElement;
|
canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
constructor(board: BoardElement) {
|
constructor({ board, onClick }: GoBoardProps) {
|
||||||
this.board = board;
|
this.board = board;
|
||||||
this.canvas = document.createElement("canvas");
|
this.canvas = document.createElement("canvas");
|
||||||
this.canvas.width = BOARD_WIDTH;
|
this.canvas.width = BOARD_WIDTH;
|
||||||
|
@ -43,9 +49,30 @@ export class GoBoard {
|
||||||
this.renderBoard();
|
this.renderBoard();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.canvas.onclick = (_) => {
|
||||||
|
console.log("clicked on ", this.cursorLocation);
|
||||||
|
if (this.cursorLocation) {
|
||||||
|
const intersection =
|
||||||
|
this.board.spaces[boardAddress(this.board.size, this.cursorLocation)];
|
||||||
|
switch (intersection.type) {
|
||||||
|
case "Unplayable":
|
||||||
|
break;
|
||||||
|
case "Empty":
|
||||||
|
console.log("need to run action: ", intersection.content);
|
||||||
|
onClick(intersection.content);
|
||||||
|
break;
|
||||||
|
case "Filled":
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assertNever(intersection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
setBoard(board: BoardElement) {
|
setBoard(board: BoardElement) {
|
||||||
|
console.log("setting an updated board: ", board);
|
||||||
this.board = board;
|
this.board = board;
|
||||||
|
|
||||||
this.pen = new Pen(
|
this.pen = new Pen(
|
||||||
|
@ -119,7 +146,7 @@ class Pen {
|
||||||
this.vspaceBetween = (height - margin * 2) / (rows - 1);
|
this.vspaceBetween = (height - margin * 2) / (rows - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
starPoint(ctx: CanvasRenderingContext2D, addr: Address) {
|
starPoint(ctx: CanvasRenderingContext2D, addr: Coordinate) {
|
||||||
ctx.fillStyle = "rgba(0, 0, 0, 1.0);";
|
ctx.fillStyle = "rgba(0, 0, 0, 1.0);";
|
||||||
const pixel = this.position(addr);
|
const pixel = this.position(addr);
|
||||||
ctx.moveTo(pixel.x, pixel.y);
|
ctx.moveTo(pixel.x, pixel.y);
|
||||||
|
@ -127,7 +154,7 @@ class Pen {
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
ghostStone(ctx: CanvasRenderingContext2D, addr: Address, color: Color) {
|
ghostStone(ctx: CanvasRenderingContext2D, addr: Coordinate, color: Color) {
|
||||||
switch (color) {
|
switch (color) {
|
||||||
case Color.White:
|
case Color.White:
|
||||||
ctx.fillStyle = "rgba(230, 230, 230, 0.5)";
|
ctx.fillStyle = "rgba(230, 230, 230, 0.5)";
|
||||||
|
@ -140,7 +167,7 @@ class Pen {
|
||||||
this.drawStone(ctx, addr);
|
this.drawStone(ctx, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
drawStone(ctx: CanvasRenderingContext2D, addr: Address) {
|
drawStone(ctx: CanvasRenderingContext2D, addr: Coordinate) {
|
||||||
const radius = this.hspaceBetween / 2 - 2;
|
const radius = this.hspaceBetween / 2 - 2;
|
||||||
const pixel = this.position(addr);
|
const pixel = this.position(addr);
|
||||||
ctx.moveTo(pixel.x, pixel.y);
|
ctx.moveTo(pixel.x, pixel.y);
|
||||||
|
@ -148,14 +175,14 @@ class Pen {
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
|
|
||||||
position(addr: Address): Pixel {
|
position(addr: Coordinate): Pixel {
|
||||||
return {
|
return {
|
||||||
x: this.margin + addr.column * this.hspaceBetween,
|
x: this.margin + addr.column * this.hspaceBetween,
|
||||||
y: this.margin + addr.row * this.vspaceBetween,
|
y: this.margin + addr.row * this.vspaceBetween,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
address(pixel: Pixel): Address | null {
|
address(pixel: Pixel): Coordinate | null {
|
||||||
if (
|
if (
|
||||||
Math.round(pixel.x) < this.margin ||
|
Math.round(pixel.x) < this.margin ||
|
||||||
Math.round(pixel.y) < this.margin
|
Math.round(pixel.y) < this.margin
|
||||||
|
@ -173,3 +200,6 @@ class Pen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const boardAddress = (size: Size, coordinate: Coordinate): number =>
|
||||||
|
coordinate.column + size.width * coordinate.row;
|
||||||
|
|
|
@ -1,21 +1,91 @@
|
||||||
import { GoBoard } from "./components/Board";
|
import { GoBoard } from "./components/Board";
|
||||||
|
import { CoreRequest, CoreResponse } from "core-types";
|
||||||
import { CoreApi, initCore } from "./coreApi";
|
import { CoreApi, initCore } from "./coreApi";
|
||||||
|
import { assertNever } from "./assertNever";
|
||||||
|
|
||||||
|
/*
|
||||||
|
const processResponse = (response: CoreResponse) => {
|
||||||
|
const root = document.getElementById("root");
|
||||||
|
if (!root) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
class UIState {
|
||||||
|
private currentView: GoBoard | null;
|
||||||
|
private rootElement: HTMLElement;
|
||||||
|
coreApi: CoreApi;
|
||||||
|
|
||||||
|
constructor(coreApi: CoreApi, root: HTMLElement) {
|
||||||
|
this.currentView = null;
|
||||||
|
this.rootElement = root;
|
||||||
|
this.coreApi = coreApi;
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
console.log("root element not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processResponse(response: CoreResponse) {
|
||||||
|
switch (response.type) {
|
||||||
|
case "PlayingFieldView":
|
||||||
|
if (this.currentView) {
|
||||||
|
this.currentView.setBoard(response.content.board);
|
||||||
|
} else {
|
||||||
|
this.currentView = new GoBoard({
|
||||||
|
board: response.content.board,
|
||||||
|
onClick: async (request: CoreRequest) => {
|
||||||
|
const response = await this.coreApi.dispatch(request);
|
||||||
|
this.processResponse(response);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.rootElement?.appendChild(this.currentView.canvas);
|
||||||
|
this.currentView.renderBoard();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.log("impossible branch: ", response);
|
||||||
|
alert("impossible branch");
|
||||||
|
// assertNever(response);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
let coreApi = await initCore();
|
let coreApi = await initCore();
|
||||||
let response = await coreApi.playingField();
|
let response = await coreApi.dispatch({ type: "PlayingField" });
|
||||||
|
const root = document.getElementById("root");
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
console.log("root element not present");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uiState = new UIState(coreApi, root);
|
||||||
|
uiState.processResponse(response);
|
||||||
|
|
||||||
|
/*
|
||||||
console.log("playing field response: ", response);
|
console.log("playing field response: ", response);
|
||||||
|
|
||||||
const root = document.getElementById("root");
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
alert("could not retrieve the app root container");
|
alert("could not retrieve the app root container");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const board = new GoBoard(response.board);
|
const board = new GoBoard({
|
||||||
|
board: response.content.board,
|
||||||
|
onClick: async (request: CoreRequest) => {
|
||||||
|
const response = await coreApi.dispatch(request);
|
||||||
|
},
|
||||||
|
});
|
||||||
root.appendChild(board.canvas);
|
root.appendChild(board.canvas);
|
||||||
console.log("constructed board: ", board);
|
console.log("constructed board: ", board);
|
||||||
board.renderBoard();
|
board.renderBoard();
|
||||||
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
Loading…
Reference in New Issue