Mercurial > irccd
comparison plugins/hangman/hangman.js @ 773:8c44bbcbbab9
Misc: style, cleanup and update
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 26 Oct 2018 13:01:00 +0200 |
parents | 3e816cebed2c |
children | 06cc2f95f479 |
comparison
equal
deleted
inserted
replaced
772:f5ccf65ae929 | 773:8c44bbcbbab9 |
---|---|
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 // Plugin information. | 19 // Plugin information. |
20 info = { | 20 info = { |
21 name: "hangman", | 21 name: "hangman", |
22 author: "David Demelier <markand@malikania.fr>", | 22 author: "David Demelier <markand@malikania.fr>", |
23 license: "ISC", | 23 license: "ISC", |
24 summary: "A hangman game for IRC", | 24 summary: "A hangman game for IRC", |
25 version: "@IRCCD_VERSION@" | 25 version: "@IRCCD_VERSION@" |
26 }; | 26 }; |
27 | 27 |
28 // Modules. | 28 // Modules. |
29 var Logger = Irccd.Logger; | 29 var Logger = Irccd.Logger; |
30 var File = Irccd.File; | 30 var File = Irccd.File; |
36 // Default options. | 36 // Default options. |
37 Plugin.config["collaborative"] = "true"; | 37 Plugin.config["collaborative"] = "true"; |
38 | 38 |
39 // Formats. | 39 // Formats. |
40 Plugin.format = { | 40 Plugin.format = { |
41 "asked": "#{nickname}, '#{letter}' was already asked.", | 41 "asked": "#{nickname}, '#{letter}' was already asked.", |
42 "dead": "#{nickname}, fail the word was: #{word}.", | 42 "dead": "#{nickname}, fail the word was: #{word}.", |
43 "found": "#{nickname}, nice! the word is now #{word}", | 43 "found": "#{nickname}, nice! the word is now #{word}", |
44 "running": "#{nickname}, the game is already running and the word is: #{word}", | 44 "running": "#{nickname}, the game is already running and the word is: #{word}", |
45 "start": "#{nickname}, the game is started, the word to find is: #{word}", | 45 "start": "#{nickname}, the game is started, the word to find is: #{word}", |
46 "win": "#{nickname}, congratulations, the word is #{word}.", | 46 "win": "#{nickname}, congratulations, the word is #{word}.", |
47 "wrong-word": "#{nickname}, this is not the word.", | 47 "wrong-word": "#{nickname}, this is not the word.", |
48 "wrong-player": "#{nickname}, please wait until someone else proposes.", | 48 "wrong-player": "#{nickname}, please wait until someone else proposes.", |
49 "wrong-letter": "#{nickname}, there is no '#{letter}'." | 49 "wrong-letter": "#{nickname}, there is no '#{letter}'." |
50 }; | 50 }; |
51 | 51 |
52 function Hangman(server, channel) | 52 function Hangman(server, channel) |
53 { | 53 { |
54 this.server = server; | 54 this.server = server; |
55 this.channel = channel; | 55 this.channel = channel; |
56 this.tries = 10; | 56 this.tries = 10; |
57 this.select(); | 57 this.select(); |
58 } | 58 } |
59 | 59 |
60 /** | 60 /** |
61 * Map of games. | 61 * Map of games. |
62 */ | 62 */ |
64 | 64 |
65 /** | 65 /** |
66 * List of words. | 66 * List of words. |
67 */ | 67 */ |
68 Hangman.words = { | 68 Hangman.words = { |
69 all: [], //!< All words, | 69 all: [], //!< All words, |
70 registry: {} //!< Words list per server/channel. | 70 registry: {} //!< Words list per server/channel. |
71 }; | 71 }; |
72 | 72 |
73 /** | 73 /** |
74 * Search for an existing game. | 74 * Search for an existing game. |
75 * | 75 * |
77 * @param channel the channel name | 77 * @param channel the channel name |
78 * @return the hangman instance or undefined if no one exists | 78 * @return the hangman instance or undefined if no one exists |
79 */ | 79 */ |
80 Hangman.find = function (server, channel) | 80 Hangman.find = function (server, channel) |
81 { | 81 { |
82 return Hangman.map[server.toString() + '@' + channel]; | 82 return Hangman.map[server.toString() + '@' + channel]; |
83 } | 83 } |
84 | 84 |
85 /** | 85 /** |
86 * Create a new game, store it in the map and return it. | 86 * Create a new game, store it in the map and return it. |
87 * | 87 * |
89 * @param channel the channel name | 89 * @param channel the channel name |
90 * @return the hangman object | 90 * @return the hangman object |
91 */ | 91 */ |
92 Hangman.create = function (server, channel) | 92 Hangman.create = function (server, channel) |
93 { | 93 { |
94 return Hangman.map[server.toString() + "@" + channel] = new Hangman(server, channel); | 94 return Hangman.map[server.toString() + "@" + channel] = new Hangman(server, channel); |
95 } | 95 } |
96 | 96 |
97 /** | 97 /** |
98 * Remove the specified game from the map. | 98 * Remove the specified game from the map. |
99 * | 99 * |
100 * @param game the game to remove | 100 * @param game the game to remove |
101 */ | 101 */ |
102 Hangman.remove = function (game) | 102 Hangman.remove = function (game) |
103 { | 103 { |
104 delete Hangman.map[game.server + "@" + game.channel]; | 104 delete Hangman.map[game.server + "@" + game.channel]; |
105 } | 105 } |
106 | 106 |
107 /** | 107 /** |
108 * Check if the text is a valid word. | 108 * Check if the text is a valid word. |
109 * | 109 * |
110 * @param word the word to check | 110 * @param word the word to check |
111 * @return true if a word | 111 * @return true if a word |
112 */ | 112 */ |
113 Hangman.isWord = function (word) | 113 Hangman.isWord = function (word) |
114 { | 114 { |
115 if (word.length === 0) | 115 if (word.length === 0) |
116 return false; | 116 return false; |
117 | 117 |
118 for (var i = 0; i < word.length; ++i) | 118 for (var i = 0; i < word.length; ++i) |
119 if (!Unicode.isLetter(word.charCodeAt(i))) | 119 if (!Unicode.isLetter(word.charCodeAt(i))) |
120 return false; | 120 return false; |
121 | 121 |
122 return true; | 122 return true; |
123 } | 123 } |
124 | 124 |
125 /** | 125 /** |
126 * Load all words. | 126 * Load all words. |
127 */ | 127 */ |
128 Hangman.loadWords = function () | 128 Hangman.loadWords = function () |
129 { | 129 { |
130 var path; | 130 var path; |
131 | 131 |
132 // User specified file? | 132 // User specified file? |
133 if (Plugin.config["file"]) | 133 if (Plugin.config["file"]) |
134 path = Plugin.config["file"]; | 134 path = Plugin.config["file"]; |
135 else | 135 else |
136 path = Plugin.paths.config + "/words.conf"; | 136 path = Plugin.paths.config + "/words.conf"; |
137 | 137 |
138 try { | 138 try { |
139 Logger.info("loading words..."); | 139 Logger.info("loading words..."); |
140 | 140 |
141 var file = new File(path, "r"); | 141 var file = new File(path, "r"); |
142 var line; | 142 var line; |
143 | 143 |
144 while ((line = file.readline()) !== undefined) | 144 while ((line = file.readline()) !== undefined) |
145 if (Hangman.isWord(line)) | 145 if (Hangman.isWord(line)) |
146 Hangman.words.all.push(line); | 146 Hangman.words.all.push(line); |
147 } catch (e) { | 147 } catch (e) { |
148 throw new Error("could not open '" + path + "'"); | 148 throw new Error("could not open '" + path + "'"); |
149 } | 149 } |
150 | 150 |
151 if (Hangman.words.all.length === 0) | 151 if (Hangman.words.all.length === 0) |
152 throw new Error("empty word database"); | 152 throw new Error("empty word database"); |
153 | 153 |
154 Logger.info("number of words in database: " + Hangman.words.all.length); | 154 Logger.info("number of words in database: " + Hangman.words.all.length); |
155 } | |
156 | |
157 /** | |
158 * Load all formats. | |
159 */ | |
160 Hangman.loadFormats = function () | |
161 { | |
162 // --- DEPRECATED ------------------------------------------- | |
163 // | |
164 // This code will be removed. | |
165 // | |
166 // Since: 2.1.0 | |
167 // Until: 3.0.0 | |
168 // Reason: new [format] section replaces it. | |
169 // | |
170 // ---------------------------------------------------------- | |
171 for (var key in Plugin.format) { | |
172 var optname = "format-" + key; | |
173 | |
174 if (typeof (Plugin.config[optname]) !== "string") | |
175 continue; | |
176 | |
177 if (Plugin.config[optname].length === 0) | |
178 Logger.warning("skipping empty '" + optname + "' format"); | |
179 else | |
180 Plugin.format[key] = Plugin.config[optname]; | |
181 } | |
182 } | 155 } |
183 | 156 |
184 /** | 157 /** |
185 * Select the next word for the game. | 158 * Select the next word for the game. |
186 */ | 159 */ |
187 Hangman.prototype.select = function () | 160 Hangman.prototype.select = function () |
188 { | 161 { |
189 var id = this.server.toString() + "@" + this.channel; | 162 var id = this.server.toString() + "@" + this.channel; |
190 | 163 |
191 // Reload the words if empty. | 164 // Reload the words if empty. |
192 if (!Hangman.words.registry[id] || Hangman.words.registry[id].length === 0) | 165 if (!Hangman.words.registry[id] || Hangman.words.registry[id].length === 0) |
193 Hangman.words.registry[id] = Hangman.words.all.slice(0); | 166 Hangman.words.registry[id] = Hangman.words.all.slice(0); |
194 | 167 |
195 var i = Math.floor(Math.random() * Hangman.words.registry[id].length); | 168 var i = Math.floor(Math.random() * Hangman.words.registry[id].length); |
196 | 169 |
197 this.word = Hangman.words.registry[id][i]; | 170 this.word = Hangman.words.registry[id][i]; |
198 | 171 |
199 // Erase words from the registry. | 172 // Erase words from the registry. |
200 Hangman.words.registry[id].splice(i, 1); | 173 Hangman.words.registry[id].splice(i, 1); |
201 | 174 |
202 // Fill table. | 175 // Fill table. |
203 this.table = {}; | 176 this.table = {}; |
204 | 177 |
205 for (var j = 0; j < this.word.length; ++j) | 178 for (var j = 0; j < this.word.length; ++j) |
206 this.table[this.word.charCodeAt(j)] = false; | 179 this.table[this.word.charCodeAt(j)] = false; |
207 } | 180 } |
208 | 181 |
209 /** | 182 /** |
210 * Format the word with underscore and letters. | 183 * Format the word with underscore and letters. |
211 * | 184 * |
212 * @return the secret | 185 * @return the secret |
213 */ | 186 */ |
214 Hangman.prototype.formatWord = function () | 187 Hangman.prototype.formatWord = function () |
215 { | 188 { |
216 var str = ""; | 189 var str = ""; |
217 | 190 |
218 for (var i = 0; i < this.word.length; ++i) { | 191 for (var i = 0; i < this.word.length; ++i) { |
219 var ch = this.word.charCodeAt(i); | 192 var ch = this.word.charCodeAt(i); |
220 | 193 |
221 if (!this.table[ch]) | 194 if (!this.table[ch]) |
222 str += "_"; | 195 str += "_"; |
223 else | 196 else |
224 str += String.fromCharCode(ch); | 197 str += String.fromCharCode(ch); |
225 | 198 |
226 if (i + 1 < this.word.length) | 199 if (i + 1 < this.word.length) |
227 str += " "; | 200 str += " "; |
228 } | 201 } |
229 | 202 |
230 return str; | 203 return str; |
231 } | 204 } |
232 | 205 |
233 /** | 206 /** |
234 * Propose a word or a letter. | 207 * Propose a word or a letter. |
235 * | 208 * |
237 * @param nickname the user trying | 210 * @param nickname the user trying |
238 * @return the status of the game | 211 * @return the status of the game |
239 */ | 212 */ |
240 Hangman.prototype.propose = function (ch, nickname) | 213 Hangman.prototype.propose = function (ch, nickname) |
241 { | 214 { |
242 var status = "found"; | 215 var status = "found"; |
243 | 216 |
244 // Check for collaborative mode. | 217 // Check for collaborative mode. |
245 if (Plugin.config["collaborative"] === "true" && !this.query) { | 218 if (Plugin.config["collaborative"] === "true" && !this.query) { |
246 if (this.last !== undefined && this.last === nickname) | 219 if (this.last !== undefined && this.last === nickname) |
247 return "wrong-player"; | 220 return "wrong-player"; |
248 | 221 |
249 this.last = nickname; | 222 this.last = nickname; |
250 } | 223 } |
251 | 224 |
252 if (typeof(ch) == "number") { | 225 if (typeof(ch) == "number") { |
253 if (this.table[ch] === undefined) { | 226 if (this.table[ch] === undefined) { |
254 this.tries -= 1; | 227 this.tries -= 1; |
255 status = "wrong-letter"; | 228 status = "wrong-letter"; |
256 } else { | 229 } else { |
257 if (this.table[ch]) { | 230 if (this.table[ch]) { |
258 this.tries -= 1; | 231 this.tries -= 1; |
259 status = "asked"; | 232 status = "asked"; |
260 } else | 233 } else |
261 this.table[ch] = true; | 234 this.table[ch] = true; |
262 } | 235 } |
263 } else { | 236 } else { |
264 if (this.word != ch) { | 237 if (this.word != ch) { |
265 this.tries -= 1; | 238 this.tries -= 1; |
266 status = "wrong-word"; | 239 status = "wrong-word"; |
267 } else | 240 } else |
268 status = "win"; | 241 status = "win"; |
269 } | 242 } |
270 | 243 |
271 // Check if dead. | 244 // Check if dead. |
272 if (this.tries <= 0) | 245 if (this.tries <= 0) |
273 status = "dead"; | 246 status = "dead"; |
274 | 247 |
275 // Check if win. | 248 // Check if win. |
276 var win = true; | 249 var win = true; |
277 | 250 |
278 for (var i = 0; i < this.word.length; ++i) { | 251 for (var i = 0; i < this.word.length; ++i) { |
279 if (!this.table[this.word.charCodeAt(i)]) { | 252 if (!this.table[this.word.charCodeAt(i)]) { |
280 win = false; | 253 win = false; |
281 break; | 254 break; |
282 } | 255 } |
283 } | 256 } |
284 | 257 |
285 if (win) | 258 if (win) |
286 status = "win"; | 259 status = "win"; |
287 | 260 |
288 return status; | 261 return status; |
289 } | 262 } |
290 | 263 |
291 function onLoad() | 264 function onLoad() |
292 { | 265 { |
293 Hangman.loadFormats(); | 266 Hangman.loadWords(); |
294 Hangman.loadWords(); | |
295 } | 267 } |
296 | 268 |
297 onReload = onLoad; | 269 onReload = onLoad; |
298 | 270 |
299 function propose(server, channel, origin, game, proposition) | 271 function propose(server, channel, origin, game, proposition) |
300 { | 272 { |
301 var kw = { | 273 var kw = { |
302 channel: channel, | 274 channel: channel, |
303 command: server.info().commandChar + Plugin.info().name, | 275 command: server.info().commandChar + Plugin.info().name, |
304 nickname: Util.splituser(origin), | 276 nickname: Util.splituser(origin), |
305 origin: origin, | 277 origin: origin, |
306 plugin: Plugin.info().name, | 278 plugin: Plugin.info().name, |
307 server: server.toString() | 279 server: server.toString() |
308 }; | 280 }; |
309 | 281 |
310 var st = game.propose(proposition, kw.nickname); | 282 var st = game.propose(proposition, kw.nickname); |
311 | 283 |
312 switch (st) { | 284 switch (st) { |
313 case "found": | 285 case "found": |
314 kw.word = game.formatWord(); | 286 kw.word = game.formatWord(); |
315 server.message(channel, Util.format(Plugin.format["found"], kw)); | 287 server.message(channel, Util.format(Plugin.format["found"], kw)); |
316 break; | 288 break; |
317 case "wrong-letter": | 289 case "wrong-letter": |
318 case "wrong-player": | 290 case "wrong-player": |
319 case "wrong-word": | 291 case "wrong-word": |
320 kw.word = proposition; | 292 kw.word = proposition; |
321 case "asked": | 293 case "asked": |
322 kw.letter = String.fromCharCode(proposition); | 294 kw.letter = String.fromCharCode(proposition); |
323 server.message(channel, Util.format(Plugin.format[st], kw)); | 295 server.message(channel, Util.format(Plugin.format[st], kw)); |
324 break; | 296 break; |
325 case "dead": | 297 case "dead": |
326 case "win": | 298 case "win": |
327 kw.word = game.word; | 299 kw.word = game.word; |
328 server.message(channel, Util.format(Plugin.format[st], kw)); | 300 server.message(channel, Util.format(Plugin.format[st], kw)); |
329 | 301 |
330 // Remove the game. | 302 // Remove the game. |
331 Hangman.remove(game); | 303 Hangman.remove(game); |
332 break; | 304 break; |
333 default: | 305 default: |
334 break; | 306 break; |
335 } | 307 } |
336 } | 308 } |
337 | 309 |
338 function onCommand(server, origin, channel, message) | 310 function onCommand(server, origin, channel, message) |
339 { | 311 { |
340 var isquery = server.isSelf(channel); | 312 var isquery = server.isSelf(channel); |
341 | 313 |
342 if (isquery) | 314 if (isquery) |
343 channel = origin; | 315 channel = origin; |
344 else | 316 else |
345 channel = channel.toLowerCase(); | 317 channel = channel.toLowerCase(); |
346 | 318 |
347 var game = Hangman.find(server, channel); | 319 var game = Hangman.find(server, channel); |
348 var kw = { | 320 var kw = { |
349 channel: channel, | 321 channel: channel, |
350 command: server.info().commandChar + Plugin.info().name, | 322 command: server.info().commandChar + Plugin.info().name, |
351 nickname: Util.splituser(origin), | 323 nickname: Util.splituser(origin), |
352 origin: origin, | 324 origin: origin, |
353 plugin: Plugin.info().name, | 325 plugin: Plugin.info().name, |
354 server: server.toString() | 326 server: server.toString() |
355 }; | 327 }; |
356 | 328 |
357 if (game) { | 329 if (game) { |
358 var list = message.split(" \t"); | 330 var list = message.split(" \t"); |
359 | 331 |
360 if (list.length === 0 || String(list[0]).length === 0) { | 332 if (list.length === 0 || String(list[0]).length === 0) { |
361 kw.word = game.formatWord(); | 333 kw.word = game.formatWord(); |
362 server.message(channel, Util.format(Plugin.format["running"], kw)); | 334 server.message(channel, Util.format(Plugin.format["running"], kw)); |
363 } else { | 335 } else { |
364 var word = String(list[0]); | 336 var word = String(list[0]); |
365 | 337 |
366 if (Hangman.isWord(word)) | 338 if (Hangman.isWord(word)) |
367 propose(server, channel, origin, game, word); | 339 propose(server, channel, origin, game, word); |
368 } | 340 } |
369 } else { | 341 } else { |
370 game = Hangman.create(server, channel); | 342 game = Hangman.create(server, channel); |
371 game.query = isquery; | 343 game.query = isquery; |
372 kw.word = game.formatWord(); | 344 kw.word = game.formatWord(); |
373 server.message(channel, Util.format(Plugin.format["start"], kw)); | 345 server.message(channel, Util.format(Plugin.format["start"], kw)); |
374 } | 346 } |
375 | 347 |
376 return game; | 348 return game; |
377 } | 349 } |
378 | 350 |
379 function onMessage(server, origin, channel, message) | 351 function onMessage(server, origin, channel, message) |
380 { | 352 { |
381 if (server.isSelf(channel)) | 353 if (server.isSelf(channel)) |
382 channel = origin; | 354 channel = origin; |
383 else | 355 else |
384 channel = channel.toLowerCase(); | 356 channel = channel.toLowerCase(); |
385 | 357 |
386 var game = Hangman.find(server, channel); | 358 var game = Hangman.find(server, channel); |
387 | 359 |
388 if (!game) | 360 if (!game) |
389 return; | 361 return; |
390 | 362 |
391 if (message.length === 1 && Unicode.isLetter(message.charCodeAt(0))) | 363 if (message.length === 1 && Unicode.isLetter(message.charCodeAt(0))) |
392 propose(server, channel, origin, game, message.charCodeAt(0)); | 364 propose(server, channel, origin, game, message.charCodeAt(0)); |
393 } | 365 } |