001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.applets.hangman;
022:
023: import java.applet.Applet;
024: import java.applet.AudioClip;
025:
026: import java.awt.Color;
027: import java.awt.Font;
028: import java.awt.FontMetrics;
029: import java.awt.Graphics;
030: import java.awt.Image;
031: import java.awt.MediaTracker;
032: import java.awt.event.KeyEvent;
033: import java.awt.event.KeyListener;
034:
035: import java.util.ArrayList;
036: import java.util.List;
037: import java.util.StringTokenizer;
038:
039: /**
040: * <a href="Hangman.java.html"><b><i>View Source</i></b></a>
041: *
042: * @author Alexander Chow
043: *
044: */
045: public class Hangman extends Applet implements KeyListener {
046:
047: private static final int MEDIA_TRACKER_HANG = 0;
048:
049: private static final int MEDIA_TRACKER_DANCE = 1;
050:
051: private static final int TOTAL_IMAGES_HANG = 5;
052:
053: private static final int TOTAL_IMAGES_DANCE = 5;
054:
055: private static final int HANG_WIDTH = 42;
056:
057: private static final int HANG_HEIGHT = 64;
058:
059: private static final int DANCE_WIDTH = 100;
060:
061: private static final int DANCE_HEIGHT = 80;
062:
063: private static final int[] DANCE_STEP = new int[] { 12, 28, 8, -6,
064: -20, 12, -10, -6, -10, -20, 8, 8, 12, -8, -4 };
065:
066: public void init() {
067: _initValues();
068: _buildWordList();
069: _loadResources();
070:
071: addKeyListener(this );
072: _newGame();
073: }
074:
075: public void paint(Graphics g) {
076: // gallows and noose
077: g.setColor(new Color(128, 64, 0));
078: g.fillRect(10, HANG_HEIGHT * 2 + 10, HANG_WIDTH + 3, 3);
079: g.fillRect(HANG_WIDTH / 2 + 10, 10, 3, HANG_HEIGHT * 2);
080: g.fillRect(HANG_WIDTH / 2 + 10, 10, HANG_WIDTH / 2 + HANG_WIDTH
081: / 2, 3);
082: g.fillRect(HANG_WIDTH * 3 / 2 + 9, 10, 3, HANG_HEIGHT / 3 + 1);
083:
084: // hanging images and wrong letters
085: if (_wrongGuess.length() != 0) {
086: g.drawImage(_hangImages[_wrongGuess.length() - 1],
087: HANG_WIDTH + 10, HANG_HEIGHT / 3, this );
088:
089: g.setColor(Color.RED);
090: g.setFont(_wrongFont);
091: g.drawChars(_wrongGuess.toUpperCase().toCharArray(), 0,
092: _wrongGuess.length(), HANG_WIDTH * 2, _wrongMetrics
093: .getHeight() + 1);
094: }
095:
096: // blank lines and correct letters
097: g.setColor(Color.BLACK);
098: g.setFont(_rightFont);
099: int width = _rightMetrics.charWidth(' ');
100: char[] wordChars = _getWord().toCharArray();
101: for (int i = 0; i < wordChars.length; i++) {
102: if (wordChars[i] != ' ') {
103: g.drawLine(HANG_WIDTH * 2 + 2 * i * width + 1,
104: HANG_HEIGHT * 2 + 1, HANG_WIDTH * 2 + 2
105: * (i + 1) * width - 1,
106: HANG_HEIGHT * 2 + 1);
107:
108: if (_gameOver()
109: || _rightGuess.indexOf(wordChars[i]) != -1) {
110: g.drawChars(_getWord().toUpperCase().toCharArray(),
111: i, 1, HANG_WIDTH * 2 + 2 * i * width
112: + width / 2, HANG_HEIGHT * 2);
113: }
114: }
115: }
116:
117: // dancing images
118: g.clearRect(_danceX, _danceY, DANCE_WIDTH, DANCE_HEIGHT);
119: if (_danceIndex != -1) {
120: _danceX += DANCE_STEP[_danceIndex % DANCE_STEP.length];
121: _danceX = Math.max(_danceX, _danceXLo);
122: _danceX = Math.min(_danceX, _danceXHi);
123:
124: g.drawImage(_danceImages[_danceIndex % TOTAL_IMAGES_DANCE],
125: _danceX, _danceY, this );
126: }
127: }
128:
129: public void keyPressed(KeyEvent e) {
130: }
131:
132: public void keyReleased(KeyEvent e) {
133: char key = e.getKeyChar();
134:
135: if (!_gameOver()) {
136: if ((key < 'a' || key > 'z')
137: || (_rightGuess.indexOf(key) != -1)
138: || (_wrongGuess.indexOf(key) != -1)) {
139:
140: play(getCodeBase(), "audio/ding.au");
141: } else {
142: Character letter = new Character(key);
143: if (_getWord().indexOf(key) != -1) {
144: _rightGuess += letter;
145:
146: for (int i = 0; i < _getWord().length(); i++) {
147: if (_getWord().charAt(i) == key) {
148: _guessLength++;
149: }
150: }
151:
152: if (_guessLength == _getWord().length()) {
153: play(getCodeBase(), "audio/whoopy.au");
154: _startDance();
155: } else {
156: play(getCodeBase(), "audio/ah.au");
157: }
158: } else {
159: _wrongGuess += letter;
160:
161: if (_wrongGuess.length() < TOTAL_IMAGES_HANG) {
162: play(getCodeBase(), "audio/ooh.au");
163: } else {
164: play(getCodeBase(), "audio/scream.au");
165: }
166: }
167: }
168:
169: repaint();
170: } else {
171: _stopDance();
172: _newGame();
173: }
174: e.consume();
175: }
176:
177: public void keyTyped(KeyEvent e) {
178: }
179:
180: private void _initValues() {
181: _tracker = new MediaTracker(this );
182: _danceImages = new Image[TOTAL_IMAGES_DANCE];
183: _hangImages = new Image[TOTAL_IMAGES_HANG];
184: _danceIndex = -1;
185: _danceY = HANG_HEIGHT / 2;
186: _danceX = _danceXLo = HANG_WIDTH * 2;
187: _danceXHi = Math.min(DANCE_WIDTH * 2 + HANG_WIDTH * 2,
188: getWidth() - DANCE_WIDTH);
189: _wordList = new ArrayList();
190: _wrongFont = new Font("MONOSPACED", Font.BOLD, 16);
191: _wrongMetrics = getFontMetrics(_wrongFont);
192: _rightFont = new Font("MONOSPACED", Font.PLAIN, 14);
193: _rightMetrics = getFontMetrics(_rightFont);
194: }
195:
196: private void _buildWordList() {
197: String paramWords = getParameter("word_list");
198: if (paramWords != null) {
199: StringTokenizer st = new StringTokenizer(paramWords, ",");
200:
201: while (st.hasMoreTokens()) {
202: boolean skip = false;
203:
204: String token = st.nextToken().trim();
205: for (int i = 0; i < token.length(); i++) {
206: char c = token.charAt(i);
207: if ((c < 'a' || c > 'z') && c != ' ') {
208: skip = true;
209: break;
210: }
211: }
212:
213: if (!skip) {
214: _wordList.add(token);
215: } else {
216: System.err.println("Token '" + token
217: + "' contains invalid characters");
218: }
219: }
220: }
221:
222: // Populate list with something
223: if (_wordList.isEmpty()) {
224: _wordList.add("liferay");
225: _wordList.add("open source");
226: _wordList.add("enterprise");
227: _wordList.add("for life");
228: }
229: }
230:
231: private void _loadResources() {
232: for (int i = 0; i < TOTAL_IMAGES_HANG; i++) {
233: Image img = getImage(getCodeBase(), "images/hanging/h"
234: + (i + 1) + ".gif");
235: _tracker.addImage(img, MEDIA_TRACKER_HANG);
236: _hangImages[i] = img;
237: }
238:
239: for (int i = 0; i < TOTAL_IMAGES_DANCE; i++) {
240: Image img = getImage(getCodeBase(), "images/dancing/d"
241: + (i + 1) + ".gif");
242: _tracker.addImage(img, MEDIA_TRACKER_DANCE);
243: _danceImages[i] = img;
244: }
245:
246: _danceMusic = getAudioClip(getCodeBase(), "audio/dance.au");
247: }
248:
249: private void _newGame() {
250: try {
251: _tracker.waitForID(MEDIA_TRACKER_HANG);
252: } catch (InterruptedException ex) {
253: // don't do anything
254: }
255: _tracker.checkAll(true);
256:
257: _rightGuess = new String();
258: _wrongGuess = new String();
259: _wordIndex = (int) (Math.random() * 100) % _wordList.size();
260:
261: _guessLength = 0;
262: String word = _getWord();
263: for (int i = 0; i < word.length(); i++) {
264: if (word.charAt(i) == ' ') {
265: _guessLength++;
266: }
267: }
268:
269: repaint();
270: }
271:
272: private boolean _gameOver() {
273: return _guessLength == _getWord().length()
274: || _wrongGuess.length() == TOTAL_IMAGES_HANG;
275: }
276:
277: private String _getWord() {
278: return (String) _wordList.get(_wordIndex);
279: }
280:
281: private void _startDance() {
282: _danceThread = new DanceThread();
283: _danceThread.start();
284: }
285:
286: private void _stopDance() {
287: if (_danceThread != null) {
288: _danceThread.interrupt();
289: _danceThread = null;
290: }
291: }
292:
293: private class DanceThread extends Thread {
294: public void run() {
295: _danceX = _danceXLo;
296: _danceX += (int) (Math.random() * 100)
297: % (_danceXHi - _danceXLo);
298: _danceIndex = 0;
299: _danceMusic.loop();
300: try {
301: _tracker.waitForID(MEDIA_TRACKER_DANCE);
302:
303: for (;;) {
304: _danceIndex++;
305: repaint();
306: sleep(250);
307: }
308: } catch (InterruptedException ex) {
309: // do nothing
310: }
311: _danceIndex = -1;
312: _danceMusic.stop();
313: repaint();
314: }
315: }
316:
317: // Media variables
318: private MediaTracker _tracker;
319: private AudioClip _danceMusic;
320: private Image[] _danceImages;
321: private Image[] _hangImages;
322: private Thread _danceThread;
323: private int _danceIndex;
324: private int _danceY;
325: private int _danceX;
326: private int _danceXLo;
327: private int _danceXHi;
328:
329: // Specific to the words
330: private List _wordList;
331: private int _wordIndex;
332: private String _rightGuess;
333: private String _wrongGuess;
334: private int _guessLength;
335:
336: // Font values
337: private Font _wrongFont;
338: private FontMetrics _wrongMetrics;
339: private Font _rightFont;
340: private FontMetrics _rightMetrics;
341:
342: }
|