CVS: TapestryBook/hangman1/src/hangman1 Guess.java,NONE,1.1 Home.java,NONE,1.1 Lose.java,NONE,1.1 WordList.txt,NONE,1.1 WordSource.java,NONE,1.1 Visit.java,NONE,1.1 Game.java,NONE,1.1

Howard Lewis Ship <[email protected]>
Newsgroups gmane.comp.java.tapestry.cvs
Message-ID <[email protected]>
Update of /cvsroot/tapestry/TapestryBook/hangman1/src/hangman1
In directory sc8-pr-cvs1:/tmp/cvs-serv10853/hangman1/src/hangman1

Added Files:
	Guess.java Home.java Lose.java WordList.txt WordSource.java 
	Visit.java Game.java 
Log Message:
Rename app from "hangman" to "hangman1".
Create (temporary) dependency of jakarta-tapestry project for latest code.

--- NEW FILE: Guess.java ---
package hangman1;

import java.util.ArrayList;
import java.util.List;

import net.sf.tapestry.IAsset;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.html.BasePage;

/**
 *
 *  A page that presents the state of the game to the user and allows the user to 
 *  make guesses (by clicking on images for different letters).
 *
 *  @author Howard Lewis Ship
 *  @version $Id: Guess.java,v 1.1 2003/01/13 19:02:18 hship Exp $
 *
 **/

public class Guess extends BasePage
{
    private char _letter;
    private boolean _letterGuessed;
    private int _guessIndex;

    /**
     *  This method must return the page back to its pristine state.
     * 
     **/

    public void initialize()
    {
        _letter = 0;
        _letterGuessed = false;
        _guessIndex = 0;
    }

    public char getLetter()
    {
        return _letter;
    }

    public void setLetter(char letter)
    {
        _letter = letter;
    }

    public IAsset getFailureImage(int failureCount)
    {
        return getAsset("digit" + failureCount);
    }

    public IAsset getScaffoldImage(int failureCount)
    {
        return getAsset("scaffold" + failureCount);
    }
  
    public String getLetterLabel()
    {
        char upper = Character.toUpperCase(_letter);

        return Character.toString(upper);
    }

    public IAsset getLetterImage()
    {
        if (_letter == '_')
            return getAsset("dash");

        return getAsset(Character.toString(_letter));
    }

    /**
     *  Returns true if the letter corresponding to the
     *  current {@link #getGuessIndex() guess index}
     *  has already been guessed by the user.
     * 
     **/

    public boolean isLetterGuessed()
    {
        return _letterGuessed;
    }

    /**
     *  Returns the current guess index, a number beteween 0
     *  and 25 which represents the letter to be guessed.
     *
     **/

    public int getGuessIndex()
    {
        return _guessIndex;
    }

    public void setLetterGuessed(boolean letterGuessed)
    {
        _letterGuessed = letterGuessed;
    }

    public void setGuessIndex(int guessIndex)
    {
        _guessIndex = guessIndex;
    }

    /**
     *  Return the image to display for the current
     *  {@link #getGuessIndex() guess index}, either a blank
     *  space if the letter has already been guessed, or
     *  the image for the corresponding letter.
     * 
     **/

    public IAsset getGuessImage()
    {
        if (_letterGuessed)
            return getAsset("space");

        String name = Character.toString(getLetterForGuessIndex());

        return getAsset(name);
    }

    /**
     *  Returns the letter corresponding to the
     *  current {@link #getGuessIndex() guess index}
     * as a letter between 'a' and 'z'.
     * 
     **/

    public char getLetterForGuessIndex()
    {
        return (char) ('a' + _guessIndex);
    }

    /**
     *  Returns the label for the guess image, either a space,
     *  or an upper-case letter.
     * 
     **/

    public String getGuessLabel()
    {
        if (_letterGuessed)
            return " ";

        char ch = Character.toUpperCase(getLetterForGuessIndex());

        return Character.toString(ch);
    }

    /**
     *  Listener method for the select link component.  We define the parameter
     *  to be the character to guess.
     * 
     **/

    public void makeGuess(IRequestCycle cycle)
    {
        Character guess = (Character) cycle.getServiceParameters()[0];

        char ch = guess.charValue();

        Visit visit = (Visit) getVisit();

        Game game = visit.getGame();

        // If this return true, then stay on this page at let
        // user keep guessing.

        if (game.makeGuess(ch))
            return;

        cycle.setPage(game.isWin() ? "Win" : "Lose");
    }
}

--- NEW FILE: Home.java ---
package hangman1;

import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.html.BasePage;

