Help with a hangman hangman game

Hello,

I’m trying to make a hangman game, but I’m new to processing and a bit unsure on how to make it work.
I would like to letters the array of words aren’t shown or something but when you press them it appears. I’ve heard of char but have no idea about how that works.
I should maybe as well use keyPressed instead of jOption as well but I’ve no idea either.

`If anyone have any tips/or explains how I should do to make these work, please let me know.
Thx in beforehand. :slight_smile:

My code until yet:

`import javax.swing.JOptionPane;
//int [] bokstäver={a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,z,;
String [] word= {"telephone","bull","London","Wales","moon","couch"};
int worde = int(random(word.length));
String str=JOptionPane.showInputDialog("Show a letter");
String str1="bull";


PFont font;
void setup() {
  size(400, 400);
  background(255,255,255);
  font=createFont("MicrosoftYaHeiUILight",15);
  fill(0);
  textFont(font);
  text("Guess a letter from the alfabeth",100,20);
  text("USed letter",100,300);
  text(word[worde],100,50);
  text(str,140,330);
  line(150,250,200,250);
  line(175,250,175,150);
  line(175,150,230,150);
  line(230,150,230,175);
  line(175,170,200,150);
 
 
}

void draw(int str,int word) {
 }
1 Like

Whoa nelly, slow down a bit. Before we start even thinking about a working game, let’s get some of the basic components working first.

First thing first, lets fix your setup() and draw() functions. These are important functions to Processing, and neither takes any parameters.

void setup(){
  size(400,400);
}

void draw(){
  background(0);
}

This is the most basic blank sketch. Try it! Does it work? Yes. Are there any errors? No. Do we understand its inner workings? Yes. These three properties are very important. If we maintain them as we write more code, our life will be much easier than if we just try to fix things at the end.

Next, we want a list of words to pick from. You already have such a list, so let’s put that list in, and let’s also copy over the code that picks a random word, and let’s just draw that random word. But since “pick a new random word and start a new game” is a common operation that we might want out hangman game do do more than once, let’s put the code that resets the game in its own function. And let’s also add a mousePressed() method to test resetting the game. Whew, that is a lot to add all at once…

String [] words = {"telephone","bull","London","Wales","moon","couch"};
int random_word_index;

void setup(){
  size(400,400);
  reset_game();
}

void reset_game(){
  random_word_index = int(random(words.length));
  // Other things to reset game here.
}

void draw(){
  background(0);
  text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
}

void mousePressed(){
  reset_game();
}

Try it! Does this still work? Are there any errors? Do you understand its inner workings?

Now we need to add some way to detect which letter the player has revealed. Since there are only two states a letter could be in - revealed or not revealed yet - we can use a boolean array to track which letters are revealed. The boolean array will need to be 26 booleans long - one for each letter.

When the game resets, all the booleans need to be set back to false, because after a game resets, no letters are revealed. We might also want to see the values in this array right now for debugging reasons… and to make sure it works. Thus:

String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
int random_word_index;
boolean[] is_letter_revealed = new boolean[26]; 

void setup() {
  size(400, 400);
  reset_game();
}

void reset_game() {
  random_word_index = int(random(words.length));
  for( int i = 0; i < is_letter_revealed.length; i++){
    is_letter_revealed[i] = false;
  }
  // Other things to reset game here.
}

void draw() {
  background(0);
  text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
  for( int i = 0; i < is_letter_revealed.length; i++){
    if( is_letter_revealed[i] ){
      text( char(int('A')+i), 10 * i, 40 );
    }
  }
}

void mousePressed() {
  reset_game();
}

void keyPressed(){
  int letter_index = -1;
  if( key >= 'a' && key <= 'z' ){
    letter_index = int(key - 'a');
  }
  if( key >= 'A' && key <= 'Z' ){
    letter_index = int(key - 'A');
  }
  if( letter_index != -1 ){
    is_letter_revealed[letter_index] = true;
    // Other things to do when a letter becomes revealed go here.
  }
}
3 Likes

Next, let’s work out the logic that determines if a letter in our random word should be visible. For letters that are revealed, we want to put that letter. For letters that are NOT revealed, we’ll put a _.

