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