From 291895a75856408788925bfb34e4c085c40efbaf Mon Sep 17 00:00:00 2001 From: Determinant Date: Wed, 10 Apr 2019 01:09:41 -0400 Subject: finish version 1.0 --- src/Snow.tsx | 220 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 190 insertions(+), 30 deletions(-) (limited to 'src/Snow.tsx') 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 { - 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 { } 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 { 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 { } } } + }); + + 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 { } 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 { reset() { this.setState({ - colorMatrix: Snow.genMatrix(), - ticking: false + ticking: false, + loaded: false }); } @@ -179,22 +283,60 @@ class Snow extends React.Component { return ( - + + { + 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}}]}}}/> + + + n = + + + this.setState({n: event.target.value, nError: false})}/> + 2 + {this.state.nError && + n must be in 2..40} + + k = 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 && + k must be in 1..n} @@ -203,10 +345,14 @@ class Snow extends React.Component { 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 && + alpha must be in (k/2, k]} @@ -215,10 +361,14 @@ class Snow extends React.Component { 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 && + nodesPerTick must be in 1..n} @@ -230,7 +380,11 @@ class Snow extends React.Component { 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 && + maxInactiveTicks must be in 1..1000000} @@ -252,21 +406,27 @@ class Snow extends React.Component {
+ + disabled={this.state.ticking}>Run + + + disabled={!this.state.ticking}>Stop + + +
-- cgit v1.2.3