diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/About.tsx | 10 | ||||
-rw-r--r-- | src/Grid.tsx | 48 | ||||
-rw-r--r-- | src/Snow.tsx | 268 | ||||
-rw-r--r-- | src/index.html | 2 | ||||
-rw-r--r-- | src/index.tsx | 2 |
5 files changed, 307 insertions, 23 deletions
diff --git a/src/About.tsx b/src/About.tsx index 9aae40c..118b961 100644 --- a/src/About.tsx +++ b/src/About.tsx @@ -60,16 +60,6 @@ function About(props: AboutProps) { 73d at tedyin dot com </ListItem> <ListItem> - <span className={classes.infoField}>GitHub:</span> - <Link href="https://github.com/Determinant/chromicle" target="_blank" rel="noopener"> - Determinant/chromicle - </Link> - </ListItem> - <ListItem> - <span className={classes.infoField}>About Me:</span> - <Link href="https://www.cs.cornell.edu/~tedyin/" target="_blank" rel="noopener"> - https://www.cs.cornell.edu/~tedyin/ - </Link> </ListItem> <ListItem> <span className={classes.infoField}>Buy me a cup of coffee:</span> diff --git a/src/Grid.tsx b/src/Grid.tsx index 65cf2ec..f68c550 100644 --- a/src/Grid.tsx +++ b/src/Grid.tsx @@ -1,17 +1,57 @@ import React from 'react'; import 'typeface-roboto'; import MGrid from '@material-ui/core/Grid'; +import orange from '@material-ui/core/colors/orange'; +import blue from '@material-ui/core/colors/blue'; +import { Theme, withStyles, StyleRules } from '@material-ui/core/styles'; +import Color from 'color'; +const styles = (theme: Theme): StyleRules => ({ + gridRow: { + height: 24, + textAlign: 'center' + }, + gridCell: { + height: 20, + width: 20, + margin: 2, + display: 'inline-block' + } +}); interface GridProps { - classes: {} + classes: { + gridRow: string, + gridCell: string + }, + data: {d: number[], col: number}[][] } class Grid extends React.Component<GridProps> { + static getColor(s: {d: number[], col: number}) { + const color = [orange[300], blue[300]]; + let {d, col} = s; + return Color(color[col]).darken(Math.min(d[col] / 10, 0.6)).hex(); + } render() { - const { classes } = this.props; - return (<div></div>); + const { classes, data } = this.props; + return ( + <div style={{margin: '0 auto'}}> + { + data.map((row, i) => ( + <div key={i} className={classes.gridRow}> + { + row.map((cell, j) => ( + <div key={j} className={classes.gridCell} style={{backgroundColor: Grid.getColor(cell)}}> + </div> + )) + } + </div> + )) + } + </div> + ); } } -export default Grid; +export default withStyles(styles)(Grid); diff --git a/src/Snow.tsx b/src/Snow.tsx index 47a1c06..9ab4dfd 100644 --- a/src/Snow.tsx +++ b/src/Snow.tsx @@ -1,23 +1,277 @@ import React from 'react'; import MGrid from '@material-ui/core/Grid'; -import { Theme, withStyles } from '@material-ui/core/styles'; +import { Theme, withStyles, StyleRules } from '@material-ui/core/styles'; +import TextField from '@material-ui/core/TextField'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +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'; -interface SnowProps { - classes: {} -} - -const styles = (theme: Theme) => ({ +const styles = (theme: Theme): StyleRules => ({ + inputLabel: { + fontSize: 16, + paddingRight: 0, + textAlign: 'right' + }, + inputValue: { + textAlign: 'left' + }, buttonSpacer: { marginBottom: theme.spacing.unit * 4, }, + bottomButtons: { + marginTop: 10, + textAlign: 'center', + minWidth: 650 + }, + slider: { + padding: '22px 0px', + } }); +interface SnowProps { + classes: { + inputLabel: string, + inputValue: string, + buttonSpacer: string, + bottomButtons: string, + slider: string + } +} + +function getRandomInt(max: number) { + return Math.floor(Math.random() * Math.floor(max)); +} + +function getRandomSubarray(arr: number[], size: number) { + let shuffled = arr.slice(0), i = arr.length, min = i - size, temp, index; + while (i-- > min) { + index = Math.floor((i + 1) * Math.random()); + temp = shuffled[index]; + shuffled[index] = shuffled[i]; + shuffled[i] = temp; + } + return shuffled.slice(min); +} + class Snow extends React.Component<SnowProps> { + + static genMatrix(n = 20) { + let d = []; + for (let i = 0; i < n; i++) + { + let r = []; + for (let j = 0; j < n; j++) + r.push({d: [0, 0], col: getRandomInt(2)}); + d.push(r); + } + return d; + } + + state = { + colorMatrix: Snow.genMatrix(), + k: 10, + alpha: 8, + nodesPerTick: 10, + maxInactiveTicks: 200, + ticking: false, + simulationSpeed: 100 + }; + + config = { + k: 10, + alpha: 8, + nodesPerTick: 10, + maxInactiveTicks: 200, + inactiveTicks: 0 + }; + + getNodeState(n: number, u: number) { + let r = Math.floor(u / n); + let c = u % n; + return this.state.colorMatrix[r][c]; + } + + setNodeState(n: number, u: number, s: {d: number[], col: number}) { + let r = Math.floor(u / n); + let c = u % n; + let m = [...this.state.colorMatrix]; + m[r][c] = s; + this.setState({colorMatrix: m}); + } + + tick(n: number, m: number) { + let N = n * n; + let active = false; + for (let i = 0; i < m; i++) + { + let u = getRandomInt(N); + let peers = []; + for (let j = 0; j < N; j++) + if (j != u) peers.push(j); + let sample = getRandomSubarray(peers, this.config.k); + let cnt = [0, 0]; + sample.forEach((v) => { + let ss = this.getNodeState(n, v); + cnt[ss.col]++; + }); + let s = this.getNodeState(n, u); + for (let c = 0; c < 2; c++) + { + if (cnt[c] > this.config.alpha) + { + s.d[c]++; + if (s.d[c] > s.d[s.col]) + { + if (s.col != c) active = true; + s.col = c; + this.setNodeState(n, u, s); + } + } + } + } + return active; + } + + pauseTick() { + this.setState({ticking: false}); + } + + startTick() { + this.config.alpha = this.state.alpha; + this.config.k = this.state.k; + this.config.nodesPerTick = this.state.nodesPerTick; + this.config.inactiveTicks = 0; + this.config.maxInactiveTicks = this.state.maxInactiveTicks; + this.autoTick(); + } + + autoTick() { + this.setState({ticking: true}); + setTimeout(() => { + let active = this.tick(20, this.config.nodesPerTick); + console.log(active); + if (!active) + { + if (++this.config.inactiveTicks > this.config.maxInactiveTicks) + { + this.pauseTick(); + return; + } + } + else + this.config.inactiveTicks = 0; + if (this.state.ticking) this.autoTick(); + }, 1000 / this.state.simulationSpeed); + } + + reset() { + this.setState({ + colorMatrix: Snow.genMatrix(), + ticking: false + }); + } + render() { const { classes } = this.props; return ( - <MGrid container spacing={16} style={{minWidth: 700}}> + <MGrid container spacing={16} style={{minWidth: 600, maxWidth: 1600}}> + <MGrid item lg={6} xs={12}> + <Grid data={this.state.colorMatrix} /> + </MGrid> + <MGrid item lg={6} xs={12}> + <Table> + <TableBody> + <TableRow> + <TableCell className={classes.inputLabel}> + k = + </TableCell> + <TableCell> + <TextField + inputProps={{ className: classes.inputValue } as React.CSSProperties} + value={this.state.k} + disabled={this.state.ticking} + onChange={event => this.setState({k: event.target.value})}/> + </TableCell> + </TableRow> + <TableRow> + <TableCell className={classes.inputLabel}> + alpha = + </TableCell> + <TableCell> + <TextField + inputProps={{ className: classes.inputValue } as React.CSSProperties} + value={this.state.alpha} + disabled={this.state.ticking} + onChange={event => this.setState({alpha: event.target.value})}/> + </TableCell> + </TableRow> + <TableRow> + <TableCell className={classes.inputLabel}> + nodesPerTick = + </TableCell> + <TableCell> + <TextField + inputProps={{ className: classes.inputValue } as React.CSSProperties} + value={this.state.nodesPerTick} + disabled={this.state.ticking} + onChange={event => this.setState({nodesPerTick: event.target.value})}/> + </TableCell> + </TableRow> + <TableRow> + <TableCell className={classes.inputLabel}> + maxInactiveTicks = + </TableCell> + <TableCell> + <TextField + inputProps={{ className: classes.inputValue } as React.CSSProperties} + value={this.state.maxInactiveTicks} + disabled={this.state.ticking} + onChange={event => this.setState({maxInactiveTicks: event.target.value})}/> + </TableCell> + </TableRow> + <TableRow> + <TableCell className={classes.inputLabel}> + simulationSpeed + </TableCell> + <TableCell> + <Slider + classes={{ container: classes.slider }} + value={this.state.simulationSpeed} + min={1} + max={1000} + onChange={(_, value) => this.setState({simulationSpeed: value})} /> + </TableCell> + </TableRow> + </TableBody> + </Table> + <div className={classes.buttonSpacer} /> + <div className={classes.bottomButtons}> + <MGrid container spacing={16}> + <MGrid item lg={4} xs={12}> + <Button + variant="contained" color="primary" + onClick={event => this.startTick()} + disabled={this.state.ticking}>Start</Button> + </MGrid> + <MGrid item lg={4} xs={12}> + <Button + variant="contained" color="primary" + onClick={event => this.pauseTick()} + disabled={!this.state.ticking}>Pause</Button> + </MGrid> + <MGrid item lg={4} xs={12}> + <Button + variant="contained" color="primary" + onClick={event => this.reset()}>Reset</Button> + </MGrid> + </MGrid> + </div> + </MGrid> </MGrid> ); } diff --git a/src/index.html b/src/index.html index a51779c..708c4fe 100644 --- a/src/index.html +++ b/src/index.html @@ -8,7 +8,7 @@ /> <meta name="theme-color" content="#000000" /> <link rel="stylesheet" href="/fonts/TypoPRO-FantasqueSansMono-Regular.css" /> - <title>Chromicle</title> + <title>Snow</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> diff --git a/src/index.tsx b/src/index.tsx index da751ca..ad08a87 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -125,7 +125,7 @@ class MainTabs extends React.Component<MainTabsProps> { {console.log(location)} <Route exact path="/snow" component={Snow} /> <Route exact path="/about" component={About} /> - <Route exact path="/" render={() => <Redirect to="/settings" />}/> + <Route exact path="/" render={() => <Redirect to="/snow" />}/> </Switch> </div> </CSSTransition> |