semantic-ui-react#Statistic TypeScript Examples
The following examples show how to use
semantic-ui-react#Statistic.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: App.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
render(): ReactElement {
const { count } = this.state;
return (
<div className="container">
<header>
<h1>カウンター</h1>
</header>
<Card>
<Statistic className="number-board">
<Statistic.Label>count</Statistic.Label>
<Statistic.Value>{count}</Statistic.Value>
</Statistic>
<Card.Content>
<div className="ui two buttons">
<Button color="red" onClick={() => this.reset()}>
Reset
</Button>
<Button color="green" onClick={() => this.increment()}>
+1
</Button>
</div>
</Card.Content>
</Card>
</div>
);
}
Example #2
Source File: App.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
render = (): ReactElement => {
const { timeLeft } = this.state;
return (
<div className="container">
<header>
<h1>タイマー</h1>
</header>
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value>{timeLeft}</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={this.reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
</div>
);
};
Example #3
Source File: Counter.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
Counter: VFC = () => {
const [count, setCount] = useState(0);
const increment = () => setCount((c) => c + 1);
const reset = () => setCount(0);
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>count</Statistic.Label>
<Statistic.Value>{count}</Statistic.Value>
</Statistic>
<Card.Content>
<div className="ui two buttons">
<Button color="red" onClick={reset}>
Reset
</Button>
<Button color="green" onClick={increment}>
+1
</Button>
</div>
</Card.Content>
</Card>
);
}
Example #4
Source File: Timer.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
Timer: VFC<{ limit: number }> = ({ limit }) => {
const [timeLeft, setTimeLeft] = useState(limit);
const reset = (): void => setTimeLeft(limit);
const tick = (): void => setTimeLeft((t) => t - 1);
useEffect(() => {
const timerId = setInterval(tick, 1000);
return () => clearInterval(timerId);
}, []);
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
if (timeLeft === 0) setTimeLeft(limit);
});
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value>{timeLeft}</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
);
}
Example #5
Source File: Timer.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
Timer: VFC<TimerProps> = ({ limit }) => {
const [timeLeft, setTimeLeft] = useState(limit);
const primes = useMemo(() => getPrimes(limit), [limit]);
const reset = () => setTimeLeft(limit);
const tick = () => setTimeLeft((t) => t - 1);
useEffect(() => {
const timerId = setInterval(tick, 1000);
return () => clearInterval(timerId);
}, []);
useEffect(() => {
if (timeLeft === 0) setTimeLeft(limit);
}, [timeLeft, limit]);
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value
className={primes.includes(timeLeft) ? 'prime-number' : undefined}
>
{timeLeft}
</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
);
}
Example #6
Source File: Timer.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
Timer: VFC<{ limit: number }> = ({ limit }) => {
const [timeLeft, isPrime, reset] = useTimer(limit);
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value className={isPrime ? 'prime-number' : undefined}>
{timeLeft}
</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
);
}
Example #7
Source File: Timer.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
Timer: VFC<Props> = ({
timeLeft = 0,
isPrime = false,
reset = () => undefined,
}) => (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value className={isPrime ? 'prime-number' : undefined}>
{timeLeft}
</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
)
Example #8
Source File: CounterBoard.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
CounterBoard: VFC<Props> = ({
count = 0,
add = () => undefined,
decrement = () => undefined,
increment = () => undefined,
}) => (
<Card>
<Statistic className="number-board">
<Statistic.Label>count</Statistic.Label>
<Statistic.Value>{count}</Statistic.Value>
</Statistic>
<Card.Content>
<div className="ui two buttons">
<Button color="red" onClick={decrement}>
-1
</Button>
<Button color="green" onClick={increment}>
+1
</Button>
</div>
<div className="fluid-button">
<Button fluid color="grey" onClick={() => add(BULK_UNIT)}>
+{BULK_UNIT}
</Button>
</div>
</Card.Content>
</Card>
)
Example #9
Source File: CounterBoard.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
CounterBoard: VFC<Props> = ({
count = 0,
add = () => undefined,
decrement = () => undefined,
increment = () => undefined,
}) => (
<Card>
<Statistic className="number-board">
<Statistic.Label>count</Statistic.Label>
<Statistic.Value>{count}</Statistic.Value>
</Statistic>
<Card.Content>
<div className="ui two buttons">
<Button color="red" onClick={decrement}>
-1
</Button>
<Button color="green" onClick={increment}>
+1
</Button>
</div>
<div className="fluid-button">
<Button fluid color="grey" onClick={() => add(BULK_UNIT)}>
+{BULK_UNIT}
</Button>
</div>
</Card.Content>
</Card>
)
Example #10
Source File: CounterBoard.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 6 votes |
CounterBoard: VFC<CounterBoardProps> = ({
count = 0,
add = () => undefined,
decrement = () => undefined,
increment = () => undefined,
}) => (
<Card>
<Statistic className="number-board">
<Statistic.Label>count</Statistic.Label>
<Statistic.Value>{count}</Statistic.Value>
</Statistic>
<Card.Content>
<div className="ui two buttons">
<Button color="red" onClick={decrement}>
-1
</Button>
<Button color="green" onClick={increment}>
+1
</Button>
</div>
<div className="fluid-button">
<Button fluid color="grey" onClick={() => add(BULK_UNIT)}>
+{BULK_UNIT}
</Button>
</div>
</Card.Content>
</Card>
)
Example #11
Source File: Timer2.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 5 votes |
Timer: VFC<{ limit: number }> = ({ limit }) => {
const [timeLeft, setTimeLeft] = useState(limit);
const primes = useMemo(() => getPrimes(limit), [limit]);
const timerId = useRef<NodeJS.Timeout>();
const reset = useCallback(() => setTimeLeft(limit), [limit]);
const tick = () => setTimeLeft((t) => t - 1);
useEffect(() => {
const clearTimer = () => {
if (timerId.current) clearInterval(timerId.current);
};
reset();
clearTimer();
timerId.current = setInterval(tick, 1000);
return clearTimer;
}, [limit, reset]);
useEffect(() => {
if (timeLeft === 0) reset();
}, [timeLeft, reset]);
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value
className={primes.includes(timeLeft) ? 'prime-number' : undefined}
>
{timeLeft}
</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
);
}
Example #12
Source File: Timer3.tsx From Riakuto-StartingReact-ja3.1 with Apache License 2.0 | 5 votes |
Timer: VFC<{ limit: number }> = ({ limit }) => {
const [timeLeft, setTimeLeft] = useState(limit);
const primes = useMemo(() => getPrimes(limit), [limit]);
const timerId = useRef<NodeJS.Timeout>();
const tick = () => setTimeLeft((t) => t - 1);
const clearTimer = () => {
if (timerId.current) clearInterval(timerId.current);
};
const reset = useCallback(() => {
clearTimer();
timerId.current = setInterval(tick, 1000);
setTimeLeft(limit);
}, [limit]);
useEffect(() => {
reset();
return clearTimer;
}, [reset]);
useEffect(() => {
if (timeLeft === 0) reset();
}, [timeLeft, reset]);
return (
<Card>
<Statistic className="number-board">
<Statistic.Label>time</Statistic.Label>
<Statistic.Value
className={primes.includes(timeLeft) ? 'prime-number' : undefined}
>
{timeLeft}
</Statistic.Value>
</Statistic>
<Card.Content>
<Button color="red" fluid onClick={reset}>
<Icon name="redo" />
Reset
</Button>
</Card.Content>
</Card>
);
}
Example #13
Source File: commoncrewdata.tsx From website with MIT License | 4 votes |
render() {
const { markdownRemark, crew, compact, crewDemands, roster } = this.props;
let panels = [
{
index: 0,
key: 0,
title: getCoolStats(crew, false),
content: { content: <div style={{ paddingBottom: '1em' }}>{this.renderOtherRanks(crew)}</div> }
}
];
if (roster && roster.length > 0) {
panels.push(
{
index: 1,
key: 1,
title: this.rosterComparisonTitle(crew, roster),
content: { content: <div style={{ paddingBottom: '1em' }}>{this.renderOtherRanks(crew, roster)}</div> }
});
}
return (
<React.Fragment>
{compact ? (
<Segment>
<Grid columns={2}>
<Grid.Column width={4}>
<Image src={`${process.env.GATSBY_ASSETS_URL}${crew.imageUrlFullBody}`} size="tiny" />
</Grid.Column>
<Grid.Column width={12}>
<CrewStat
skill_name="security_skill"
data={crew.base_skills.security_skill}
scale={compact ? 0.75 : 1}
/>
<CrewStat skill_name="command_skill" data={crew.base_skills.command_skill} scale={compact ? 0.75 : 1} />
<CrewStat
skill_name="diplomacy_skill"
data={crew.base_skills.diplomacy_skill}
scale={compact ? 0.75 : 1}
/>
<CrewStat skill_name="science_skill" data={crew.base_skills.science_skill} scale={compact ? 0.75 : 1} />
<CrewStat
skill_name="medicine_skill"
data={crew.base_skills.medicine_skill}
scale={compact ? 0.75 : 1}
/>
<CrewStat
skill_name="engineering_skill"
data={crew.base_skills.engineering_skill}
scale={compact ? 0.75 : 1}
/>
</Grid.Column>
</Grid>
</Segment>
) : (
<Segment>
<CrewStat skill_name="security_skill" data={crew.base_skills.security_skill} scale={compact ? 0.75 : 1} />
<CrewStat skill_name="command_skill" data={crew.base_skills.command_skill} scale={compact ? 0.75 : 1} />
<CrewStat skill_name="diplomacy_skill" data={crew.base_skills.diplomacy_skill} scale={compact ? 0.75 : 1} />
<CrewStat skill_name="science_skill" data={crew.base_skills.science_skill} scale={compact ? 0.75 : 1} />
<CrewStat skill_name="medicine_skill" data={crew.base_skills.medicine_skill} scale={compact ? 0.75 : 1} />
<CrewStat
skill_name="engineering_skill"
data={crew.base_skills.engineering_skill}
scale={compact ? 0.75 : 1}
/>
</Segment>
)}
{crew.skill_data && crew.skill_data.length > 0 && (
<Accordion
defaultActiveIndex={-1}
panels={[
{
index: 0,
key: 0,
title: 'Other fuse levels',
content: {
content: (
<Segment.Group raised>
{crew.skill_data.map((sk: any, idx: number) => (
<Segment key={idx}>
<Rating
defaultRating={sk.rarity}
maxRating={crew.max_rarity}
icon="star"
size="small"
disabled
/>
<CrewStat skill_name="security_skill" data={sk.base_skills.security_skill} scale={0.75} />
<CrewStat skill_name="command_skill" data={sk.base_skills.command_skill} scale={0.75} />
<CrewStat skill_name="diplomacy_skill" data={sk.base_skills.diplomacy_skill} scale={0.75} />
<CrewStat skill_name="science_skill" data={sk.base_skills.science_skill} scale={0.75} />
<CrewStat skill_name="medicine_skill" data={sk.base_skills.medicine_skill} scale={0.75} />
<CrewStat
skill_name="engineering_skill"
data={sk.base_skills.engineering_skill}
scale={0.75}
/>
</Segment>
))}
</Segment.Group>
)
}
}
]}
/>
)}
{crew.flavor && !compact && <p>{crew.flavor}</p>}
{compact && (
<div style={{ textAlign: 'center' }}>
<StatLabel title="Voyage rank" value={crew.ranks.voyRank} />
<StatLabel title="Gauntlet rank" value={crew.ranks.gauntletRank} />
<StatLabel title="Big book tier" value={formatTierLabel(markdownRemark.frontmatter.bigbook_tier)} />
{markdownRemark.frontmatter.events !== null && (
<StatLabel title="Events" value={markdownRemark.frontmatter.events} />
)}
</div>
)}
{!compact && (
<>
<Statistic.Group size="tiny">
{markdownRemark.frontmatter.events !== null && (
<Statistic>
<Statistic.Label>Events</Statistic.Label>
<Statistic.Value>{markdownRemark.frontmatter.events}</Statistic.Value>
</Statistic>
)}
<Statistic>
<Statistic.Label>Big Book Tier</Statistic.Label>
<Statistic.Value>{formatTierLabel(markdownRemark.frontmatter.bigbook_tier)}</Statistic.Value>
</Statistic>
<Statistic>
<Statistic.Label>CAB Rating <CABExplanation /></Statistic.Label>
<Statistic.Value>{crew.cab_ov ?? 'None'}</Statistic.Value>
</Statistic>
{!compact && markdownRemark.frontmatter.in_portal !== null && (
<Statistic color={markdownRemark.frontmatter.in_portal ? 'green' : 'red'}>
<Statistic.Label>Portal</Statistic.Label>
<Statistic.Value>{markdownRemark.frontmatter.in_portal ? 'YES' : 'NO'}</Statistic.Value>
</Statistic>
)}
</Statistic.Group>
<Statistic.Group style={{ paddingBottom: '2em' }} size="tiny">
<Statistic>
<Statistic.Label>CAB Rank <CABExplanation /></Statistic.Label>
<Statistic.Value>{crew.cab_ov_rank ? rankLinker(false, crew.cab_ov_rank, crew.symbol, 'cab_ov', 'descending', 'rarity:'+crew.max_rarity) : 'None'}</Statistic.Value>
</Statistic>
<Statistic>
<Statistic.Label>Voyage Rank</Statistic.Label>
<Statistic.Value>{rankLinker(false, crew.ranks.voyRank, crew.symbol, 'ranks.voyRank')}</Statistic.Value>
</Statistic>
<Statistic>
<Statistic.Label>Gauntlet Rank</Statistic.Label>
<Statistic.Value>{rankLinker(false, crew.ranks.gauntletRank, crew.symbol, 'ranks.gauntletRank')}</Statistic.Value>
</Statistic>
</Statistic.Group>
</>
)}
{crewDemands && (
<p>
<b>{crewDemands.factionOnlyTotal}</b>
{' faction items, '}
<span style={{ display: 'inline-block' }}>
<img src={`${process.env.GATSBY_ASSETS_URL}atlas/energy_icon.png`} height={14} />
</span>{' '}
<b>{crewDemands.totalChronCost}</b>
{', '}
<span style={{ display: 'inline-block' }}>
<img src={`${process.env.GATSBY_ASSETS_URL}currency_sc_currency_0.png`} height={16} />
</span>{' '}
<b>{crewDemands.craftCost}</b>
</p>
)}
<Accordion
exclusive={false}
panels={panels}
/>
<p>
<b>Traits: </b>
{crew.traits_named
.map(trait => (
<a key={trait} href={`/?search=trait:${trait}`}>
{trait}
</a>
))
.reduce((prev, curr) => [prev, ', ', curr])}
{', '}
{crew.traits_hidden
.map(trait => (
<a style={{ color: 'lightgray' }} key={trait} href={`/?search=trait:${trait}`}>
{trait}
</a>
))
.reduce((prev, curr) => [prev, ', ', curr])}
</p>
{crew.cross_fuse_targets && crew.cross_fuse_targets.symbol && (
<p>
Can cross-fuse with{' '}
<Link to={`/crew/${crew.cross_fuse_targets.symbol}/`}>{crew.cross_fuse_targets.name}</Link>.
</p>
)}
{crew.collections.length > 0 && (
<p>
<b>Collections: </b>
{crew.collections
.map(col => (
<Link key={col} to={`/collections/#${encodeURIComponent(col)}`}>
{col}
</Link>
))
.reduce((prev, curr) => [prev, ', ', curr])}
</p>
)}
<p>
<b>Date added: </b>{new Date(crew.date_added).toLocaleDateString("en-US")} (<b>Obtained: </b>{crew.obtained})
</p>
{crew.nicknames && crew.nicknames.length > 0 && (
<p>
<b>Also known as: </b>
{crew.nicknames
.map((nick, idx) => (
<span key={idx}>{nick.cleverThing}{nick.creator ? <> (coined by <i>{nick.creator}</i>)</> : ''}</span>
))
.reduce((prev, curr) => [prev, ', ', curr])}
</p>
)}
</React.Fragment>
);
}
Example #14
Source File: commoncrewdata.tsx From website with MIT License | 4 votes |
renderOtherRanks(crew, roster = false) {
let v = [];
let g = [];
let b = [];
const skillName = short => CONFIG.SKILLS[CONFIG.SKILLS_SHORT.find(c => c.short === short).name];
const rankHandler = rank => roster
? roster.filter(c => c.ranks[rank] && crew.ranks[rank] > c.ranks[rank]).length + 1
: crew.ranks[rank];
const tripletHandler = rank => roster
? roster.filter(c => c.ranks[rank] &&
c.ranks[rank].name == crew.ranks[rank].name &&
crew.ranks[rank].rank > c.ranks[rank].rank).length + 1
: crew.ranks[rank].rank;
// Need to filter by skills first before sorting by voyage triplet
const tripletFilter = crew.ranks.voyTriplet
? crew.ranks.voyTriplet.name.split('/')
.map(s => 'skill:'+s.trim())
.reduce((prev, curr) => prev+' '+curr)
: '';
for (let rank in crew.ranks) {
if (rank.startsWith('V_')) {
v.push(
<Statistic key={rank}>
<Statistic.Label>{rank.substr(2).replace('_', ' / ')}</Statistic.Label>
<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, 'ranks.'+rank)}</Statistic.Value>
</Statistic>
);
} else if (rank.startsWith('G_')) {
g.push(
<Statistic key={rank}>
<Statistic.Label>{rank.substr(2).replace('_', ' / ')}</Statistic.Label>
<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, 'ranks.'+rank)}</Statistic.Value>
</Statistic>
);
} else if (rank.startsWith('B_') && crew.ranks[rank]) {
b.push(
<Statistic key={rank}>
<Statistic.Label>{skillName(rank.substr(2))}</Statistic.Label>
<Statistic.Value>{rankLinker(roster, rankHandler(rank), crew.symbol, CONFIG.SKILLS_SHORT.find(c => c.short === rank.substr(2)).name, 'descending')}</Statistic.Value>
</Statistic>
);
}
}
return (
<React.Fragment>
<Segment>
<Header as="h5">Base ranks</Header>
<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
{b}
</Statistic.Group>
</Segment>
<Segment>
<Header as="h5">Voyage skill ranks</Header>
{crew.ranks.voyTriplet && (
<React.Fragment>
<Statistic.Group widths="one" size={'mini'}>
<Statistic>
<Statistic.Label>{crew.ranks.voyTriplet.name}</Statistic.Label>
<Statistic.Value>{rankLinker(roster, tripletHandler('voyTriplet'), crew.symbol, 'ranks.voyRank', 'ascending', tripletFilter)}</Statistic.Value>
</Statistic>
</Statistic.Group>
<Divider />
</React.Fragment>
)}
<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
{v}
</Statistic.Group>
</Segment>
<Segment>
<Header as="h5">Gauntlet pair ranks</Header>
<Statistic.Group widths="three" size={'mini'} style={{ paddingBottom: '0.5em' }}>
{g}
</Statistic.Group>
</Segment>
</React.Fragment>
);
}
Example #15
Source File: crewchallenge.tsx From website with MIT License | 4 votes |
DailyGame = () => {
const portalCrew = React.useContext(PortalCrewContext);
const [dailyId, setDailyId] = useStateWithStorage('datalore/dailyId', '', { rememberForever: true, onInitialize: variableReady });
const [solution, setSolution] = useStateWithStorage('datalore/dailySolution', '', { rememberForever: true, onInitialize: variableReady });
const [guesses, setGuesses] = useStateWithStorage('datalore/dailyGuesses', [], { rememberForever: true, onInitialize: variableReady });
const [stats, setStats] = useStateWithStorage('datalore/dailyStats', new PlayerStats(), { rememberForever: true, onInitialize: variableReady });
const [loadState, setLoadState] = React.useState(0);
const [solveState, setSolveState] = React.useState(SolveState.Unsolved);
const [showStats, setShowStats] = React.useState(false);
const currentTime = new Date();
// Game time is current day midnight ET
const gameTime = new Date(currentTime);
gameTime.setUTCHours(gameTime.getUTCHours()-4); // ET is UTC-4
gameTime.setUTCHours(4, 0, 0, 0); // Midnight ET is 4:00:00 UTC
// Daily reset time is next midnight ET
const resetTime = new Date(gameTime);
resetTime.setUTCDate(resetTime.getUTCDate()+1)
React.useEffect(() => {
if (loadState === 4) initializeDailyGame();
}, [loadState]);
React.useEffect(() => {
setShowStats(solveState !== SolveState.Unsolved);
}, [solveState]);
if (loadState < 4 || solution === '')
return (<></>);
const rules = new GameRules();
return (
<React.Fragment>
<p>How well do you know the characters from Star Trek Timelines? We pick one mystery crew member every day. Guess who it is, using your knowledge of <b>Variants</b>, <b>Series</b>, <b>Rarity</b>, <b>Skills</b>, and <b>Traits</b> to help narrow the possibilities. You have <b>{DEFAULT_GUESSES} tries</b> to guess the mystery crew. Good luck!</p>
<CrewChallengeGame rules={rules} solution={solution}
guesses={guesses} setGuesses={setGuesses}
solveState={solveState} setSolveState={setSolveState}
gameTime={gameTime} onGameEnd={handleGameEnd} />
{renderResetTime()}
{renderStats()}
</React.Fragment>
);
function variableReady(keyName: string): void {
setLoadState(prevState => Math.min(prevState + 1, 4));
}
function initializeDailyGame(): void {
const getGameIdFromDate = (gameTime: Date) => {
const utcYear = gameTime.getUTCFullYear(), utcMonth = gameTime.getUTCMonth()+1, utcDate = gameTime.getUTCDate();
return `${utcYear}/${utcMonth}/${utcDate}`;
};
const getSeed = (gameId: string) => {
const seedrandom = require('seedrandom');
const rng = seedrandom(gameId);
return Math.floor(rng()*portalCrew.length);
};
const getFreshSeed = (gameId: string) => {
let randomSeed = getSeed(gameId);
while (recentSeeds.includes(randomSeed)) {
gameId += '+';
randomSeed = getSeed(gameId);
}
return randomSeed;
};
// Don't re-use likely solutions from the past 3 weeks
const recentSeeds = [];
const previousDay = new Date(gameTime);
previousDay.setUTCDate(previousDay.getUTCDate()-21);
for (let i = 0; i < 20; i++) {
previousDay.setUTCDate(previousDay.getUTCDate()+1);
let previousId = getGameIdFromDate(previousDay);
const previousSeed = getFreshSeed(previousId);
recentSeeds.push(previousSeed);
}
// Daily game id is based on game time
const gameId = getGameIdFromDate(gameTime);
setDailyId(gameId);
const dailySeed = getFreshSeed(gameId);
const dailySolution = portalCrew[dailySeed].symbol;
// Create new game
if (dailyId === '' || dailyId !== gameId) {
setGuesses([]);
setSolution(dailySolution);
setSolveState(SolveState.Unsolved);
return;
}
// No existing solution, get solveState from daily solution
if (solution === '') {
setSolution(dailySolution);
if (guesses.includes(dailySolution))
setSolveState(SolveState.Winner);
else if (guesses.length >= DEFAULT_GUESSES)
setSolveState(SolveState.Loser);
return;
}
// Get solveState from existing solution
if (guesses.includes(solution))
setSolveState(SolveState.Winner);
else if (guesses.length >= DEFAULT_GUESSES)
setSolveState(SolveState.Loser);
}
function handleGameEnd(solveState: number): void {
stats.plays++;
if (solveState === SolveState.Winner) {
stats.wins++;
stats.guesses[guesses.length]++;
stats.streak++;
stats.maxStreak = Math.max(stats.streak, stats.maxStreak);
}
else {
stats.guesses.fail++;
stats.streak = 0;
}
setStats({... stats});
}
function renderStats(): JSX.Element {
if (stats.plays === 0) return (<></>);
if (!showStats)
return (
<div style={{ marginTop: '2em' }}>
<Button icon='chart bar' content='Stats' onClick={() => setShowStats(true)} />
</div>
);
return (
<React.Fragment>
<Divider />
<Header as='h3'>Statistics</Header>
<Statistic.Group size='small'>
<Statistic>
<Statistic.Value>{stats.plays}</Statistic.Value>
<Statistic.Label>Played</Statistic.Label>
</Statistic>
<Statistic>
<Statistic.Value>{Math.floor(stats.wins/stats.plays*100)}</Statistic.Value>
<Statistic.Label>Win%</Statistic.Label>
</Statistic>
<Statistic>
<Statistic.Value>{stats.streak}</Statistic.Value>
<Statistic.Label>Current Streak</Statistic.Label>
</Statistic>
<Statistic>
<Statistic.Value>{stats.maxStreak}</Statistic.Value>
<Statistic.Label>Max Streak</Statistic.Label>
</Statistic>
</Statistic.Group>
</React.Fragment>
);
}
function renderResetTime(): JSX.Element {
if (!showStats || solveState === SolveState.Unsolved) return (<></>);
const formatTime = (seconds: number) => {
const h = Math.floor(seconds / 3600);
const m = Math.floor(seconds % 3600 / 60);
const s = Math.floor(seconds % 3600 % 60);
return h+'h ' +m+'m';
};
return (
<div style={{ marginTop: '2em' }}>
A new mystery crew will be available in <b>{formatTime((resetTime.getTime()-currentTime.getTime())/1000)}</b>.
</div>
);
}
}