001: package dalma.sample.hangman;
002:
003: import dalma.EndPoint;
004: import dalma.TimeUnit;
005: import dalma.Workflow;
006: import dalma.endpoints.email.EmailEndPoint;
007:
008: import javax.mail.MessagingException;
009: import javax.mail.internet.MimeMessage;
010: import javax.mail.internet.MimeMultipart;
011: import java.io.IOException;
012: import java.util.logging.Level;
013:
014: /**
015: * A hangman game.
016: *
017: * <p>
018: * One instance of this class represents one on-going game of Hangman.
019: *
020: * <p>
021: * This class is bytecode-instrumented before execution.
022: *
023: * @author Kohsuke Kawaguchi
024: */
025: public class HangmanWorkflow extends Workflow {
026:
027: /**
028: * {@link EndPoint} that we are talking to.
029: */
030: private final EmailEndPoint ep;
031: private final MimeMessage msg; // the first message
032:
033: public HangmanWorkflow(EmailEndPoint ep, MimeMessage msg) {
034: this .ep = ep;
035: this .msg = msg;
036: }
037:
038: public void run() {
039: try {
040: // the answer
041: String word = WordList.getRandomWord();
042:
043: getLogger().info(
044: "Started a new game with " + msg.getFrom()[0]);
045: getLogger().info("Answer is " + word);
046: setTitle("Game with " + msg.getFrom()[0]);
047:
048: int retry = 6; // allow 6 guesses
049:
050: // the characters the user chose
051: // true means selected
052: boolean[] opened = new boolean[26];
053:
054: MimeMessage mail = msg; // last e-mail received
055:
056: while (retry > 0) {
057: // send the hint
058: mail = (MimeMessage) mail.reply(false);
059: mail
060: .setText("Word: "
061: + maskWord(word, opened)
062: + "\n\n"
063: + "You Chose: "
064: + maskWord(
065: "abcdefghijklmnopqrstuvwxyz",
066: opened) + "\n\n" + retry
067: + " more guesses\n");
068:
069: mail = ep.waitForReply(mail, 7, TimeUnit.DAYS);
070: if (mail == null) {
071: // it's been 1 week. sorry.
072: System.out.println("timeout");
073: return;
074: }
075:
076: getLogger().info(
077: "Received a reply from " + mail.getFrom()[0]);
078:
079: // pick up the char the user chose
080: char ch = getSelectedChar(mail.getContent());
081: if (ch == 0)
082: continue;
083:
084: if (word.indexOf(ch) < 0) {
085: // bzzzt!
086: retry--;
087: }
088:
089: opened[ch - 'a'] = true;
090:
091: if (maskWord(word, opened).equals(word)) {
092: // bingo!
093: mail = (MimeMessage) mail.reply(false);
094: mail.setText("Bingo! The word was\n\n " + word);
095: ep.send(mail);
096: getLogger().info("The user won");
097: return;
098: }
099: }
100:
101: MimeMessage reply = (MimeMessage) mail.reply(false);
102: reply.setText("Bzzzt! The word was\n\n " + word);
103: ep.send(reply);
104: getLogger().info("The user lost");
105: } catch (Exception e) {
106: getLogger().log(Level.WARNING, "error", e);
107: }
108: }
109:
110: /**
111: * Picks up a character chosen by the user.
112: *
113: * The algorithm is to find the first line that contains just one character.
114: */
115: private static char getSelectedChar(Object content)
116: throws MessagingException, IOException {
117: String body = getMailBody(content);
118: for (String line : body.split("\n")) {
119: line = line.trim();
120: if (line.length() == 1) {
121: char ch = Character.toLowerCase(line.charAt(0));
122: if ('a' <= ch && ch <= 'z')
123: return ch;
124: }
125: }
126: return 0;
127: }
128:
129: /**
130: * Obtains the mail body as a string.
131: *
132: * E-mail contents can be delivered in so many forms
133: * (plain text, HTML, or S/MIME packaged, ...), so this has to be
134: * somewhat arbitrary and ugly.
135: */
136: private static String getMailBody(Object content)
137: throws MessagingException, IOException {
138: if (content instanceof MimeMultipart) {
139: MimeMultipart mp = (MimeMultipart) content;
140: return getMailBody(mp.getBodyPart(0).getContent());
141: }
142: return content.toString();
143: }
144:
145: /**
146: * Creates a mask of a word (e.g., p__tt_ from pretty) based on
147: * the currently selected set of characters.
148: *
149: * @param word
150: * word to mask
151: * @param opened
152: * each item in the array represents whether or not the character is
153: * chosen.
154: */
155: private String maskWord(String word, boolean[] opened) {
156: String mask = word;
157: for (int i = 0; i < opened.length; i++) {
158: if (!opened[i])
159: mask = mask.replace((char) ('a' + i), '_');
160: }
161: return mask;
162: }
163:
164: private static final long serialVersionUID = 1L;
165: }
|