/**
 *
 *  This class contains the logic for the Home page; currently, that's very straight forward, a 
 *  <em>listener method</em> that is invoked when the user clicks the
 *  start button on the page.
 *
 *  @author Howard Lewis Ship
 *  @version $Id: Home.java,v 1.1 2003/01/13 19:02:21 hship Exp $
 *
 **/

public class Home extends BasePage
{
	public void start(IRequestCycle cycle)
	{
		// Get the visit object and cast it to the application-specific class, Visit.
		
		Visit visit = (Visit)getVisit();
		
		visit.startGame(cycle);
	}
}

--- NEW FILE: Lose.java ---
package hangman1;

import net.sf.tapestry.IAsset;
import net.sf.tapestry.IRequestCycle;
import net.sf.tapestry.html.BasePage;

/**
 *
 *  Page displayed when the users misses too many guesses.
 *  Displays the target word, and gives the user a chance
 *  to start a new game.
 *
 *  @author Howard Lewis Ship
 *  @version $Id: Lose.java,v 1.1 2003/01/13 19:02:24 hship Exp $
 *
 **/

public class Lose extends BasePage
{
    private char _letter;

    public void initialize()
    {
        _letter = 0;
    }

    public char getLetter()
    {
        return _letter;
    }

    public void setLetter(char letter)
    {
        _letter = letter;
    }

    public char getLetterLabel()
    {
        return Character.toUpperCase(_letter);
    }

    public IAsset getLetterImage()
    {
        return getAsset(Character.toString(_letter));
    }
    
    public void playAgain(IRequestCycle cycle)
    {
    	Visit visit = (Visit)getVisit();
    	
    	visit.startGame(cycle);
    }
}

--- NEW FILE: WordList.txt ---
# $Id: WordList.txt,v 1.1 2003/01/13 19:02:24 hship Exp $
#
# One word per line.  Case and whitespace is ignored.  Comments
# are lines that begin with hash.  Blank lines are ignored.
# The UI is configured for max word length of eight.

tapestry
greyhound
microsoft
peanut
pinball
helmet
stereo
citadel
gargoyle
cranium
axiom
media
virus
orbit
wizard
golden
revenge
bowling
annual
mercy
anatomy
zanzibar
pepper
connect
monster
impress
doctor
horror
cooking
virtual
power
freight
formula
board
eclipse
biology


--- NEW FILE: WordSource.java ---
package hangman1;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import net.sf.tapestry.ApplicationRuntimeException;

/**
 *
 *  Used by {@link hangman1.Game} to obtain a a random word.
 *
 *  @author Howard Lewis Ship
 *  @version $Id: WordSource.java,v 1.1 2003/01/13 19:02:26 hship Exp $
 *
 **/

public class WordSource
{
    private int _nextWord;
    private List _words = new ArrayList();

    public WordSource()
    {
        readWords();
    }

    private void readWords()
    {

        try
        {
            InputStream in = getClass().getResourceAsStream("WordList.txt");
            Reader r = new InputStreamReader(in);
            LineNumberReader lineReader = new LineNumberReader(r);

            while (true)
            {
                String line = lineReader.readLine();

                if (line == null)
                    break;

                if (line.startsWith("#"))
                    continue;

                String word = line.trim().toLowerCase();

                if (word.length() == 0)
                    continue;

                _words.add(word);
            }

            lineReader.close();
        }
        catch (IOException ex)
        {
            throw new ApplicationRuntimeException(
                "Unable to read list of words from file WordList.txt.",
                ex);
        }

        // Randomize the word order

        Collections.shuffle(_words);

    }

    /**
     *  Gets the next random word from the list.  Once the list is exhausted, it
     *  is shuffled and the first word is taken; this ensures that the user won't
     *  see a repeat word until all words in the list have been played.
     * 
     **/

    public String nextWord()
    {
        if (_nextWord >= _words.size())
        {
            _nextWord = 0;
            Collections.shuffle(_words);
        }

        return (String) _words.get(_nextWord++);
    }
}

--- NEW FILE: Visit.java ---
package hangman1;

import net.sf.tapestry.IRequestCycle;

/**
 *
 *  The Visit class runs most of the game logic and acts as controller, mediating
 *  between the pure interface code and the pure logic code.
 *
 *  @author Howard Lewis Ship
 *  @version $Id: Visit.java,v 1.1 2003/01/13 19:02:27 hship Exp $
 *
 **/

public class Visit
{
    private WordSource _wordSource;
    private Game _game;

    public void startGame(IRequestCycle cycle)
    {
        // In a real application, the word source would be shared between all sessions.  Here, we just allow
        // each Visit to have its own instance.

        if (_wordSource == null)
            _wordSource = new WordSource();

        // On the other hand, the Game is specifically for this
        // Visit.

        if (_game == null)
            _game = new Game();

        _game.start(_wordSource.nextWord());

        // Now that the Game is initialized, we can go to the Guess page to
        // allow the user to start making guesses.

        cycle.setPage("Guess");
    }
    