String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
int random_word_index;
boolean[] is_letter_revealed = new boolean[26]; 

void setup() {
  size(400, 400);
  reset_game();
}

void reset_game() {
  // Pick a new random word.
  random_word_index = int(random(words.length));
  // Reset all the revealed letters.
  for( int i = 0; i < is_letter_revealed.length; i++){
    is_letter_revealed[i] = false;
  }
  // Other things to reset game here.
}

void draw() {
  background(0);
  // Show the current random word.
  text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
  // Show the currently revealed letters.
  for( int i = 0; i < is_letter_revealed.length; i++){
    if( is_letter_revealed[i] ){
      text( char(int('A')+i), 10 * i, 40 );
    }
  }
  // Show the hidden word with revealed letters.
  for( int i = 0; i < words[random_word_index].length(); i++){
    int letter_value = int(words[random_word_index].charAt(i));
    // Deal with different cased letters in our hidden words.
    if( letter_value >= int('a') ){
      letter_value -= int('a');
    } else {
      letter_value -= int('A');
    }
    // Draw this letter or a blank space.
    if( is_letter_revealed[letter_value] ){
      text( char(int('A')+letter_value), 10 * i, 60 );
    } else {
      text( '_', 10 * i, 60 );
    }
  }
}

void mousePressed() {
  reset_game();
}

void keyPressed(){
  int letter_index = -1;
  // Detect lowercase letters.
  if( key >= 'a' && key <= 'z' ){
    letter_index = int(key - 'a');
  }
  // Detect uppercase letters.
  if( key >= 'A' && key <= 'Z' ){
    letter_index = int(key - 'A');
  }
  // If a letter was detected, deal with it.
  if( letter_index != -1 ){
    is_letter_revealed[letter_index] = true;
    // Other things to do when a letter becomes revealed go here.
  }
}

That is a good chunk of code that just got added. Make sure you’re following along and understand it! We loop over each index in the random word. For each index, we get the integer value of the character at that position. Then we conver that letter value to an index in our is_letter_revealed array. If the letter is revealed, we draw the letter. If not, we draw a blank. Test it yourself! When I wrote it, I had a number of fun bugs to deal with…

2 Likes

Next, we need a variable to track how many mistakes the player has made in their letter selection. This will be useful later when we go to draw the hangman.

I’m calling it the deathometer.

// A list of random words that could be used.
String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
// Which random word we are currently using.
int random_word_index;
// An array that tracks which letters are revealed.
boolean[] is_letter_revealed = new boolean[26];
// A counter that tracks how dead the hanging man is.
int deathometer;

void setup() {
  size(400, 400);
  reset_game();
}

void reset_game() {
  // Pick a new random word.
  random_word_index = int(random(words.length));
  // Reset all the revealed letters.
  for( int i = 0; i < is_letter_revealed.length; i++){
    is_letter_revealed[i] = false;
  }
  deathometer = 0;
  // Other things to reset game here.
}

void draw() {
  background(0);
  // Show the current random word.
  text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
  // Show the currently revealed letters.
  for( int i = 0; i < is_letter_revealed.length; i++){
    if( is_letter_revealed[i] ){
      text( char(int('A')+i), 10 * i, 40 );
    }
  }
  // Show the hidden word with revealed letters.
  for( int i = 0; i < words[random_word_index].length(); i++){
    int letter_value = int(words[random_word_index].charAt(i));
    // Deal with different cased letters in our hidden words.
    if( letter_value >= int('a') ){
      letter_value -= int('a');
    } else {
      letter_value -= int('A');
    }
    // Draw this letter or a blank space.
    if( is_letter_revealed[letter_value] ){
      text( char(int('A')+letter_value), 20 + 10 * i, 60 );
    } else {
      text( '_', 20 + 10 * i, 60 );
    }
  }
  // Display the deathometer counter.
  text( "Deathometer: " + deathometer, 20, 80 );
}

void mousePressed() {
  reset_game();
}

