I'm making an Ultimate Tic-Tac-Toe game and I'm creating the grid/board.
How do I use generics recursively to make my grid have other grids inside of it (in its cells)? The depth level is unknown, this might have more than depth of 2... It could be a grid of a grid of a grid of a grid of cells i.e.
It's about the same thing as the leaf/branch problem. A branch can have leaves or other branches (not both at the same time in this case).
I've already tried a few things (using interfaces, defining custom types, etc..) but it was always giving the same errors (see below, in the errors part).
Here is the code I ended up with...
Cell.ts
import { CellValue } from "./CellValue";
export class Cell {
private value: CellValue;
constructor() {
}
public getValue(): CellValue {
return this.value;
}
}
TicTacToeGrid.ts
import { Cell } from "./Cell";
/**
* Represents the Tic Tac Toe grid.
*/
export class TicTacToeGrid<T = TicTacToeGrid|Cell> {
/**
* The grid can contain cells or other grids
* making it a grid of grids.
*/
private grid: Array<Array<T>> = [];
/**
* Creates a new grid and initiailzes it.
* @param {[number, number][]} sizes an array containing the sizes of each grid.
* The first grid has the size defined in the first element of the array. i.e. [3, 3] for a 3x3 grid.
* The others elements are the sizes for the sub-grids.
*/
constructor(sizes: [number, number][]) {
const size: [number, number] = sizes.splice(-1)[0]; // Get the size of this grid
for(let y = 0; y < size[1]; y++) {
this.grid.push();
for(let x = 0; x < size[0]; x++) {
this.grid[y].push();
this.grid[y][x] = sizes.length > 0 ? new TicTacToeGrid(sizes) : new Cell(); // if there still are size left in the array, create a new sub-grid with these sizes
}
}
}
/**
* Returns the content of the specified cell
* @param {number} x the x position of the cell whose content wants to be retrieved
* @param {number} y the y position of the cell whose content wants to be retrieved
*/
public getElement(x: number, y: number): T {
return this.grid[y][x];
}
}
index.ts
import { TicTacToeGrid } from "./TicTacToeGrid ";
import { Cell } from "./Cell";
const board: TicTacToeGrid<TicTacToeGrid<Cell>> = new TicTacToeGrid<TicTacToeGrid<Cell>>([[3, 3], [5, 5]]);
const value: number= board.getElement(2, 2).getElement(1, 1).getValue();
Everything works fine except the compiler throws 2 errors in TicTacToeGrid.js:
Type parameter 'T' has a circular default.
-> Ok, but how do I solve this?
Type 'Cell | TicTacToeGrid<unknown>' is not assignable to type 'T'. 'Cell | TicTacToeGrid<unknown>' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'. Type 'Cell' is not assignable to type 'T'. 'Cell' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{}'.
-> How do I deal with this? What does it exactly mean?