Skip to content

Commit

Permalink
change some interfaces to abstract classes
Browse files Browse the repository at this point in the history
  • Loading branch information
Jamison-Chen committed Aug 12, 2023
1 parent 984052c commit 221ed42
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 83 deletions.
4 changes: 3 additions & 1 deletion js/humanPlayer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export default class HumanPlayer {
import { Player } from "./player";
export default class HumanPlayer extends Player {
constructor() {
super();
this.markPlaying = null;
this.winCount = 0;
}
Expand Down
4 changes: 0 additions & 4 deletions js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ function startP2CGame(shouldTrain) {
moveControlBar();
if (shouldTrain) {
document.addEventListener("completeTraining", onCompleteTraining);
// Visualize training process (event-driven, very slow)
// const game = new Playground(mlPlayer, new GraphPlayer());
// game.trainMachine(24, 12);
// Hide training process (iteration, very fast)
const game = new TrainingGround(mlPlayer, new GraphPlayer());
game.trainMachine(2400, 400);
}
Expand Down
4 changes: 3 additions & 1 deletion js/mlPlayer.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AutoPlayer } from "./player.js";
import Utils from "./utils.js";
class Node {
constructor(key) {
Expand All @@ -17,8 +18,9 @@ class Node {
this.children = [];
}
}
export class GraphPlayer {
export class GraphPlayer extends AutoPlayer {
constructor() {
super();
this.database = { BBBBBBBBB: new Node("BBBBBBBBB") };
this.path = [];
this.markPlaying = null;
Expand Down
6 changes: 3 additions & 3 deletions js/player.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export function isAutoPlayer(player) {
return ("moveWithOpponent" in player &&
typeof player.moveWithOpponent === "function");
export class Player {
}
export class AutoPlayer extends Player {
}
61 changes: 22 additions & 39 deletions js/playground.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isAutoPlayer } from "./player.js";
import { AutoPlayer } from "./player.js";
import { GraphPlayer } from "./mlPlayer.js";
import RandomPlayer from "./randomPlayer.js";
import HumanPlayer from "./humanPlayer.js";
Expand Down Expand Up @@ -38,23 +38,21 @@ export class Playground {
this.currentPlayer.select(position);
};
this.onPlayerMove = (e) => {
var _a;
const [r, c] = e.detail.position;
(_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[r][c].setMark(e.detail.markPlaying);
this.board?.matrix[r][c].setMark(e.detail.markPlaying);
const opponent = this.currentPlayer === this.player1 ? this.player2 : this.player1;
if (isAutoPlayer(opponent)) {
if (opponent instanceof AutoPlayer) {
opponent.moveWithOpponent([r, c], this.board.matrix);
}
this.judge();
};
this.onCallNextPlayer = () => {
var _a, _b;
const oldPlayerMark = (_a = this.currentPlayer) === null || _a === void 0 ? void 0 : _a.markPlaying;
const oldPlayerMark = this.currentPlayer?.markPlaying;
this.currentPlayer =
this.currentPlayer === this.player1 ? this.player2 : this.player1;
(_b = this.board) === null || _b === void 0 ? void 0 : _b.div.classList.replace(oldPlayerMark, this.currentPlayer.markPlaying);
this.board?.div.classList.replace(oldPlayerMark, this.currentPlayer.markPlaying);
if (!(this.currentPlayer instanceof HumanPlayer)) {
setTimeout(() => { var _a; return (_a = this.currentPlayer) === null || _a === void 0 ? void 0 : _a.select(); });
setTimeout(() => this.currentPlayer?.select());
}
};
this.onGameOver = (e) => {
Expand Down Expand Up @@ -122,25 +120,20 @@ export class Playground {
document.addEventListener("stop", this.onStop);
}
judge() {
var _a, _b, _c;
let winnerMark = null;
// Check each row
for (let i = 0; i < this.board.matrix.length; i++) {
if ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[i].every((cell) => {
var _a;
return (cell.mark === ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[i][0].mark) &&
if (this.board?.matrix[i].every((cell) => {
return (cell.mark === this.board?.matrix[i][0].mark &&
this.board.matrix[i][0].mark !== " ");
})) {
winnerMark = this.board.matrix[i][0].mark;
break;
}
}
if (winnerMark === null) {
// Check each column
for (let i = 0; i < this.board.matrix[0].length; i++) {
if ((_b = this.board) === null || _b === void 0 ? void 0 : _b.matrix.every((row) => {
var _a;
return (row[i].mark === ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[0][i].mark) &&
if (this.board?.matrix.every((row) => {
return (row[i].mark === this.board?.matrix[0][i].mark &&
this.board.matrix[0][i].mark !== " ");
})) {
winnerMark = this.board.matrix[0][i].mark;
Expand All @@ -149,7 +142,6 @@ export class Playground {
}
}
if (winnerMark === null) {
// Check each diagnal
const diagnal1 = [
this.board.matrix[0][0].mark,
this.board.matrix[1][1].mark,
Expand Down Expand Up @@ -178,7 +170,7 @@ export class Playground {
}
throw Error(`Cannot find winner with mark: ${winnerMark}`);
}
else if (!((_c = this.board) === null || _c === void 0 ? void 0 : _c.matrix.some((row) => row.some((cell) => cell.mark === " ")))) {
else if (!this.board?.matrix.some((row) => row.some((cell) => cell.mark === " "))) {
setTimeout(() => document.dispatchEvent(new CustomEvent("gameOver", {
detail: { winner: null },
})));
Expand Down Expand Up @@ -210,7 +202,6 @@ export class Playground {
}
Playground.endingScreenDiv.classList.remove("show");
this.board = this.initBoard();
// Choose and record first player
if (Math.random() >= 0.5) {
this.currentPlayer = this.player1;
this.player1.markPlaying = "O";
Expand All @@ -224,7 +215,7 @@ export class Playground {
this.p2StartCount++;
}
if (!(this.currentPlayer instanceof HumanPlayer)) {
setTimeout(() => { var _a; return (_a = this.currentPlayer) === null || _a === void 0 ? void 0 : _a.select(); });
setTimeout(() => this.currentPlayer?.select());
}
}
trainMachine(trainTimes, batch) {
Expand Down Expand Up @@ -290,7 +281,6 @@ export class TrainingGround extends Playground {
}));
}
startTrainEpoch() {
var _a, _b;
this.prepare();
while (this.remainingGames > 0) {
this.playerMove();
Expand Down Expand Up @@ -318,12 +308,12 @@ export class TrainingGround extends Playground {
break;
}
else {
const oldPlayerMark = (_a = this.currentPlayer) === null || _a === void 0 ? void 0 : _a.markPlaying;
const oldPlayerMark = this.currentPlayer?.markPlaying;
this.currentPlayer =
this.currentPlayer === this.player1
? this.player2
: this.player1;
(_b = this.board) === null || _b === void 0 ? void 0 : _b.div.classList.replace(oldPlayerMark, this.currentPlayer.markPlaying);
this.board?.div.classList.replace(oldPlayerMark, this.currentPlayer.markPlaying);
}
}
}
Expand All @@ -344,34 +334,28 @@ export class TrainingGround extends Playground {
}
}
playerMove() {
var _a, _b, _c;
const [r, c] = (_a = this.currentPlayer) === null || _a === void 0 ? void 0 : _a.select(false);
(_b = this.board) === null || _b === void 0 ? void 0 : _b.matrix[r][c].setMark((_c = this.currentPlayer) === null || _c === void 0 ? void 0 : _c.markPlaying);
const [r, c] = this.currentPlayer?.select(false);
this.board?.matrix[r][c].setMark(this.currentPlayer?.markPlaying);
const opponent = this.currentPlayer === this.player1 ? this.player2 : this.player1;
if (isAutoPlayer(opponent)) {
if (opponent instanceof AutoPlayer) {
opponent.moveWithOpponent([r, c], this.board.matrix);
}
}
judge() {
var _a, _b, _c;
let winnerMark = null;
// Check each row
for (let i = 0; i < this.board.matrix.length; i++) {
if ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[i].every((cell) => {
var _a;
return (cell.mark === ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[i][0].mark) &&
if (this.board?.matrix[i].every((cell) => {
return (cell.mark === this.board?.matrix[i][0].mark &&
this.board.matrix[i][0].mark !== " ");
})) {
winnerMark = this.board.matrix[i][0].mark;
break;
}
}
if (winnerMark === null) {
// Check each column
for (let i = 0; i < this.board.matrix[0].length; i++) {
if ((_b = this.board) === null || _b === void 0 ? void 0 : _b.matrix.every((row) => {
var _a;
return (row[i].mark === ((_a = this.board) === null || _a === void 0 ? void 0 : _a.matrix[0][i].mark) &&
if (this.board?.matrix.every((row) => {
return (row[i].mark === this.board?.matrix[0][i].mark &&
this.board.matrix[0][i].mark !== " ");
})) {
winnerMark = this.board.matrix[0][i].mark;
Expand All @@ -380,7 +364,6 @@ export class TrainingGround extends Playground {
}
}
if (winnerMark === null) {
// Check each diagnal
const diagnal1 = [
this.board.matrix[0][0].mark,
this.board.matrix[1][1].mark,
Expand All @@ -406,7 +389,7 @@ export class TrainingGround extends Playground {
}
throw Error(`Cannot find winner with mark: ${winnerMark}`);
}
else if (!((_c = this.board) === null || _c === void 0 ? void 0 : _c.matrix.some((row) => row.some((cell) => cell.mark === " ")))) {
else if (!this.board?.matrix.some((row) => row.some((cell) => cell.mark === " "))) {
this.isGameRunning = false;
}
return null;
Expand Down
4 changes: 3 additions & 1 deletion js/randomPlayer.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export default class RandomPlayer {
import { AutoPlayer } from "./player.js";
export default class RandomPlayer extends AutoPlayer {
constructor() {
super();
this.allChoices = [
[0, 0],
[0, 1],
Expand Down
5 changes: 3 additions & 2 deletions ts/humanPlayer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Player } from "./player";
import { MoveEvent } from "./playground";
import { MoveEvent } from "./playground.js";

export default class HumanPlayer implements Player {
export default class HumanPlayer extends Player {
public markPlaying: "O" | "X" | null;
public winCount: number;
public constructor() {
super();
this.markPlaying = null;
this.winCount = 0;
}
Expand Down
5 changes: 3 additions & 2 deletions ts/main.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Notice the .js in path below
import {
Playground,
CompleteTrainingEvent,
Expand Down Expand Up @@ -44,11 +45,11 @@ function startP2CGame(shouldTrain: boolean): void {
"completeTraining",
onCompleteTraining as EventListener
);
// Visualize training process (event-driven, very slow)
//// Visualize training process (event-driven, very slow)
// const game = new Playground(mlPlayer, new GraphPlayer());
// game.trainMachine(24, 12);

// Hide training process (iteration, very fast)
//// Hide training process (iteration, very fast)
const game = new TrainingGround(mlPlayer, new GraphPlayer());
game.trainMachine(2400, 400);
} else {
Expand Down
5 changes: 3 additions & 2 deletions ts/mlPlayer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AutoPlayer, Player } from "./player.js";
import { AutoPlayer } from "./player.js";
import { Cell, MoveEvent } from "./playground.js";
import Utils from "./utils.js";

Expand Down Expand Up @@ -35,12 +35,13 @@ type NodeWithRotateCount = {
rotateCount: number;
};

export class GraphPlayer implements Player, AutoPlayer {
export class GraphPlayer extends AutoPlayer {
private path: PathInfo[];
private database: { [key: string]: Node };
public markPlaying: "O" | "X" | null;
public winCount: number;
public constructor() {
super();
this.database = { BBBBBBBBB: new Node("BBBBBBBBB") };
this.path = [];
this.markPlaying = null;
Expand Down
24 changes: 10 additions & 14 deletions ts/player.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import { Cell } from "./playground";
import { Cell } from "./playground.js";

export interface Player {
markPlaying: "O" | "X" | null;
winCount: number;
select(...arg: any): [number, number];
export abstract class Player {
public abstract markPlaying: "O" | "X" | null;
public abstract winCount: number;
public abstract select(...arg: any): [number, number];
}

export interface AutoPlayer extends Player {
moveWithOpponent(position: [number, number], latestBoard: Cell[][]): void;
}

export function isAutoPlayer(player: Player): player is AutoPlayer {
return (
"moveWithOpponent" in player &&
typeof player.moveWithOpponent === "function"
);
export abstract class AutoPlayer extends Player {
public abstract moveWithOpponent(
position: [number, number],
latestBoard: Cell[][]
): void;
}
7 changes: 3 additions & 4 deletions ts/playground.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Player, isAutoPlayer } from "./player.js";
import { AutoPlayer, Player } from "./player.js";
import { GraphPlayer } from "./mlPlayer.js";
import RandomPlayer from "./randomPlayer.js";
import HumanPlayer from "./humanPlayer.js";
Expand Down Expand Up @@ -96,7 +96,7 @@ export class Playground {

const opponent =
this.currentPlayer === this.player1 ? this.player2 : this.player1;
if (isAutoPlayer(opponent)) {
if (opponent instanceof AutoPlayer) {
opponent.moveWithOpponent([r, c], this.board!.matrix);
}
this.judge();
Expand Down Expand Up @@ -435,7 +435,7 @@ export class TrainingGround extends Playground {

const opponent =
this.currentPlayer === this.player1 ? this.player2 : this.player1;
if (isAutoPlayer(opponent)) {
if (opponent instanceof AutoPlayer) {
opponent.moveWithOpponent([r, c], this.board!.matrix);
}
}
Expand Down Expand Up @@ -498,7 +498,6 @@ export class TrainingGround extends Playground {
winnerMark = diagnal2[0] as "O" | "X";
}
}

if (winnerMark) {
this.isGameRunning = false;
for (const player of [this.player1, this.player2]) {
Expand Down
7 changes: 4 additions & 3 deletions ts/randomPlayer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { AutoPlayer, Player } from "./player";
import { Cell, MoveEvent } from "./playground";
import { AutoPlayer } from "./player.js";
import { Cell, MoveEvent } from "./playground.js";

export default class RandomPlayer implements Player, AutoPlayer {
export default class RandomPlayer extends AutoPlayer {
private allChoices: [number, number][];
private availableChoices: [number, number][];
public markPlaying: "O" | "X" | null;
public winCount: number;
public constructor() {
super();
this.allChoices = [
[0, 0],
[0, 1],
Expand Down
Loading

0 comments on commit 221ed42

Please sign in to comment.