    /**
     *  Returns the {@link Game} instance for this Visit; this is used
     *  primarily by the {@link Guess} page to display things like
     *  the number of remaining guesses and the list of guessed
     *  and unguessed letters.
     * 
     **/

    public Game getGame()
    {
        return _game;
    }
}

--- NEW FILE: Game.java ---
package hangman1;

public class Game
{
    /**
     *  The word being guessed.
     * 
     **/

    private String _targetWord;

    /**
     *  The number of remaining failures allowed.  This
     *  is decremented with each invalid guess, and
     *  ends the game when it reaches zero.
     * 
     **/

    private int _failuresLeft;

    /**
     *  The letters of the word being guessed.  These initially are all the underscore
     *  character (indicating unguessed positions), but are converted to real
     *  letters when a succesful guess occurs.
     * 
     **/

    private char[] _letters;

    /**
     *  Indicates which letters the user has already guessed.  'A' is at position 0,
     *  'B' at position 1, and so on, up to 'Z' at position 25.
     * 
     **/

    private boolean[] _guessed = new boolean[26];

    /**
     *  Set to true when the user succesfully guesses the word
     *  (a slots in the letters are filled in).
     * 
     **/

    private boolean _win;

    /**
     *  Returns true if the user has guessed all letters in the word.
     * 
     **/

    public boolean isWin()
    {
        return _win;
    }

    /**
     *  Returns an array of letters that have been guessed by the user, with
     *  an underscore for each unguessed position.  Once the user loses,
     *  this returns the array of actual letters in the target word.
     * 
     *  <p>
     *  The caller must not modify this array.
     * 
     **/

    public char[] getLetters()
    {
        return _letters;
    }

    /**
     *  Returns the number of failed guesses remaining.
     * 
     **/

    public int getFailuresLeft()
    {
        return _failuresLeft;
    }

    /**
     *  Returns an array of flags indicating which letters have already been guessed.
     *  There are 26 flags, one for each letter, starting with 'A' at index 0, up to 'Z' at
     *  index 25.
     * 
     *  <p>The caller must not modify this array.
     * 
     **/

    public boolean[] getGuessedLetters()
    {
        return _guessed;
    }

    /**
     *  Initializes the Game with a new target word.  This resets the failures and initializes the array of letters. 
     * 
     **/

    public void start(String word)
    {
        _targetWord = word;
        _failuresLeft = 6;
        _win = false;

        int count = word.length();

        _letters = new char[count];

        for (int i = 0; i < _letters.length; i++)
            _letters[i] = '_';

        for (int i = 0; i < 26; i++)
            _guessed[i] = false;
    }

    /**
     *  The user makes a guess.  If the letter has already been guessed, then no change occurs.
     *  Otherwise, there's a check to see if the guess fills in any positions in the target word.
     *  This may result in a win.  If the guess doesn't match any letter of the word, then
     *  a failure occurs; when enough failures occur, there's a loss.
     * 
     *  @returns true if further guesses are allowed (this guess did not result in a win or a loss),
     *  or false if further guesses are not allowed (the user guessed the word, or used up
     *  all possible failures).
     * 
     **/

    public boolean makeGuess(char letter)
    {
        char ch = Character.toLowerCase(letter);

        if (ch < 'a' || ch > 'z')
            throw new IllegalArgumentException("Must provide an alphabetic character.");

        int index = ch - 'a';

        // If the user (somehow) guesses the same letter more than once, it does not affect
        // state of the game.

        if (_guessed[index])
            return true;

        _guessed[index] = true;

        boolean good = false;
        boolean complete = true;

        for (int i = 0; i < _letters.length; i++)
        {
            if (_letters[i] != '_')
                continue;

            if (_targetWord.charAt(i) == ch)
            {
                good = true;
                _letters[i] = ch;
                continue;
            }

            // An empty slot that does not match
            // the guess, so the word is not
            // complete.

            complete = false;
        }

        if (good)
        {
            _win = complete;

            return !complete;
        }

        _failuresLeft--;

        if (_failuresLeft <= 0)
        {
            // Replace the letters array with the solution

            _letters = _targetWord.toCharArray();

            return false;
        }

        // Not a good guess, but not a loss yet

        return true;
    }
}



-------------------------------------------------------
This SF.NET email is sponsored by: FREE  SSL Guide from Thawte
are you planning your Web Server Security? Click here to get a FREE
Thawte SSL guide and find the answers to all your  SSL security issues.
http://ads.sourceforge.net/cgi-bin/redirect.pl?thaw0026en
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.