void keyPressed(){
  int letter_index = -1;
  // Detect lowercase letters.
  if( key >= 'a' && key <= 'z' ){
    letter_index = int(key - 'a');
  }
  // Detect uppercase letters.
  if( key >= 'A' && key <= 'Z' ){
    letter_index = int(key - 'A');
  }
  // If a letter was detected, deal with it.
  if( letter_index != -1 ){
    // If this letter was already revealed, the player is dumb for picking the same letter again.
    if( is_letter_revealed[letter_index] ){
      // Punish player.
      deathometer++;
      return; // Nothing else to do about it!
    }
    is_letter_revealed[letter_index] = true;
    // Was that letter in the hidden word? If not, deathometer increases!
    if( !word_has_letter( letter_index ) ){
      // Punish player.
      deathometer++;
    }
    // Other things to do when a letter becomes revealed go here.
  }
}

// Does the hidden word contain that letter?
boolean word_has_letter( int to_find ){
  for( int i = 0; i < words[random_word_index].length(); i++){
    int letter_value = int(words[random_word_index].charAt(i));
    if( letter_value >= int('a') ){
      letter_value -= int('a');
    } else {
      letter_value -= int('A');
    }
    if( to_find == letter_value ){
      return( true ); // We found it!
    }
  }
  return( false ); // Not found in this word!
}

Again, this adds a lot of code. Notice that the deathometer is reset when the game_reset() function is called. Notice that it increases if the player picks the same letter more than once. Notice it increases if the player picks a letter that is not in the hidden word.


So… That’s the basics.

Time for a tea break.

We have a lot of logic going on now. Things are getting… complicated.

But we have the core functionality for our hangman game present.

Is there a way that we could take this core logic and just… get it out of the way somehow? Hmmm.

Well it turns out there is. What we can do is take the existing game logic and encapsulate it in its own class.

Hangman hm;

void setup() {
  size(400, 400);
  hm = new Hangman();
}

void draw() {
  background(0);
  hm.show_debug_info();
}

void mousePressed() {
  hm.reset_game();
}

void keyPressed() {
  hm.cope_with_letter(key);
}






///// ----- You could even put the rest of this in a different tab!

class Hangman {
  // A list of random words that could be used.
  String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
  // Which random word we are currently using.
  int random_word_index;
  // An array that tracks which letters are revealed.
  boolean[] is_letter_revealed = new boolean[26];
  // A counter that tracks how dead the hanging man is.
  int deathometer;

  Hangman() {
    reset_game();
  }

  void reset_game() {
    // Pick a new random word.
    random_word_index = int(random(words.length));
    // Reset all the revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      is_letter_revealed[i] = false;
    }
    // Reset the deathometer counter.
    deathometer = 0;
    // Other things to reset game here.
  }

  void show_debug_info() {
    //background(0);
    // Show the current random word.
    text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
    // Show the currently revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      if ( is_letter_revealed[i] ) {
        text( char(int('A')+i), 10 * i, 40 );
      }
    }
    // Show the hidden word with revealed letters.
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      // Deal with different cased letters in our hidden words.
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      // Draw this letter or a blank space.
      if ( is_letter_revealed[letter_value] ) {
        text( char(int('A')+letter_value), 20 + 10 * i, 60 );
      } else {
        text( '_', 20 + 10 * i, 60 );
      }
    }
    // Display the deathometer counter.
    text( "Deathometer: " + deathometer, 20, 80 );
  }

  //void mousePressed() {
  //  reset_game();
  //}

  void cope_with_letter(char in_key) {
    int letter_index = -1;
    // Detect lowercase letters.
    if ( in_key >= 'a' && in_key <= 'z' ) {
      letter_index = int(in_key - 'a');
    }
    // Detect uppercase letters.
    if ( in_key >= 'A' && in_key <= 'Z' ) {
      letter_index = int(in_key - 'A');
    }
    // If a letter was detected, deal with it.
    if ( letter_index != -1 ) {
      // If this letter was already revealed, the player is dumb for picking the same letter again.
      if ( is_letter_revealed[letter_index] ) {
        // Punish player.
        deathometer++;
        return; // Nothing else to do about it!
      }
      is_letter_revealed[letter_index] = true;
      // Was that letter in the hidden word? If not, deathometer increases!
      if ( !word_has_letter( letter_index ) ) {
        // Punish player.
        deathometer++;
      }
      // Other things to do when a letter becomes revealed go here.
    }
  }

  // Does the hidden word contain that letter?
  boolean word_has_letter( int to_find ) {
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      if ( to_find == letter_value ) {
        return( true ); // We found it!
      }
    }
    return( false ); // Not found in this word!
  }
  
  int get_damage(){
    return( deathometer );
  }
  
}

