/******************* * VisualHangman (v4) for java 1.3.1 * * This applet emulates the well-known game, including scaffold graphics. * Scalable offsetable graphics for trial and error prog dev. * Accepts spaces and hyphens, but doesn't require these to be guessed. * * Current areas for improvement: * * Scaffold graphics are 'ungrouped'; difficult to move en masse. * [?tuition topic: Grouping graphics as a single moveable entity] * * GUI layout management seems hard. * [?tuition topic: Controlling layout] * * My first 'real' Java Applet! * Coded by Andy Murray, started 22/10/02 * * last updated 06/11/02 */ import java.applet.Applet; import java.awt.*; import java.awt.event.*; public class VisHang4_131 extends Applet implements ActionListener, ItemListener { //declare variables int maxWordLength, // cannot be exceeded livesRemaining, // starts @ 10, hanged at 0 ! gScale, // graphic magnification xOS, // graphic x offset yOS, // graphic y offset colorDec, // degree of shade of grey decrement for eache wrong guess appletWidth, appletHeight; String wordToFind, // the word itself wordSoFar, // displayed to user, recalc after every button press chosenSoFar, // record of all alphabetic button presses, used only for debugging notfoundSoFar, // record of unsuccessful buttons pressed historyString, // keeps record of all words used joyWord, // stickman's victory exclamation doomWord, // stickman's worry exclamation singleLetters [], // array of individual letters for checking usercue, // general user help placeholder usercueSet, // specific user help messages... usercueFindWord, usercueFindPhrase, usercueGiveUp, usercueRevealWord, usercueRevealPhrase, usercueFailureWord, usercueFailurePhrase, usercueSuccess; boolean entryMode, // flag for when entering new word charFound [], // flag array indicating which letters have been found nothingToGuess, // flag to trap invalid words isPhrase, // flag to distinguish phrase from single word peekFlag; // FOR DEBUGGING Panel wordPanel, // for layout grouping buttonPanel, // for layout grouping infoPanel, // for layout grouping historyPanel; // for layout grouping Button anyButton, // used to construct all alphabetic buttons answerButton, // buttons given unique names for easy dis/enabling resetButton, spaceButton, hyphenButton, backspaceButton, enterButton; Color enabledColor, disabledColor, playColor, winColor, deathColor, enterColor, usercueColor; Label wordLabel, livesLabel, notfoundLabel; TextField wordTextField, livesTextField, notfoundTextField, peekTextField; TextArea historyTextArea, usercueTextArea; Checkbox historyCheckbox; // user switch for display of history Font buttonFont; /****************** * */ public void init() { peekFlag = false; // used when debugging appletWidth = 400; appletHeight = 400; maxWordLength=26; joyWord=" yay!"; doomWord=" oo-er!"; usercue="not yet set"; usercueSet=" Think of a word or phrase for somebody else to guess.\n Spell it out, then click Enter - but don't let them see!"; usercueFindWord=" Click the letters to try to find the word.\n Or click Ans to give up."; usercueFindPhrase=" Click the letters to try to find the phrase.\n Or click Ans to give up."; usercueGiveUp=" You committed suicide!\n Click Reset to play again."; usercueRevealWord=" Maybe you didn't know that word.\n Click Reset to play again."; usercueRevealPhrase=" Maybe you didn't know that phrase.\n Click Reset to play again."; usercueFailureWord=" Oh dear!\n Click Ans to see what the word was."; usercueFailurePhrase=" Oh dear!\n Click Ans to see what the phrase was."; usercueSuccess=" Well done!\n Click Reset to play again."; enabledColor = Color.orange; disabledColor = Color.lightGray; enterColor = Color.black; winColor = Color.pink; playColor = Color.white; colorDec = 14; //amount to grey the playColor each wrong guess int shade = 255-(10*colorDec); deathColor = new Color(shade, shade, shade); // usercueColor = Color.white; usercueColor = new Color(150, 200, 255); // to satisfy level 1 criteria ! buttonFont = new Font("Arial", Font.BOLD, 12); // to satisfy level 1 criteria ! historyString=""; charFound = new boolean [maxWordLength]; singleLetters = new String [maxWordLength]; gScale = 10; // gibbet magnification factor xOS = 280; // gibbet x offset yOS = 260; // gibbet y offset makeGUI(); wordToFind="*RESET*"; // leading * used to trigger new word entry routine updateAllDisplays(); // also gets called after every button press, also recalculates wordSoFar } /****************** * */ public void makeGUI() { //construct panels and layouts wordPanel = new Panel(); wordPanel.setBackground(enabledColor); buttonPanel = new Panel(); GridLayout g = new GridLayout(5, 7); g.setVgap(2); g.setHgap(1); buttonPanel.setLayout(g); buttonPanel.setBackground(Color.black); infoPanel = new Panel(); infoPanel.setBackground(Color.lightGray); historyPanel = new Panel(); historyPanel.setBackground(Color.lightGray); historyPanel.setLayout(new BorderLayout()); //construct label objects wordLabel = new Label("Word to find:"); livesLabel = new Label("Lives left:"); notfoundLabel = new Label("Not found:"); //construct non-editable text field objects wordTextField = new TextField(36); //best to specify size for 1.3.1 ************ wordTextField.setEditable(false); wordTextField.setBackground(Color.white); livesTextField= new TextField(2); livesTextField.setEditable(false); notfoundTextField = new TextField(19); notfoundTextField.setEditable(false); //add labels and text fields to panels wordPanel.add(wordLabel); wordPanel.add(wordTextField); infoPanel.add(notfoundLabel); infoPanel.add(notfoundTextField); infoPanel.add(livesLabel); infoPanel.add(livesTextField); //construct alphabetic buttons and add to button panel for (char c = 'A'; c<='Z'; c++) { anyButton = new Button(String.valueOf(c)); anyButton.addActionListener(this); anyButton.setBackground(enabledColor); anyButton.setFont(buttonFont); buttonPanel.add(anyButton); } //construct answer and reset buttons, add to button panel answerButton = new Button("Ans"); answerButton.addActionListener(this); buttonPanel.add(answerButton); resetButton = new Button("Reset"); resetButton.addActionListener(this); buttonPanel.add(resetButton); //construct additional buttons required for input, add to button panel spaceButton = new Button("Space"); spaceButton.addActionListener(this); buttonPanel.add(spaceButton); hyphenButton = new Button("Dash"); hyphenButton.addActionListener(this); buttonPanel.add(hyphenButton); backspaceButton = new Button("<<<"); backspaceButton.addActionListener(this); buttonPanel.add(backspaceButton); enterButton = new Button("Enter"); enterButton.addActionListener(this); buttonPanel.add(enterButton); //construct optional history stuff historyCheckbox = new Checkbox("Show history", true); //user-option, must be declared true for 1.3.1 / MS JVM historyCheckbox.addItemListener(this); historyTextArea = new TextArea(3, 20); historyTextArea.setEditable(false); historyPanel.add("North", historyCheckbox); if (historyCheckbox.getState()) { historyPanel.add("Center", historyTextArea); } //construct usercue stuff usercueTextArea = new TextArea(usercue, 2, 50, TextArea.SCROLLBARS_NONE); usercueTextArea.setEditable(false); usercueTextArea.setBackground(usercueColor); //peek stuff peekTextField= new TextField(40); //add panels to applet in desired flow layout order add(usercueTextArea); add(wordPanel); add(buttonPanel); add(infoPanel); add(historyPanel); if (peekFlag) { add(peekTextField); } //define applet properties setSize(appletWidth, appletHeight); } /****************** * */ public void updateAllDisplays() { // peekTextField.setText(wordToFind); if (wordToFind.startsWith("*")) //e.g."*RESET*" (* cannot be entered by user) { usercue = usercueSet; getNewWord(); } else if (entryMode==false) //i.e. game in progress { //re-calculate wordSoFar from array wordSoFar=" "; for (int i=0; i-1) { usercue = (isPhrase) ? usercueFailurePhrase : usercueFailureWord; } //i.e. not if suicide } else if (getWinStatus()) { setButtonTypeEnabled("Letter", false); setButtonTypeEnabled("Ans", false); setButtonTypeEnabled("Reset", true); usercue = usercueSuccess; } } wordTextField.setText((entryMode) ? wordToFind : wordSoFar); //wordTextField.setSize(wordTextField.getPreferredSize()); //adjusts for font width variances in 1.4.1 wordTextField.resize(wordTextField.getPreferredSize()); //wordPanel.setSize(wordPanel.getPreferredSize()); //as previous line wordPanel.resize(wordPanel.getPreferredSize()); //validate(); //recalculates applet layout, but not recognised in 1.3.1 this.doLayout(); livesTextField.setText((entryMode) ? "" : Integer.toString(livesRemaining)); notfoundTextField.setText((entryMode) ? "" : notfoundSoFar); historyTextArea.setText(historyString); //optional usercueTextArea.setText(usercue); //user guidance //set background color according to lives left int shade = 255 - (10 - livesRemaining)*colorDec; if (entryMode==false) { playColor = new Color(shade, shade, shade); setBackground(playColor); } repaint(); //update gibbet graphic } /****************** * */ public void setupNewWord() //setup all stuff dependent on the new word { livesRemaining = 10; // chosenSoFar = ""; //debugging only notfoundSoFar = ""; nothingToGuess = true; char c; //set all charFound flags to false unless '/' or '-' divides words and get single letters for (int count=0; count< wordToFind.length() ; count++) { c = wordToFind.charAt(count); nothingToGuess = ( (c >= 'A') && (c <= 'Z') ) ? false : nothingToGuess; charFound[count] = (c == '/') ? true : false; charFound[count] = (c == '-') ? true : charFound[count]; singleLetters[count] = wordToFind.substring(count, count+1); } //detect if phrase isPhrase = (wordToFind.indexOf("/")>-1); // peekTextField.setText( (isPhrase) ? "true" : "false"); // peekTextField.setText( (nothingToGuess) ? "true" : "false"); if (nothingToGuess) { wordToFind = "*NTG*"; } //trap nothing to guess (e.g. hyphens & spaces only) updateAllDisplays(); } /****************** * */ public void itemStateChanged(ItemEvent ie) { if (ie.getItem() == historyCheckbox.getLabel()) //should be just == historyCheckbox??? but this doesn't work! { if (historyCheckbox.getState()==false) { // historyTextArea.setText("off"); historyPanel.remove(historyTextArea); } else { // historyTextArea.setText("on"); historyPanel.add("Center", historyTextArea); } updateAllDisplays(); } } /****************** * */ public void actionPerformed(ActionEvent e) { buttonClicked(e.getActionCommand()); } /****************** * */ public void buttonClicked(String s) { if (s.length() == 1) // its a single letter { if (entryMode==true) // if entering new word... { wordToFind+= (wordToFind.length() 0) { killLetterButton(s); //disable for further clicks chosenSoFar += s + " "; // add chosen letter to string (optional) int found = wordToFind.indexOf(s); //test is it in the word? if (found == -1) //if not in word { notfoundSoFar += s + " "; //add to notfound string livesRemaining --; //decrement lives remaining } else //if found in word, set charFound flag(s) { for (int count=0; count0) ) //backspace only enabled in entryMode { wordToFind= wordToFind.substring(0, wordToFind.length()-1); } else if (s.equals("Enter")) //button only enabled in entryMode { if(wordToFind.trim().length()>0) //don't accept null { entryMode = false; setButtonTypeEnabled("Ans", true); setButtonTypeEnabled("Reset", false); setButtonTypeEnabled("Space", false); setButtonTypeEnabled("Dash", false); setButtonTypeEnabled("<<<", false); setButtonTypeEnabled("Enter", false); //wordToFind = wordToFind.trim().replaceAll(" ", "/"); //not recognised in 1.3.1 wordToFind = wordToFind.trim().replace(' ', '/'); //deal with spaces wordLabel.setText("Word to find:"); setupNewWord(); // peekTextField.setText( (isPhrase) ? "true" : "false"); if ( (wordToFind.length()>0) && (wordToFind.charAt(0)!='*') ) { usercue = (isPhrase) ? usercueFindPhrase : usercueFindWord; } else usercue = usercueSet; } else wordToFind = "*NULL ENTRY*"; //re-trigger reset } updateAllDisplays(); //in every case!! } public void paint(Graphics g) { g.translate(xOS, yOS); //positions scaffold if (entryMode) //inputting new word { drawScenery(g, enterColor); } else if (getWinStatus()) //game won { drawScenery(g, winColor); drawHead(g); drawBody(g); drawRightArmUp(g); drawLeftArmUp(g); drawRightLeg(g); drawLeftLeg(g); g.drawString(joyWord, 2*gScale, 6*gScale); } else if (livesRemaining==0) //game lost { drawScenery(g, deathColor); drawUpright(g); drawCrossbar(g); drawHoistedMan(g); } else //game in progress { drawScenery(g, playColor); switch (livesRemaining) { case 1 : drawRope(g); //break statements not appropriate (accumulative draws) case 2 : drawCrossbar(g); case 3 : drawUpright(g); case 4 : drawLeftArmDown(g); case 5 : drawRightArmDown(g); case 6 : drawLeftLeg(g); case 7 : drawRightLeg(g); case 8 : drawBody(g); case 9 : drawHead(g); } } } /****************** * */ public void drawScenery(Graphics g, Color c) // c sets applet background colour { this.setBackground(c); g.setColor(Color.black); //sets colour ready for rest of drawing // g.drawLine(0*gScale, 14*gScale, 9*gScale, 14*gScale); //ground } public void drawHead(Graphics g) { g.drawOval(5*gScale, 7*gScale, 2*gScale, 2*gScale); } public void drawBody(Graphics g) { g.drawLine(6*gScale, 9*gScale, 6*gScale, 11*gScale); } public void drawRightLeg(Graphics g) { g.drawLine(6*gScale, 11*gScale, 5*gScale, 14*gScale); } public void drawLeftLeg(Graphics g) { g.drawLine(6*gScale, 11*gScale, 7*gScale, 14*gScale); } public void drawRightArmDown(Graphics g) { g.drawLine(6*gScale, 10*gScale, 4*gScale, 12*gScale); } public void drawRightArmUp(Graphics g) { g.drawLine(6*gScale, 10*gScale, 4*gScale, 9*gScale); } public void drawLeftArmDown(Graphics g) { g.drawLine(6*gScale, 10*gScale, 8*gScale, 12*gScale); } public void drawLeftArmUp(Graphics g) { g.drawLine(6*gScale, 10*gScale, 8*gScale, 9*gScale); } public void drawUpright(Graphics g) { g.fillRect(1*gScale, 2*gScale, 1*gScale, 12*gScale); g.drawLine(2*gScale, 4*gScale, 4*gScale, 2*gScale); } public void drawCrossbar(Graphics g) { g.fillRect(1*gScale, 1*gScale, 6*gScale, 1*gScale); } public void drawRope(Graphics g) { g.drawLine(6*gScale, 2*gScale, 6*gScale, 7*gScale); g.drawString(doomWord, 2*gScale, 7*gScale); } public void drawHoistedMan(Graphics g) { g.drawLine(6*gScale, 2*gScale, 6*gScale, 6*gScale); // rope g.setColor(Color.blue); g.drawOval(4*gScale, 5*gScale, 2*gScale, 2*gScale); // head g.drawLine(6*gScale, 6*gScale, 6*gScale, 8*gScale); // body g.drawLine(6*gScale, 8*gScale, 5*gScale+6, 11*gScale); // right leg g.drawLine(6*gScale, 8*gScale, 7*gScale-6, 11*gScale); // left leg g.drawLine(6*gScale, 7*gScale, 5*gScale+6, 9*gScale); // right arm g.drawLine(6*gScale, 7*gScale, 7*gScale-6, 9*gScale); // left arm } /****************** * */ public boolean getWinStatus() { //returns true if game won return ( (wordSoFar.indexOf("_") == -1) && (livesRemaining>0) ); } /****************** * */ public void getNewWord() { entryMode=true; //set flag for new word input in buttonClicked() setButtonTypeEnabled("Letter", true); setButtonTypeEnabled("Ans", false); setButtonTypeEnabled("Reset", false); setButtonTypeEnabled("Space", true); setButtonTypeEnabled("Dash", true); setButtonTypeEnabled("<<<", true); setButtonTypeEnabled("Enter", true); wordLabel.setText("New word:"); //show hint wordToFind=""; //reset word } /****************** * */ public void setButtonTypeEnabled(String type, boolean state) { Component c; if (type.equals("Letter")) { for (int i=0; i<26; i++) { c = buttonPanel.getComponent(i); c.setEnabled(state); c.setBackground( (state) ? enabledColor : disabledColor ); } } else { Button b = anyButton; if (type.equals("Ans")) { b = answerButton; } if (type.equals("Reset")) { b = resetButton; } if (type.equals("Space")) { b = spaceButton; } if (type.equals("Dash")) { b = hyphenButton; } if (type.equals("<<<")) { b = backspaceButton; } if (type.equals("Enter")) { b = enterButton; } b.setEnabled(state); b.setBackground((state) ? enabledColor : disabledColor ); } } /****************** * */ public void killLetterButton(String s) { Component c; int index; index = s.compareTo("A"); c = buttonPanel.getComponent(index); c.setEnabled(false); c.setBackground(disabledColor); } }