Added demos in stanek

This commit is contained in:
Olivier Gagnon 2022-04-12 20:23:03 -04:00
parent 2b4b59b371
commit 3e357ab9a7
6 changed files with 294 additions and 85 deletions

67
src/CotMG/DummyGift.ts Normal file

@ -0,0 +1,67 @@
import { ActiveFragment } from "./ActiveFragment";
import { IStaneksGift } from "./IStaneksGift";
export class DummyGift implements IStaneksGift {
storedCycles = 0;
fragments: ActiveFragment[] = [];
_width: number;
_height: number;
constructor(width: number, height: number, fragments: ActiveFragment[]) {
this.fragments = fragments;
this._width = width;
this._height = height;
}
width(): number {
return this._width;
}
height(): number {
return this._height;
}
charge(): any {
throw new Error("unimplemented for dummy gift");
}
process(): any {
throw new Error("unimplemented for dummy gift");
}
effect(): any {
throw new Error("unimplemented for dummy gift");
}
canPlace(): any {
throw new Error("unimplemented for dummy gift");
}
place(): any {
throw new Error("unimplemented for dummy gift");
}
findFragment(): any {
throw new Error("unimplemented for dummy gift");
}
fragmentAt(worldX: number, worldY: number): ActiveFragment | undefined {
for (const aFrag of this.fragments) {
if (aFrag.fullAt(worldX, worldY)) {
return aFrag;
}
}
return undefined;
}
delete(): any {
throw new Error("unimplemented for dummy gift");
}
clear(): any {
throw new Error("unimplemented for dummy gift");
}
count(): any {
throw new Error("unimplemented for dummy gift");
}
inBonus(): any {
throw new Error("unimplemented for dummy gift");
}
prestigeAugmentation(): any {
throw new Error("unimplemented for dummy gift");
}
prestigeSourceFile(): any {
throw new Error("unimplemented for dummy gift");
}
}

@ -12,3 +12,26 @@ export function loadStaneksGift(saveString: string): void {
staneksGift = new StaneksGift(); staneksGift = new StaneksGift();
} }
} }
export function zeros(dimensions: number[]): any {
const array = [];
for (let i = 0; i < dimensions[0]; ++i) {
array.push(dimensions.length == 1 ? 0 : zeros(dimensions.slice(1)));
}
return array;
}
export function calculateGrid(gift: IStaneksGift): number[][] {
const newgrid = zeros([gift.width(), gift.height()]) as unknown as number[][];
for (let i = 0; i < gift.width(); i++) {
for (let j = 0; j < gift.height(); j++) {
const fragment = gift.fragmentAt(i, j);
if (!fragment) continue;
newgrid[i][j] = 1;
}
}
return newgrid;
}

@ -0,0 +1,33 @@
import { Box, Table } from "@mui/material";
import * as React from "react";
import { ActiveFragment } from "../ActiveFragment";
import { DummyGift } from "../DummyGift";
import { Grid } from "./Grid";
import { calculateGrid, zeros } from "../Helper";
interface IProps {
width: number;
height: number;
fragments: ActiveFragment[];
}
export function DummyGrid(props: IProps): React.ReactElement {
const gift = new DummyGift(props.width, props.height, props.fragments);
const activeGrid = calculateGrid(gift);
const ghostGrid = zeros([props.width, props.height]);
return (
<Box>
<Table>
<Grid
width={props.width}
height={props.height}
activeGrid={activeGrid}
ghostGrid={ghostGrid}
gift={gift}
enter={() => undefined}
click={() => undefined}
/>
</Table>
</Box>
);
}

60
src/CotMG/ui/Grid.tsx Normal file

@ -0,0 +1,60 @@
import { Table, TableBody, TableRow } from "@mui/material";
import * as React from "react";
import { ActiveFragment } from "../ActiveFragment";
import { IStaneksGift } from "../IStaneksGift";
import { Cell } from "./Cell";
interface IProps {
width: number;
height: number;
activeGrid: number[][];
ghostGrid: number[][];
gift: IStaneksGift;
enter(i: number, j: number): void;
click(i: number, j: number): void;
}
function randomColor(fragment: ActiveFragment): string {
// Can't set Math.random seed so copy casino. TODO refactor both RNG later.
let s1 = Math.pow((fragment.x + 1) * (fragment.y + 1), 10);
let s2 = s1;
let s3 = s1;
const colors = [];
for (let i = 0; i < 3; i++) {
s1 = (171 * s1) % 30269;
s2 = (172 * s2) % 30307;
s3 = (170 * s3) % 30323;
colors.push((s1 / 30269.0 + s2 / 30307.0 + s3 / 30323.0) % 1.0);
}
return `rgb(${colors[0] * 256}, ${colors[1] * 256}, ${colors[2] * 256})`;
}
export function Grid(props: IProps): React.ReactElement {
function color(worldX: number, worldY: number): string {
if (props.ghostGrid[worldX][worldY] && props.activeGrid[worldX][worldY]) return "red";
if (props.ghostGrid[worldX][worldY]) return "white";
if (props.activeGrid[worldX][worldY]) {
const fragment = props.gift.fragmentAt(worldX, worldY);
if (!fragment) throw new Error("ActiveFragment should not be null");
return randomColor(fragment);
}
return "";
}
// switch the width/length to make axis consistent.
const elems = [];
for (let j = 0; j < props.height; j++) {
const cells = [];
for (let i = 0; i < props.width; i++) {
cells.push(
<Cell key={i} onMouseEnter={() => props.enter(i, j)} onClick={() => props.click(i, j)} color={color(i, j)} />,
);
}
elems.push(<TableRow key={j}>{cells}</TableRow>);
}
return <TableBody>{elems}</TableBody>;
}