Look at how tidy that is!

2 Likes

Thank you so much! @TfGuy44 (y)
Very easy to follow :slight_smile:

With the core game logic done, we’re now free to make it pretty. We’re going to need a hanging man, so let’s make one of those. And we might actually want letter keys to press instead of using key presses. As a bonus, these can serve as indicators of which letters have already been used. So as a start, we’ve got this:

//Hangman hm;

void setup() {
  size(600, 400);
  //hm = new Hangman();
}

void draw() {
  background(0);
  //hm.show_debug_info();

  pushMatrix();
  translate(10, height-10);
  strokeWeight(4);
  stroke(255);
  line(0, 0, 80, 0);
  line(0, 0, 0, -380);
  line(60, 0, 0, -60);
  translate(0, -380);
  line(0, 0, 40, 0);
  line(40, 0, 40, 10);
  translate(40, 40);
  noFill();
  ellipse(0,0,60,60);
  translate(0,30);
  line(0,0,0,120);
  line(0,20,-30,120);
  line(0,20,30,120);
  line(0,120,-30,220);
  line(0,120,30,220);
  popMatrix();
  
  pushMatrix();
  translate(100,0);
  translate(10,10);
  strokeWeight(1);
  int t = 0;
  textAlign(CENTER);
  textSize(28);
  for( int j = 0; j < 3; j++){
    for( int i = 0; i < 9; i++ ){
      pushMatrix();
      translate(40 * i + (j==2?20:0), 40 * j);
      if( t < 26 ){
        rect(0, 0, 30, 30, 4);        
        text( char(int('A'+t++)), 15, 25);
      }
      popMatrix();
    }
  }
  popMatrix();
}

void mousePressed() {
  //hm.reset_game();
}

void keyPressed() {
  //hm.cope_with_letter(key);
}

Next let’s make the hanging man’s drawing conditional on a value. And let’s make our letter buttons be their own thing since they’re going to have a bit of logic behind them.

//Hangman hm;
Button[] alpha_buttons = new Button[26]; 

void setup() {
  size(600, 400);
  //hm = new Hangman();
  int t = 0;
  for ( int j = 0; j < 3; j++) {
    for ( int i = 0; i < 9; i++ ) {
      if ( t < 26 ) {
        alpha_buttons[t] = new Button(110 + 40 * i + (j==2?20:0), 280 + 40 * j, char(int('A'+t++)) );
      }
    }
  }
}

void draw() {
  background(0);
  //hm.show_debug_info();
  draw_man( int(map(mouseX, 0, width, 0, 14)) );
  for( int i = 0; i < 26; i++){
    alpha_buttons[i].draw();
  }
}

void mousePressed() {
  //hm.reset_game();
}

void keyPressed() {
  //hm.cope_with_letter(key);
}

void draw_man(int d) {
  pushMatrix();
  translate(10, height-10);
  strokeWeight(4);
  stroke(255);
  int dm = 0;
  if ( d > dm++ )
    line(0, 0, 80, 0);
  if ( d > dm++ )
    line(0, 0, 0, -380);
  if ( d > dm++ )
    line(60, 0, 0, -60);
  translate(0, -380);
  if ( d > dm++ )
    line(0, 0, 40, 0);
  if ( d > dm++ )
    line(40, 0, 40, 10);
  translate(40, 40);
  noFill();
  if ( d > dm++ )
    ellipse(0, 0, 60, 60);
  translate(0, 30);
  if ( d > dm++ )
    line(0, 0, 0, 120);
  if ( d > dm++ )
    line(0, 20, -30, 120);
  if ( d > dm++ )
    line(0, 20, 30, 120);
  if ( d > dm++ )
    line(0, 120, -30, 220);
  if ( d > dm++ )
    line(0, 120, 30, 220);
  popMatrix();
}

