+const MAX_PROMPT_ITEMS = 20;
+
function undisplay(element) {
element.style.display="none";
}
events.addEventListener("game-state", event => {
const state = JSON.parse(event.data);
+ window.game.reset_game_state();
+
window.game.set_prompts(state.prompts);
window.game.set_active_prompt(state.active_prompt);
window.game.set_active_prompt(prompt);
});
-events.addEventListener("answered", event => {
- const players_answered = JSON.parse(event.data);
+events.addEventListener("player-answered", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_answered(player);
+});
+
+events.addEventListener("player-answering", event => {
+ const player = JSON.parse(event.data);
- window.game.set_players_answered(players_answered);
+ window.game.set_player_answering(player);
+});
+
+events.addEventListener("vote-end-answers", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_vote_end_answers(player);
+});
+
+events.addEventListener("unvote-end-answers", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_unvote_end_answers(player);
});
events.addEventListener("ambiguities", event => {
window.game.set_ambiguities(ambiguities);
});
-events.addEventListener("judged", event => {
- const players_judged = JSON.parse(event.data);
+events.addEventListener("player-judged", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_judged(player);
+});
+
+events.addEventListener("player-judging", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_judging(player);
+});
+
+events.addEventListener("vote-end-judging", event => {
+ const player = JSON.parse(event.data);
- window.game.set_players_judged(players_judged);
+ window.game.set_player_vote_end_judging(player);
+});
+
+events.addEventListener("unvote-end-judging", event => {
+ const player = JSON.parse(event.data);
+
+ window.game.set_player_unvote_end_judging(player);
});
events.addEventListener("scores", event => {
const category_input = this.category.current;
const category = category_input.value;
- if (/[0-9]/.test(category))
- category_input.setCustomValidity("");
+ const match = category.match(/[0-9]+/);
+ if (match) {
+ const num_items = parseInt(match[0], 10);
+ if (num_items <= MAX_PROMPT_ITEMS)
+ category_input.setCustomValidity("");
+ }
}
- handle_submit(event) {
+ async handle_submit(event) {
const form = event.currentTarget;
const category_input = this.category.current;
const category = category_input.value;
return;
}
- fetch_post_json("prompts", {
- items: parseInt(match[0], 10),
+ const num_items = parseInt(match[0], 10);
+
+ if (num_items > MAX_PROMPT_ITEMS) {
+ category_input.setCustomValidity(`Maximum number of items is ${MAX_PROMPT_ITEMS}`);
+ form.reportValidity();
+ return;
+ }
+
+ const response = await fetch_post_json("prompts", {
+ items: num_items,
prompt: category
});
+ if (response.status === 200) {
+ const result = await response.json();
+ if (! result.valid) {
+ add_message("danger", result.message);
+ return;
+ }
+ } else {
+ add_message("danger", "An error occurred submitting your category");
+ }
+
form.reset();
}
constructor(props) {
super(props);
+ const word_sets = props.words.map(word => {
+ const set = new Set();
+ set.add(word);
+ return set;
+ });
+
this.state = {
- word_groups: props.words.map(word => [word]),
+ word_sets: word_sets,
submitted: false,
selected: null
};
async handle_submit() {
const response = await fetch_post_json(
- `judging/${this.props.prompt.id}`,{
- word_groups: this.state.word_groups
+ `judged/${this.props.prompt.id}`,{
+ word_groups: this.state.word_sets.map(set => Array.from(set))
}
);
handle_click(word) {
if (this.state.selected == word) {
/* Second click on same word removes the word from the group. */
- const new_groups = this.state.word_groups.filter(
- group => (! group.includes(this.state.selected)) || (group.length > 1)).map(
- group => {
- return group.filter(w => w !== this.state.selected);
- }
- );
+ const idx = this.state.word_sets.findIndex(s => s.has(word));
+ const set = this.state.word_sets[idx];
+ if (set.size === 1)
+ return;
+ const new_set = new Set([...set].filter(w => w !== word));
this.setState({
selected: null,
- word_groups: [...new_groups, [word]]
+ word_sets: [...this.state.word_sets.slice(0, idx),
+ new_set,
+ new Set().add(word),
+ ...this.state.word_sets.slice(idx+1)]
});
} else if (this.state.selected) {
/* Click of a second word groups the two together. */
- const new_groups = this.state.word_groups.filter(
- group => (! group.includes(word)) || (group.length > 1)).map(
- group => {
- if (group.includes(this.state.selected)) {
- if (! group.includes(word))
- return [...group, word];
- else
- return group;
- } else {
- return group.filter(w => w !== word);
- }
- }
- );
- this.setState({
- selected: null,
- word_groups: new_groups
- });
+ const idx1 = this.state.word_sets.findIndex(s => s.has(this.state.selected));
+ const idx2 = this.state.word_sets.findIndex(s => s.has(word));
+ const set1 = this.state.word_sets[idx1];
+ const set2 = this.state.word_sets[idx2];
+ const new_set = new Set([...set2, ...set1]);
+ if (idx1 < idx2) {
+ this.setState({
+ selected: null,
+ word_sets: [...this.state.word_sets.slice(0, idx1),
+ ...this.state.word_sets.slice(idx1 + 1, idx2),
+ new_set,
+ ...this.state.word_sets.slice(idx2 + 1)]
+ });
+ } else {
+ this.setState({
+ selected: null,
+ word_sets: [...this.state.word_sets.slice(0, idx2),
+ new_set,
+ ...this.state.word_sets.slice(idx2 + 1, idx1),
+ ...this.state.word_sets.slice(idx1 + 1)]
+ });
+ }
} else {
/* First click of a word selects it. */
this.setState({
if (this.state.submitted)
return (
<div className="please-wait">
- <h2>{this.props.players_judged}/
- {this.props.players_total} players have responded</h2>
+ <h2>Submission received</h2>
+ <p>
+ The following players have completed judging:
+ {[...this.props.players_judged].join(', ')}
+ </p>
<p>
- Please wait for the rest of the players to complete judging.
+ Still waiting for the following players:
</p>
+ <ul>
+ {Object.entries(this.props.players_judging).map(player => {
+ return (
+ <li
+ key={player}
+ >
+ {player}
+ {this.props.players_judging[player] ?
+ <span className="typing"/> : null }
+ </li>
+ );
+ })}
+ </ul>
+ <button
+ className="vote-button"
+ onClick={() => fetch_post_json(`end-judging/${this.props.prompt.id}`) }
+ >
+ Move On
+ <div className="vote-choices">
+ {[...this.props.votes].map(v => {
+ return (
+ <div
+ key={v}
+ className="vote-choice"
+ >
+ {v}
+ </div>
+ );
+ })}
+ </div>
+ </button>
+
</div>
);
what goes around comes around, so it's best to be generous when
judging.
</p>
- {this.state.word_groups.map(word_group => {
+ {this.state.word_sets.map(set => {
return (
<div
className="ambiguity-group"
- key={word_group[0]}
+ key={Array.from(set)[0]}
>
- {word_group.map(word => {
- return (
- <button
- className={this.state.selected === word ?
- btn_selected_class : btn_class }
- key={word}
- onClick={() => this.handle_click(word)}
+ {Array.from(set).map(word => {
+ return (
+ <button
+ className={this.state.selected === word ?
+ btn_selected_class : btn_class }
+ key={word}
+ onClick={() => this.handle_click(word)}
>
- {word}
- </button>
- );
- })}
+ {word}
+ </button>
+ );
+ })}
</div>
);
})}
if (this.state.submitted)
return (
<div className="please-wait">
- <h2>{this.props.players_answered}/
- {this.props.players_total} players have responded</h2>
+ <h2>Submission received</h2>
<p>
- Please wait for the rest of the players to submit their answers.
+ The following players have submitted their answers:
+ {[...this.props.players_answered].join(', ')}
</p>
+ <p>
+ Still waiting for the following players:
+ </p>
+ <ul>
+ {Object.entries(this.props.players_answering).map(player => {
+ return (
+ <li
+ key={player}
+ >
+ {player}
+ {this.props.players_answering[player] ?
+ <span className="typing"/> : null }
+ </li>
+ );
+ })}
+ </ul>
+ <button
+ className="vote-button"
+ onClick={() => fetch_post_json(`end-answers/${this.props.prompt.id}`) }
+ >
+ Move On
+ <div className="vote-choices">
+ {[...this.props.votes].map(v => {
+ return (
+ <div
+ key={v}
+ className="vote-choice"
+ >
+ {v}
+ </div>
+ );
+ })}
+ </div>
+ </button>
+
</div>
);
other_players: [],
prompts: [],
active_prompt: null,
- players_answered: 0,
+ players_answered: new Set(),
+ players_answering: {},
+ end_answers_votes: new Set(),
ambiguities: null,
- players_judged: 0
+ players_judged: new Set(),
+ players_judging: {},
+ end_judging_votes: new Set(),
+ scores: null
};
}
});
}
+ reset_game_state() {
+ this.setState({
+ prompts: [],
+ active_prompt: null,
+ players_answered: new Set(),
+ players_answering: {},
+ end_answers_votes: new Set(),
+ ambiguities: null,
+ players_judged: new Set(),
+ players_judging: {},
+ end_judging_votes: new Set(),
+ scores: null
+ });
+ }
+
set_prompts(prompts) {
this.setState({
prompts: prompts
});
}
- set_players_answered(players_answered) {
+ set_player_answered(player) {
+ const new_players_answering = {...this.state.players_answering};
+ delete new_players_answering[player];
+
+ this.setState({
+ players_answered: new Set([...this.state.players_answered, player]),
+ players_answering: new_players_answering
+ });
+ }
+
+ set_player_answering(player) {
+ this.setState({
+ players_answering: {
+ ...this.state.players_answering,
+ [player]: {active: true}
+ }
+ });
+ }
+
+ set_player_vote_end_answers(player) {
+ this.setState({
+ end_answers_votes: new Set([...this.state.end_answers_votes, player])
+ });
+ }
+
+ set_player_unvote_end_answers(player) {
this.setState({
- players_answered: players_answered
+ end_answers_votes: new Set([...this.state.end_answers_votes].filter(p => p !== player))
});
}
});
}
- set_players_judged(players_judged) {
+ set_player_judged(player) {
+ const new_players_judging = {...this.state.players_judging};
+ delete new_players_judging[player];
+
+ this.setState({
+ players_judged: new Set([...this.state.players_judged, player]),
+ players_judging: new_players_judging
+ });
+ }
+
+ set_player_judging(player) {
+ this.setState({
+ players_judging: {
+ ...this.state.players_judging,
+ [player]: {active: true}
+ }
+ });
+ }
+
+
+ set_player_vote_end_judging(player) {
+ this.setState({
+ end_judging_votes: new Set([...this.state.end_judging_votes, player])
+ });
+ }
+
+ set_player_unvote_end_judging(player) {
this.setState({
- players_judged: players_judged
+ end_judging_votes: new Set([...this.state.end_judging_votes].filter(p => p !== player))
});
}
prompt={state.active_prompt}
words={state.ambiguities}
players_judged={state.players_judged}
- players_total={players_total}
+ players_judging={state.players_judging}
+ votes={state.end_judging_votes}
/>;
}
return <ActivePrompt
prompt={state.active_prompt}
players_answered={state.players_answered}
- players_total={players_total}
+ players_answering={state.players_answering}
+ votes={state.end_answers_votes}
/>;
}