aboutsummaryrefslogtreecommitdiff
path: root/src/Snow.tsx
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2019-04-10 01:09:41 -0400
committerDeterminant <ted.sybil@gmail.com>2019-04-10 01:09:41 -0400
commit291895a75856408788925bfb34e4c085c40efbaf (patch)
tree4fe1ea3e1b1faf5012de93104c49032dc3937a52 /src/Snow.tsx
parent94330abf2d1ba606976ec4f2dc10277b78cdd036 (diff)
finish version 1.0
Diffstat (limited to 'src/Snow.tsx')
-rw-r--r--src/Snow.tsx220
1 files changed, 190 insertions, 30 deletions
diff --git a/src/Snow.tsx b/src/Snow.tsx
index a391f0a..89c5073 100644
--- a/src/Snow.tsx
+++ b/src/Snow.tsx
@@ -8,13 +8,17 @@ import TableRow from '@material-ui/core/TableRow';
import TableCell from '@material-ui/core/TableCell';
import Button from '@material-ui/core/Button';
import Slider from '@material-ui/lab/Slider';
-import Grid from './Grid';
+import FormGroup from '@material-ui/core/FormGroup';
+import Grid, {getNodeColor} from './Grid';
+import { Line } from 'react-chartjs-2';
+import Color from 'color';
const styles = (theme: Theme): StyleRules => ({
inputLabel: {
fontSize: 16,
paddingRight: 0,
- textAlign: 'right'
+ textAlign: 'right',
+ width: '30%'
},
inputValue: {
textAlign: 'left'
@@ -28,6 +32,15 @@ const styles = (theme: Theme): StyleRules => ({
},
slider: {
padding: '22px 0px',
+ },
+ errorHint: {
+ fontSize: 16,
+ paddingLeft: 16,
+ lineHeight: '32px',
+ color: theme.palette.secondary.main
+ },
+ grid: {
+ textAlign: 'center'
}
});
@@ -37,7 +50,9 @@ interface SnowProps {
inputValue: string,
buttonSpacer: string,
bottomButtons: string,
- slider: string
+ slider: string,
+ errorHint: string,
+ grid: string
}
}
@@ -56,9 +71,11 @@ function getRandomSubarray(arr: number[], size: number) {
return shuffled.slice(min);
}
+const watchedD = [15, 10, 5, 1];
+
class Snow extends React.Component<SnowProps> {
- static genMatrix(n = 20) {
+ static genMatrix(n: number) {
let d = [];
for (let i = 0; i < n; i++)
{
@@ -71,16 +88,31 @@ class Snow extends React.Component<SnowProps> {
}
state = {
- colorMatrix: Snow.genMatrix(),
- k: 10,
- alpha: 8,
- nodesPerTick: 10,
- maxInactiveTicks: 200,
+ colorMatrix: Snow.genMatrix(20),
+ n: '20',
+ k: '10',
+ alpha: '8',
+ nodesPerTick: '20',
+ maxInactiveTicks: '200',
+ loaded: true,
ticking: false,
- simulationSpeed: 100
+ simulationSpeed: 100,
+ dialogOpen: false,
+ dialogMsg: {title: '', message: ''},
+ nError: false,
+ kError: false,
+ alphaError: false,
+ nodesPerTickError: false,
+ maxInactiveTicksError: false,
+ dcnts: [watchedD.map(() => [] as number[]),
+ watchedD.map(() => [] as number[])] as number[][][],
+ ticks: [] as number[],
+ N: 400
};
config = {
+ iter: 0,
+ n: 20,
k: 10,
alpha: 8,
nodesPerTick: 10,
@@ -105,8 +137,10 @@ class Snow extends React.Component<SnowProps> {
tick(n: number, m: number) {
let N = n * n;
let active = false;
- for (let i = 0; i < m; i++)
- {
+
+ let nodes = [];
+ for (let j = 0; j < N; j++) nodes.push(j);
+ getRandomSubarray(nodes, m).forEach(v => {
let u = getRandomInt(N);
let peers = [];
for (let j = 0; j < N; j++)
@@ -131,6 +165,30 @@ class Snow extends React.Component<SnowProps> {
}
}
}
+ });
+
+ if (this.config.iter % 10 == 0)
+ {
+ let dcnts = [];
+ for (let c = 0; c < 2; c++)
+ {
+ dcnts.push(watchedD.map((d, i) => {
+ let dcnt = 0;
+ for (let i = 0; i < n; i++)
+ for (let j = 0; j < n; j++)
+ {
+ const s = this.state.colorMatrix[i][j];
+ if (s.d[c] >= d)
+ dcnt++;
+ }
+ if (c == 0) dcnt = -dcnt;
+ return [...this.state.dcnts[c][i], dcnt].splice(-50);
+ }));
+ }
+ this.setState({
+ dcnts: dcnts,
+ ticks: [...this.state.ticks, this.config.iter].splice(-50)
+ });
}
return active;
}
@@ -140,19 +198,65 @@ class Snow extends React.Component<SnowProps> {
}
startTick() {
- this.config.alpha = this.state.alpha;
- this.config.k = this.state.k;
- this.config.nodesPerTick = this.state.nodesPerTick;
+ const n = Number(this.state.n);
+ const N = n * n;
+ const k = Number(this.state.k);
+ const alpha = Number(this.state.alpha);
+ const nodesPerTick = Number(this.state.nodesPerTick);
+ const maxInactiveTicks = Number(this.state.maxInactiveTicks);
+
+ if (!Number.isInteger(n) || n < 2 || n > 40)
+ {
+ this.setState({ nError: true });
+ return;
+ }
+ if (!Number.isInteger(k) || k < 1 || k > N)
+ {
+ this.setState({ kError: true });
+ return;
+ }
+ if (!Number.isInteger(alpha) || !(k / 2 < alpha && alpha <= k))
+ {
+ this.setState({ alphaError: true });
+ return;
+ }
+ if (!Number.isInteger(nodesPerTick) || nodesPerTick < 1 || nodesPerTick > N)
+ {
+ this.setState({ nodesPerTickError: true });
+ return;
+ }
+ if (!Number.isInteger(maxInactiveTicks) || maxInactiveTicks < 1 || maxInactiveTicks > 1e6)
+ {
+ this.setState({ maxInactiveTicksError: true });
+ return;
+ }
+
+ if (!this.state.loaded)
+ {
+ this.config.iter = 0;
+ this.config.n = n;
+ this.setState({
+ loaded: true,
+ colorMatrix: Snow.genMatrix(this.config.n),
+ dcnts: [watchedD.map(() => [] as number[]),
+ watchedD.map(() => [] as number[])],
+ ticks: [],
+ N: n * n
+ });
+ }
+ this.config.alpha = alpha;
+ this.config.k = k;
+ this.config.nodesPerTick = nodesPerTick;
this.config.inactiveTicks = 0;
- this.config.maxInactiveTicks = this.state.maxInactiveTicks;
+ this.config.maxInactiveTicks = maxInactiveTicks;
this.autoTick();
}
autoTick() {
this.setState({ticking: true});
setTimeout(() => {
- let active = this.tick(20, this.config.nodesPerTick);
- console.log(active);
+ let active = this.tick(this.config.n, this.config.nodesPerTick);
+ this.config.iter++;
if (!active)
{
if (++this.config.inactiveTicks > this.config.maxInactiveTicks)
@@ -169,8 +273,8 @@ class Snow extends React.Component<SnowProps> {
reset() {
this.setState({
- colorMatrix: Snow.genMatrix(),
- ticking: false
+ ticking: false,
+ loaded: false
});
}
@@ -179,22 +283,60 @@ class Snow extends React.Component<SnowProps> {
return (
<MGrid container spacing={16} style={{minWidth: 600}}>
- <MGrid item lg={6} xs={12}>
+ <MGrid item lg={6} xs={12} className={classes.grid}>
<Grid data={this.state.colorMatrix} />
+ <Line data={() => {
+ let datasets = this.state.dcnts.map((dd, c) => dd.map((line, i) => {
+ const base = getNodeColor(watchedD[i], c);
+ return {
+ data: line,
+ label: `${c == 0 ? 'A' : 'B'}(d-${watchedD[i]})`,
+ borderColor: base,
+ backgroundColor: Color(base).fade(0.5).rgb().string(),
+ borderWidth: 2
+ };
+ })).flat();
+ return {
+ datasets,
+ labels: this.state.ticks
+ }
+ }}
+ options={{ scales: { yAxes: [{ ticks: {min: -this.state.N, max: this.state.N}}]}}}/>
</MGrid>
<MGrid item lg={4} xs={12}>
<Table>
<TableBody>
<TableRow>
<TableCell className={classes.inputLabel}>
+ n =
+ </TableCell>
+ <TableCell>
+ <TextField
+ inputProps={{ className: classes.inputValue, maxLength: 2 } as React.CSSProperties}
+ value={this.state.n}
+ disabled={this.state.loaded}
+ style={{width: 40}}
+ error={this.state.nError}
+ onChange={event => this.setState({n: event.target.value, nError: false})}/>
+ <sup>2</sup>
+ {this.state.nError &&
+ <span className={classes.errorHint}>n must be in 2..40</span>}
+ </TableCell>
+ </TableRow>
+ <TableRow>
+ <TableCell className={classes.inputLabel}>
k =
</TableCell>
<TableCell>
<TextField
- inputProps={{ className: classes.inputValue } as React.CSSProperties}
+ inputProps={{ className: classes.inputValue, maxLength: 4 } as React.CSSProperties}
value={this.state.k}
disabled={this.state.ticking}
- onChange={event => this.setState({k: event.target.value})}/>
+ style={{width: 40}}
+ error={this.state.kError}
+ onChange={event => this.setState({k: event.target.value, kError: false})}/>
+ {this.state.kError &&
+ <span className={classes.errorHint}>k must be in 1..n</span>}
</TableCell>
</TableRow>
<TableRow>
@@ -203,10 +345,14 @@ class Snow extends React.Component<SnowProps> {
</TableCell>
<TableCell>
<TextField
- inputProps={{ className: classes.inputValue } as React.CSSProperties}
+ inputProps={{ className: classes.inputValue, maxLength: 4 } as React.CSSProperties}
value={this.state.alpha}
disabled={this.state.ticking}
- onChange={event => this.setState({alpha: event.target.value})}/>
+ style={{width: 40}}
+ error={this.state.alphaError}
+ onChange={event => this.setState({alpha: event.target.value, alphaError: false})}/>
+ {this.state.alphaError &&
+ <span className={classes.errorHint}>alpha must be in (k/2, k]</span>}
</TableCell>
</TableRow>
<TableRow>
@@ -215,10 +361,14 @@ class Snow extends React.Component<SnowProps> {
</TableCell>
<TableCell>
<TextField
- inputProps={{ className: classes.inputValue } as React.CSSProperties}
+ inputProps={{ className: classes.inputValue, maxLength: 4 } as React.CSSProperties}
value={this.state.nodesPerTick}
disabled={this.state.ticking}
- onChange={event => this.setState({nodesPerTick: event.target.value})}/>
+ style={{width: 40}}
+ error={this.state.nodesPerTickError}
+ onChange={event => this.setState({nodesPerTick: event.target.value, nodesPerTickError: false})}/>
+ {this.state.nodesPerTickError &&
+ <span className={classes.errorHint}>nodesPerTick must be in 1..n</span>}
</TableCell>
</TableRow>
<TableRow>
@@ -230,7 +380,11 @@ class Snow extends React.Component<SnowProps> {
inputProps={{ className: classes.inputValue } as React.CSSProperties}
value={this.state.maxInactiveTicks}
disabled={this.state.ticking}
- onChange={event => this.setState({maxInactiveTicks: event.target.value})}/>
+ style={{width: 50}}
+ error={this.state.maxInactiveTicksError}
+ onChange={event => this.setState({maxInactiveTicks: event.target.value, maxInactiveTicksError: false})}/>
+ {this.state.maxInactiveTicksError &&
+ <span className={classes.errorHint}>maxInactiveTicks must be in 1..1000000</span>}
</TableCell>
</TableRow>
<TableRow>
@@ -252,21 +406,27 @@ class Snow extends React.Component<SnowProps> {
<div className={classes.bottomButtons}>
<MGrid container item spacing={16}>
<MGrid item lg={4} xs={12}>
+ <FormGroup>
<Button
variant="contained" color="primary"
onClick={event => this.startTick()}
- disabled={this.state.ticking}>Start</Button>
+ disabled={this.state.ticking}>Run</Button>
+ </FormGroup>
</MGrid>
<MGrid item lg={4} xs={12}>
+ <FormGroup>
<Button
variant="contained" color="primary"
onClick={event => this.pauseTick()}
- disabled={!this.state.ticking}>Pause</Button>
+ disabled={!this.state.ticking}>Stop</Button>
+ </FormGroup>
</MGrid>
<MGrid item lg={4} xs={12}>
+ <FormGroup>
<Button
variant="contained" color="primary"
onClick={event => this.reset()}>Reset</Button>
+ </FormGroup>
</MGrid>
</MGrid>
</div>