class Button {
  float x, y, w, h;
  char t;
  int index;
  Button( float ix, float iy, char it ) {
    x = ix;
    y = iy;
    w = 30;
    h = 30;
    t = it;
    index = int(t - 'A');
  }
  void draw() {
    textAlign(CENTER);
    textSize(28);
    stroke(255);
    strokeWeight(1);
    noFill();
    rect(x, y, w, h, 4);
    fill(255);
    text( t, x+15, y+25);
  }
}
1 Like

Now we tie everything back together.

Hangman hm;
Button[] alpha_buttons = new Button[26]; 

void setup() {
  size(600, 400);
  hm = new Hangman();
  int t = 0;
  for ( int j = 0; j < 3; j++) {
    for ( int i = 0; i < 9; i++ ) {
      if ( t < 26 ) {
        alpha_buttons[t] = new Button(110 + 40 * i + (j==2?20:0), 280 + 40 * j, char(int('A'+t++)) );
      }
    }
  }
}

void draw() {
  background(0);
  pushMatrix();
  translate(100,0);
  textSize(16);
  textAlign(CORNER);
  hm.show_debug_info();
  popMatrix();
  draw_man( hm.get_damage() ); //int(map(mouseX, 0, width, 0, 14)) );
  for( int i = 0; i < 26; i++){
    alpha_buttons[i].draw();
  }
}

void mousePressed() {
  for( int i = 0; i < 26; i++){
    alpha_buttons[i].on_click();
  }
}

void draw_man(int d) {
  pushMatrix();
  translate(10, height-10);
  strokeWeight(4);
  stroke(255);
  int dm = 0;
  if ( d > dm++ )
    line(0, 0, 80, 0);
  if ( d > dm++ )
    line(0, 0, 0, -380);
  if ( d > dm++ )
    line(60, 0, 0, -60);
  translate(0, -380);
  if ( d > dm++ )
    line(0, 0, 40, 0);
  if ( d > dm++ )
    line(40, 0, 40, 10);
  translate(40, 40);
  noFill();
  if ( d > dm++ )
    ellipse(0, 0, 60, 60);
  translate(0, 30);
  if ( d > dm++ )
    line(0, 0, 0, 120);
  if ( d > dm++ )
    line(0, 20, -30, 120);
  if ( d > dm++ )
    line(0, 20, 30, 120);
  if ( d > dm++ )
    line(0, 120, -30, 220);
  if ( d > dm++ )
    line(0, 120, 30, 220);
  popMatrix();
}

class Button {
  float x, y, w, h;
  char t;
  int index;
  Button( float ix, float iy, char it ) {
    x = ix;
    y = iy;
    w = 30;
    h = 30;
    t = it;
    index = int(t - 'A');
  }
  void draw() {
    textAlign(CENTER);
    textSize(28);
    stroke(255);
    strokeWeight(1);
    noFill();
    rect(x, y, w, h, 4);
    fill(255);
    text( t, x+15, y+25);
  }
  void on_click(){
    if( over() ){
      hm.cope_with_letter(t);
    }
  }
  boolean over(){
    return( x < mouseX && mouseX < x + w && y < mouseY && mouseY < y + h );
  }
}



///// ----- You could even put the rest of this in a different tab!

class Hangman {
  // A list of random words that could be used.
  String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
  // Which random word we are currently using.
  int random_word_index;
  // An array that tracks which letters are revealed.
  boolean[] is_letter_revealed = new boolean[26];
  // A counter that tracks how dead the hanging man is.
  int deathometer;

  Hangman() {
    reset_game();
  }

