events.addEventListener("player-exit", event => {
const info = JSON.parse(event.data);
- window.game.remove_player(info);
+ window.game.disable_player(info);
});
events.addEventListener("player-update", event => {
if (! props.player.id)
return null;
- const all_players = [props.player, ...props.other_players];
+ const all_players = [{...props.player, active:true}, ...props.other_players];
const sorted_players = all_players.sort((a,b) => {
return b.score - a.score;
});
- const names_and_scores = sorted_players.map(player => {
- if (player.score)
- return `${player.name} (${player.score})`;
- else
- return player.name;
- }).join(', ');
+ /* Return a new array with the separator interspersed between
+ * each element of the array passed in as the argument.
+ */
+ function intersperse(arr, sep) {
+ return arr.reduce((acc, val) => [...acc, sep, val], []).slice(1);
+ }
+
+ let names_and_scores = sorted_players.map(player => {
+ if (player.score) {
+ return (
+ <span
+ key={player.name}
+ className={player.active ? "player-active" : "player-idle"}
+ >
+ {player.name} ({player.score})
+ </span>
+ );
+ } else {
+ if (player.active)
+ return player.name;
+ else
+ return null;
+ }
+ }).filter(component => component != null);
+
+ names_and_scores = intersperse(names_and_scores, ", ");
return (
<div className="player-info">
<span className="players-header">Players: </span>
- <span>{names_and_scores}</span>
+ {names_and_scores}
</div>
);
});
const LetsPlay = React.memo(props => {
- const quorum = Math.round((props.num_players + 1) / 2);
+ const quorum = Math.max(0, props.num_players - props.prompts.length);
const max_votes = props.prompts.reduce(
(max_so_far, v) => Math.max(max_so_far, v.votes.length), 0);
- if (max_votes < quorum)
- return null;
+ if (max_votes < quorum) {
+ let text = `Before we play, we should collect a bit
+ more information about what category would
+ be interesting for this group. So, either
+ type a new category option above, or else`;
+ if (props.prompts.length) {
+ if (props.prompts.length > 1)
+ text += " vote on some of the categories below.";
+ else
+ text += " vote on the category below.";
+ } else {
+ text += " wait for others to submit, and then vote on them below.";
+ }
- const candidates = props.prompts.filter(p => p.votes.length >= quorum);
+ return (
+ <div className="before-we-play">
+ <p>
+ {text}
+ </p>
+ </div>
+ );
+ }
+
+ const candidates = props.prompts.filter(p => p.votes.length >= max_votes);
const index = Math.floor(Math.random() * candidates.length);
const winner = candidates[index];
const response = await fetch_post_json(
`judged/${this.props.prompt.id}`,{
- word_groups: this.state.word_sets.map(set => Array.from(set)),
- kudos: this.state.starred ? Array.from(this.state.starred) : null
+ word_groups: this.state.word_sets.map(
+ set => ({
+ words: Array.from(set),
+ kudos: this.state.starred === set ? true : false
+ }))
}
);
<div className="ambiguities">
<h2>Judging Answers</h2>
<p>
- Click on each pair of answers that should be scored as equivalent,
- (and click any word twice to split it out from a group). Remember,
+ Click/tap on each pair of answers that should be scored as equivalent,
+ (or click a word twice to split it out from a group). Remember,
what goes around comes around, so it's best to be generous when
judging.
</p>
+ <p>
+ Also, for an especially fun or witty answer, you can give kudos
+ by clicking the star on the right. You may only do this for one
+ word/group.
+ </p>
<h2>{this.props.prompt.prompt}</h2>
{this.state.word_sets.map(set => {
return (
}
onClick={(event) => {
event.stopPropagation();
- this.setState({
- starred: set
- });
+ if (this.state.starred === set) {
+ this.setState({
+ starred: null
+ });
+ } else {
+ this.setState({
+ starred: set
+ });
+ }
}}
>
{this.state.starred === set ?
}
set_other_player_info(info) {
+ const player_object = {...info, active: true};
const other_players_copy = [...this.state.other_players];
const idx = other_players_copy.findIndex(o => o.id === info.id);
if (idx >= 0) {
- other_players_copy[idx] = info;
+ other_players_copy[idx] = player_object;
} else {
- other_players_copy.push(info);
+ other_players_copy.push(player_object);
}
this.setState({
other_players: other_players_copy
});
}
- remove_player(info) {
+ disable_player(info) {
+ const idx = this.state.other_players.findIndex(o => o.id === info.id);
+ if (idx < 0)
+ return;
+
+ const other_players_copy = [...this.state.other_players];
+ other_players_copy[idx].active = false;
+
this.setState({
- other_players: this.state.other_players.filter(o => o.id !== info.id)
+ other_players: other_players_copy
});
}
render() {
const state = this.state;
- const players_total = 1 + state.other_players.length;
if (state.scores) {
+ const players_total = state.players_answered.size;
+
let perfect_score = 0;
for (let i = 0;
i < state.active_prompt.items &&
<ul>
{state.scores.scores.map(score => {
let perfect = null;
- if (score.score == perfect_score) {
+ if (score.score === perfect_score) {
perfect = <span className="achievement">Perfect!</span>;
}
+ let quirkster = null;
+ if (score.score === state.active_prompt.items) {
+ quirkster = <span className="achievement">Quirkster!</span>;
+ }
+ let kudos_slam = null;
+ if (score.kudos > 0 && score.kudos >= players_total - 1) {
+ kudos_slam = <span className="achievement">Kudos Slam!</span>;
+ }
return (
<li key={score.players[0]}>
- {score.players.join("/")}: {score.score} {perfect}
+ {score.players.join("/")}: {score.score}
+ {score.kudos ? `, ${'★'.repeat(score.kudos)}` : ""}
+ {' '}{perfect} {quirkster} {kudos_slam}
</li>
);
})}
<h2>Words submitted</h2>
<ul>
{state.scores.words.map(word => {
+ let great_minds = null;
+ if (word.kudos.length && word.players.length > 1) {
+ great_minds = <span className="achievement">Great Minds!</span>;
+ }
+ let kudos_slam = null;
+ if (word.kudos.length > 0 && word.kudos.length >= players_total - 1) {
+ kudos_slam = <span className="achievement">Kudos Slam!</span>;
+ }
return (
<li key={word.word}>
- {word.word} ({word.players.length}): {word.players.join(', ')}
+ {word.word} ({word.players.length}
+ {word.kudos.length ? `, ${'★'.repeat(word.kudos.length)}` : ""}
+ ): {word.players.join(', ')}
+ {' '}{great_minds}{kudos_slam}
</li>
);
})}
<CategoryRequest
key="category-request"
/>,
+ <LetsPlay
+ key="lets-play"
+ num_players={1+state.other_players.filter(p => p.active).length}
+ prompts={state.prompts}
+ />,
<PromptOptions
key="prompts"
prompts={state.prompts}
player={state.player_info}
- />,
- <LetsPlay
- key="lets-play"
- num_players={1+state.other_players.length}
- prompts={state.prompts}
/>
];
}