aboutsummaryrefslogblamecommitdiff
path: root/src/Snow.tsx
blob: 4bba42214819dc9a03bef485509ecd695b0b8534 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

                                           







                                                                         



                                                    
 



                                               

                           



                         


                                             


                            


                            








                                           
     

   





                              


                          

















                                                                             

                                
                                               
 
                                 











                                                          






                                        
                       











                                                                    


              

                























                                                                       



                                                  























                                                                 























                                                                          








                                        
















































                                                                                                  
                                      
                                                        





                                       

                                                                            















                                                                               

                           


           






                                             



                                       
                                                                  
                                                                    




                                                                                   
















                                                                                                        
                        
                                           




                                                                               



                                                                  
















                                                                                                               



                                    
                                                                                                               

                                                         




                                                                                                       







                                                                  
                                                                                                               

                                                         




                                                                                                               







                                                                  
                                                                                                               

                                                           




                                                                                                                             










                                                                                                 




                                                                                                                                     


















                                                                                           
                                                       
                                                   
                                       


                                                                   

                                                                          

                                                   
                                       


                                                                   

                                                                            

                                                   
                                       


                                                                              
                                        



                                





                                        
import React from 'react';
import MGrid from '@material-ui/core/Grid';
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 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',
        width: '30%'
    },
    inputValue: {
        textAlign: 'left'
    },
    buttonSpacer: {
        marginBottom: theme.spacing.unit * 4,
    },
    bottomButtons: {
        marginTop: 10,
        textAlign: 'center',
    },
    slider: {
        padding: '22px 0px',
    },
    errorHint: {
        fontSize: 16,
        paddingLeft: 16,
        lineHeight: '32px',
        color: theme.palette.secondary.main
    },
    grid: {
        textAlign: 'center'
    }
});

interface SnowProps {
    classes: {
        inputLabel: string,
        inputValue: string,
        buttonSpacer: string,
        bottomButtons: string,
        slider: string,
        errorHint: string,
        grid: 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);
}

const watchedD = [15, 10, 5, 1];

class Snow extends React.Component<SnowProps> {

    static genMatrix(n: number) {
        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(20),
        n: '20',
        k: '10',
        alpha: '8',
        nodesPerTick: '20',
        maxInactiveTicks: '200',
        loaded: true,
        ticking: false,
        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,
        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;

        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++)
                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);
                    }
                }
            }
        });

        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;
    }

    pauseTick() {
        this.setState({ticking: false});
    }

    startTick() {
        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({