  void reset_game() {
    // Pick a new random word.
    random_word_index = int(random(words.length));
    // Reset all the revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      is_letter_revealed[i] = false;
    }
    // Reset the deathometer counter.
    deathometer = 0;
    // Other things to reset game here.
  }

  void show_debug_info() {
    //background(0);
    // Show the current random word.
    text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
    // Show the currently revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      if ( is_letter_revealed[i] ) {
        text( char(int('A')+i), 10 * i, 40 );
      }
    }
    // Show the hidden word with revealed letters.
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      // Deal with different cased letters in our hidden words.
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      // Draw this letter or a blank space.
      if ( is_letter_revealed[letter_value] ) {
        text( char(int('A')+letter_value), 20 + 10 * i, 60 );
      } else {
        text( '_', 20 + 10 * i, 60 );
      }
    }
    // Display the deathometer counter.
    text( "Deathometer: " + deathometer, 20, 80 );
  }

  //void mousePressed() {
  //  reset_game();
  //}

  void cope_with_letter(char in_key) {
    int letter_index = -1;
    // Detect lowercase letters.
    if ( in_key >= 'a' && in_key <= 'z' ) {
      letter_index = int(in_key - 'a');
    }
    // Detect uppercase letters.
    if ( in_key >= 'A' && in_key <= 'Z' ) {
      letter_index = int(in_key - 'A');
    }
    // If a letter was detected, deal with it.
    if ( letter_index != -1 ) {
      // If this letter was already revealed, the player is dumb for picking the same letter again.
      if ( is_letter_revealed[letter_index] ) {
        // Punish player.
        deathometer++;
        return; // Nothing else to do about it!
      }
      is_letter_revealed[letter_index] = true;
      // Was that letter in the hidden word? If not, deathometer increases!
      if ( !word_has_letter( letter_index ) ) {
        // Punish player.
        deathometer++;
      }
      // Other things to do when a letter becomes revealed go here.
    }
  }

  // Does the hidden word contain that letter?
  boolean word_has_letter( int to_find ) {
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      if ( to_find == letter_value ) {
        return( true ); // We found it!
      }
    }
    return( false ); // Not found in this word!
  }

  int get_damage() {
    return( deathometer );
  }
}

But alas, out tidy setup() and draw() functions are becoming a mess again!

Maybe the class Button is not enough. We can encapsulate the entire set of buttons into a single object too! Let’s take a moment now to tidy things up.

Hangman hangman;
Keyboard keyboard;

void setup() {
  size(600, 400);
  hangman = new Hangman();
  keyboard = new Keyboard();
}

void draw() {
  background(0);
  hangman.draw();
  keyboard.draw();
}

void mousePressed() {
  keyboard.click();
}









///// ----- LINE OF TIDY

void draw_man(int d) {
  pushMatrix();
  translate(10, height-10);
  strokeWeight(4);
  stroke(255);
  int dm = 0;
  if ( d > dm++ )
    line(0, 0, 80, 0);
  if ( d > dm++ )
    line(0, 0, 0, -380);
  if ( d > dm++ )
    line(60, 0, 0, -60);
  translate(0, -380);
  if ( d > dm++ )
    line(0, 0, 40, 0);
  if ( d > dm++ )
    line(40, 0, 40, 10);
  translate(40, 40);
  noFill();
  if ( d > dm++ )
    ellipse(0, 0, 60, 60);
  translate(0, 30);
  if ( d > dm++ )
    line(0, 0, 0, 120);
  if ( d > dm++ )
    line(0, 20, -30, 120);
  if ( d > dm++ )
    line(0, 20, 30, 120);
  if ( d > dm++ )
    line(0, 120, -30, 220);
  if ( d > dm++ )
    line(0, 120, 30, 220);
  popMatrix();
}

class Keyboard {
  Button[] alpha_buttons = new Button[26];
  Keyboard() {
    int t = 0;
    for ( int j = 0; j < 3; j++) {
      for ( int i = 0; i < 9; i++ ) {
        if ( t < 26 ) {
          alpha_buttons[t] = new Button(110 + 40 * i + (j==2?20:0), 280 + 40 * j, char(int('A'+t++)) );
        }
      }
    }
  }
  void draw() {
    for ( int i = 0; i < 26; i++) {
      alpha_buttons[i].draw();
    }
  }
  void click() {
    for ( int i = 0; i < 26; i++) {
      alpha_buttons[i].on_click();
    }
  }
}