@ -1,62 +1,20 @@
import * as React from "react"; import * as React from "react";
import { Fragment, NoneFragment } from "../Fragment"; import { Fragment, NoneFragment } from "../Fragment";
import { ActiveFragment } from "../ActiveFragment";
import { FragmentType } from "../FragmentType"; import { FragmentType } from "../FragmentType";
import { IStaneksGift } from "../IStaneksGift"; import { IStaneksGift } from "../IStaneksGift";
import { Cell } from "./Cell";
import { FragmentInspector } from "./FragmentInspector"; import { FragmentInspector } from "./FragmentInspector";
import { FragmentSelector } from "./FragmentSelector"; import { FragmentSelector } from "./FragmentSelector";
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Button from "@mui/material/Button"; import Button from "@mui/material/Button";
import TableRow from "@mui/material/TableRow";
import TableBody from "@mui/material/TableBody";
import { Table } from "../../ui/React/Table"; import { Table } from "../../ui/React/Table";
import { Grid } from "./Grid";
function zeros(dimensions: number[]): any { import { zeros, calculateGrid } from "../Helper";
const array = [];
for (let i = 0; i < dimensions[0]; ++i) {
array.push(dimensions.length == 1 ? 0 : zeros(dimensions.slice(1)));
}
return array;
}
function randomColor(fragment: ActiveFragment): string {
// Can't set Math.random seed so copy casino. TODO refactor both RNG later.
let s1 = Math.pow((fragment.x + 1) * (fragment.y + 1), 10);
let s2 = s1;
let s3 = s1;
const colors = [];
for (let i = 0; i < 3; i++) {
s1 = (171 * s1) % 30269;
s2 = (172 * s2) % 30307;
s3 = (170 * s3) % 30323;
colors.push((s1 / 30269.0 + s2 / 30307.0 + s3 / 30323.0) % 1.0);
}
return `rgb(${colors[0] * 256}, ${colors[1] * 256}, ${colors[2] * 256})`;
}
interface IProps { interface IProps {
gift: IStaneksGift; gift: IStaneksGift;
} }
export function MainBoard(props: IProps): React.ReactElement { export function MainBoard(props: IProps): React.ReactElement {
function calculateGrid(gift: IStaneksGift): any {
const newgrid = zeros([gift.width(), gift.height()]);
for (let i = 0; i < gift.width(); i++) {
for (let j = 0; j < gift.height(); j++) {
const fragment = gift.fragmentAt(i, j);
if (!fragment) continue;
newgrid[i][j] = 1;
}
}
return newgrid;
}
const [grid, setGrid] = React.useState(calculateGrid(props.gift)); const [grid, setGrid] = React.useState(calculateGrid(props.gift));
const [ghostGrid, setGhostGrid] = React.useState(zeros([props.gift.width(), props.gift.height()])); const [ghostGrid, setGhostGrid] = React.useState(zeros([props.gift.width(), props.gift.height()]));
const [pos, setPos] = React.useState([0, 0]); const [pos, setPos] = React.useState([0, 0]);
@ -96,44 +54,11 @@ export function MainBoard(props: IProps): React.ReactElement {
setGrid(calculateGrid(props.gift)); setGrid(calculateGrid(props.gift));
} }
function color(worldX: number, worldY: number): string {
if (ghostGrid[worldX][worldY] && grid[worldX][worldY]) return "red";
if (ghostGrid[worldX][worldY]) return "white";
if (grid[worldX][worldY]) {
const fragment = props.gift.fragmentAt(worldX, worldY);
if (!fragment) throw new Error("ActiveFragment should not be null");
return randomColor(fragment);
}
return "";
}
function clear(): void { function clear(): void {
props.gift.clear(); props.gift.clear();
setGrid(zeros([props.gift.width(), props.gift.height()])); setGrid(zeros([props.gift.width(), props.gift.height()]));
} }
// switch the width/length to make axis consistent.
const elems = [];
for (let j = 0; j < props.gift.height(); j++) {
const cells = [];
for (let i = 0; i < props.gift.width(); i++) {
cells.push(
<Cell
key={i}
onMouseEnter={() => moveGhost(i, j, rotation)}
onClick={() => clickAt(i, j)}
color={color(i, j)}
/>,
);
}
elems.push(
<TableRow key={j} className="staneksgift_row">
{cells}
</TableRow>,
);
}
function updateSelectedFragment(fragment: Fragment): void { function updateSelectedFragment(fragment: Fragment): void {
setSelectedFragment(fragment); setSelectedFragment(fragment);
const newgrid = zeros([props.gift.width(), props.gift.height()]); const newgrid = zeros([props.gift.width(), props.gift.height()]);
@ -162,7 +87,15 @@ export function MainBoard(props: IProps): React.ReactElement {
<Button onClick={clear}>Clear</Button> <Button onClick={clear}>Clear</Button>
<Box display="flex"> <Box display="flex">
<Table> <Table>
<TableBody>{elems}</TableBody> <Grid
width={props.gift.width()}
height={props.gift.height()}
activeGrid={grid}
ghostGrid={ghostGrid}
gift={props.gift}
enter={(i, j) => moveGhost(i, j, rotation)}
click={(i, j) => clickAt(i, j)}
/>
</Table> </Table>
<FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} /> <FragmentInspector gift={props.gift} x={pos[0]} y={pos[1]} fragment={props.gift.fragmentAt(pos[0], pos[1])} />
</Box> </Box>

@ -7,6 +7,13 @@ import { IStaneksGift } from "../IStaneksGift";
import { Info } from "@mui/icons-material"; import { Info } from "@mui/icons-material";
import { dialogBoxCreate } from "../../ui/React/DialogBox"; import { dialogBoxCreate } from "../../ui/React/DialogBox";
import Typography from "@mui/material/Typography"; import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import { Table } from "@mui/material";
import { Grid } from "./Grid";
import { DummyGift } from "../DummyGift";
import { ActiveFragment } from "../ActiveFragment";
import { Fragments } from "../Fragment";
import { DummyGrid } from "./DummyGrid";
type IProps = { type IProps = {
staneksGift: IStaneksGift; staneksGift: IStaneksGift;
@ -64,13 +71,99 @@ export function StaneksGiftRoot({ staneksGift }: IProps): React.ReactElement {
charged. charged.
</Typography> </Typography>
{/* <DummyGrid
TODO: width={4}
Board showing a booster fragment touching a single stat fragment on one edge, labeled as providing a 10% bonus to the stat fragment. height={4}
Board showing a booster fragment touching a single stat fragment on many edges, labeled as providing a 10% bonus to the stat fragment. fragments={[
Board showing a booster fragment diagonal from a single stat fragment along multiple corners, labeled as providing no bonus to the stat fragment. new ActiveFragment({
Board showing a booster fragment touching multiple stat fragments, labeled as providing a 10% bonus to each stat fragment. x: 0,
*/} y: 0,
rotation: 0,
fragment: Fragments.find((f) => f.id === 5) ?? Fragments[0],
}),
new ActiveFragment({
x: 0,
y: 2,
rotation: 0,
fragment: Fragments.find((f) => f.id === 101) ?? Fragments[0],
}),
]}
/>
<Typography sx={{ fontStyle: "italic" }}>
This boost provides a bonus to the touching fragment
</Typography>
<DummyGrid
width={4}
height={4}
fragments={[
new ActiveFragment({
x: 0,
y: 1,
rotation: 3,
fragment: Fragments.find((f) => f.id === 100) ?? Fragments[0],
}),
new ActiveFragment({
x: 0,
y: 0,
rotation: 2,
fragment: Fragments.find((f) => f.id === 1) ?? Fragments[0],
}),
]}
/>
<Typography sx={{ fontStyle: "italic" }}>
Even though the booster touches many tiles, the bonus is only applied once.
</Typography>
<DummyGrid
width={4}
height={4}
fragments={[
new ActiveFragment({
x: 0,
y: 0,
rotation: 0,
fragment: Fragments.find((f) => f.id === 5) ?? Fragments[0],
}),
new ActiveFragment({
x: 2,
y: 0,
rotation: 0,
fragment: Fragments.find((f) => f.id === 105) ?? Fragments[0],
}),
]}
/>
<Typography sx={{ fontStyle: "italic" }}>
Even though the booster touches many tiles, the bonus is only applied once.
</Typography>
<DummyGrid
width={4}
height={4}
fragments={[
new ActiveFragment({
x: 0,
y: 0,
rotation: 1,
fragment: Fragments.find((f) => f.id === 27) ?? Fragments[0],
}),
new ActiveFragment({
x: 0,
y: 1,
rotation: 2,
fragment: Fragments.find((f) => f.id === 100) ?? Fragments[0],
}),
new ActiveFragment({
x: 2,
y: 0,
rotation: 1,
fragment: Fragments.find((f) => f.id === 30) ?? Fragments[0],
}),
]}
/>
<Typography sx={{ fontStyle: "italic" }}>
This booster provides bonus to all fragment it touches.
</Typography>
<br /> <br />
<Typography> <Typography>