X-Git-Url: https://git.cworth.org/git?p=lmno.games;a=blobdiff_plain;f=empathy%2Fempathy.jsx;h=546df87acbbb0129f33deffc8e4996209460800d;hp=60540c03b8246d84fcab3b5c9dc7507f500c10b4;hb=d016635ce24d1502f77c610d1a4afbfeca3ec5e8;hpb=123507982e9643a1cf2d747fbd556fc3856bfa49 diff --git a/empathy/empathy.jsx b/empathy/empathy.jsx index 60540c0..546df87 100644 --- a/empathy/empathy.jsx +++ b/empathy/empathy.jsx @@ -1,3 +1,5 @@ +const MAX_PROMPT_ITEMS = 20; + function undisplay(element) { element.style.display="none"; } @@ -55,6 +57,8 @@ events.addEventListener("player-update", event => { 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); @@ -76,10 +80,28 @@ events.addEventListener("start", event => { 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 => { @@ -88,10 +110,28 @@ 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_player_vote_end_judging(player); +}); + +events.addEventListener("unvote-end-judging", event => { + const player = JSON.parse(event.data); - window.game.set_players_judged(players_judged); + window.game.set_player_unvote_end_judging(player); }); events.addEventListener("scores", event => { @@ -185,11 +225,15 @@ class CategoryRequest extends React.PureComponent { 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; @@ -204,11 +248,29 @@ class CategoryRequest extends React.PureComponent { 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(); } @@ -287,10 +349,6 @@ const PromptOptions = React.memo(props => { const LetsPlay = React.memo(props => { - function handle_click(prompt_id) { - fetch_post_json - } - const quorum = Math.round((props.num_players + 1) / 2); const max_votes = props.prompts.reduce( (max_so_far, v) => Math.max(max_so_far, v.votes.length), 0); @@ -324,16 +382,27 @@ class Ambiguities extends React.PureComponent { 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 }; + + this.judging_sent_recently = false; } async handle_submit() { - const response = await fetch_post_json(`judging/${this.props.prompt.id}`, - this.state.word_groups); + const response = await fetch_post_json( + `judged/${this.props.prompt.id}`,{ + word_groups: this.state.word_sets.map(set => Array.from(set)) + } + ); if (response.status === 200) { const result = await response.json(); @@ -342,7 +411,7 @@ class Ambiguities extends React.PureComponent { return; } } else { - add_message("danger", "An error occurred submitting your answers"); + add_message("danger", "An error occurred submitting the results of your judging"); return; } @@ -352,37 +421,55 @@ class Ambiguities extends React.PureComponent { } handle_click(word) { + + /* Let the server know we are doing some judging, (but rate limit + * this so we don't send a "judging" notification more frquently + * than necessary. + */ + if (! this.judging_sent_recently) { + fetch_post_json(`judging/${this.props.prompt.id}`); + this.judging_sent_recently = true; + setTimeout(() => { this.judging_sent_recently = false; }, 1000); + } + 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({ @@ -395,11 +482,46 @@ class Ambiguities extends React.PureComponent { if (this.state.submitted) return (
+ The following players have completed judging: + {[...this.props.players_judged].join(', ')} +
- Please wait for the rest of the players to complete judging. + Still waiting for the following players:
+- Please wait for the rest of the players to submit their answers. + The following players have submitted their answers: + {[...this.props.players_answered].join(', ')}
++ Still waiting for the following players: +
+