class Button {
  float x, y, w, h;
  char t;
  int index;
  Button( float ix, float iy, char it ) {
    x = ix;
    y = iy;
    w = 30;
    h = 30;
    t = it;
    index = int(t - 'A');
  }
  void draw() {
    textAlign(CENTER);
    textSize(28);
    stroke(255);
    strokeWeight(1);
    noFill();
    rect(x, y, w, h, 4);
    fill(255);
    text( t, x+15, y+25);
  }
  void on_click() {
    if ( over() ) {
      hangman.cope_with_letter(t);
    }
  }
  boolean over() {
    return( x < mouseX && mouseX < x + w && y < mouseY && mouseY < y + h );
  }
}

class Hangman {
  // A list of random words that could be used.
  String [] words = {"telephone", "bull", "London", "Wales", "moon", "couch"};
  // Which random word we are currently using.
  int random_word_index;
  // An array that tracks which letters are revealed.
  boolean[] is_letter_revealed = new boolean[26];
  // A counter that tracks how dead the hanging man is.
  int deathometer;

  Hangman() {
    reset_game();
  }

  void reset_game() {
    // Pick a new random word.
    random_word_index = int(random(words.length));
    // Reset all the revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      is_letter_revealed[i] = false;
    }
    // Reset the deathometer counter.
    deathometer = 0;
    // Other things to reset game here.
  }

  void show_debug_info() {
    //background(0);
    // Show the current random word.
    text( "Our random word is: " + words[ random_word_index  ], 20, 20 );
    // Show the currently revealed letters.
    for ( int i = 0; i < is_letter_revealed.length; i++) {
      if ( is_letter_revealed[i] ) {
        text( char(int('A')+i), 10 * i, 40 );
      }
    }
    // Show the hidden word with revealed letters.
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      // Deal with different cased letters in our hidden words.
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      // Draw this letter or a blank space.
      if ( is_letter_revealed[letter_value] ) {
        text( char(int('A')+letter_value), 20 + 10 * i, 60 );
      } else {
        text( '_', 20 + 10 * i, 60 );
      }
    }
    // Display the deathometer counter.
    text( "Deathometer: " + deathometer, 20, 80 );
  }
  
  void draw(){
    draw_man( damage() );
    pushMatrix();
    translate(150, 50);
    textSize(32);
    // Show the hidden word with revealed letters.
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      // Deal with different cased letters in our hidden words.
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      // Draw this letter or a blank space.
      if ( is_letter_revealed[letter_value] ) {
        text( char(int('A')+letter_value), 20 + 30 * i, 60 );
      } else {
        text( '_', 20 + 30 * i, 60 );
      }
    }
    popMatrix();
  }

  //void mousePressed() {
  //  reset_game();
  //}

  void cope_with_letter(char in_key) {
    int letter_index = -1;
    // Detect lowercase letters.
    if ( in_key >= 'a' && in_key <= 'z' ) {
      letter_index = int(in_key - 'a');
    }
    // Detect uppercase letters.
    if ( in_key >= 'A' && in_key <= 'Z' ) {
      letter_index = int(in_key - 'A');
    }
    // If a letter was detected, deal with it.
    if ( letter_index != -1 ) {
      // If this letter was already revealed, the player is dumb for picking the same letter again.
      if ( is_letter_revealed[letter_index] ) {
        // Punish player.
        deathometer++;
        return; // Nothing else to do about it!
      }
      is_letter_revealed[letter_index] = true;
      // Was that letter in the hidden word? If not, deathometer increases!
      if ( !word_has_letter( letter_index ) ) {
        // Punish player.
        deathometer++;
      }
      // Other things to do when a letter becomes revealed go here.
    }
  }

  // Does the hidden word contain that letter?
  boolean word_has_letter( int to_find ) {
    for ( int i = 0; i < words[random_word_index].length(); i++) {
      int letter_value = int(words[random_word_index].charAt(i));
      if ( letter_value >= int('a') ) {
        letter_value -= int('a');
      } else {
        letter_value -= int('A');
      }
      if ( to_find == letter_value ) {
        return( true ); // We found it!
      }
    }
    return( false ); // Not found in this word!
  }

  int damage() {
    return( deathometer );
  }
}
1 Like