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