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 }