This document discusses refactoring a Hangman game code to support inheritance. It describes abstracting the mapping of characters to positions in an array into a virtual function. This allows creating subclasses for different character sets that only differ in their implementation of the letterToStoragePosition function. The Hangman code is updated to use the new function instead of explicit character mappings, making it easier to extend to new character sets by subclassing.
2. Hangman Code
0 1 2 3 4 5 6 19 20 21 22 23 24 25
‘a’‘b’‘c’‘d’‘e’‘f’‘g’ ‘t’‘u’‘v’ ‘w’‘x’‘y’‘z’
true or false
letterGuessed[]
n The letterGuessed[] array is used to keep track of which letters
have been guessed so far.
n We only consider the 26 lowercase letters of the alphabet. All
other characters are considered invalid – i.e. not part of the
game.
n So each element of letterGuessed[] contains true or false,
depending on whether the corresponding character has been
guessed by the user or not.
3. Hangman Code
0 1 2 3 4 5 6 19 20 21 22 23 24 25
‘a’‘b’‘c’‘d’‘e’‘f’‘g’ ‘t’‘u’‘v’ ‘w’‘x’‘y’‘z’
true or false
letterGuessed[]
n There is a correspondence between a letter and a position in the
array.
0 -> ‘a’
1 -> ‘b’
25 -> ‘z’
4. Hangman Code
0 1 2 3 4 5 6 19 20 21 22 23 24 25
‘a’‘b’‘c’‘d’‘e’‘f’‘g’ ‘t’‘u’‘v’ ‘w’‘x’‘y’‘z’
true or false
letterGuessed[]
n There is an easy way to work out the position, given the
character:
given a lowercase character c, its position in letterGuessed[] is
c – ‘a’
so, e.g. if c = ‘e’, then its position is ‘e’ – ‘a’ = 4
5. Hangman Code
n Now suppose I wanted to play the Hangman game, but I wanted
my opponent to guess my computer password, which is allowed
to contain any sequence of lowercase or uppercase characters or
any number ‘0’, ‘1’, .., ‘9’
n The only change I need to make to my Hangman game is to
extend the range of valid characters.
0 1 24 25
‘a’‘b’ ‘y’‘z’
true or false
letterGuessed[]
‘A’‘B’ ‘Y’‘Z’‘0’‘1’ ‘8’‘9’
26 27 50 51 52 53 54 55
n Now we have a more complicated mapping of character to a
position in the letterGuessed[] array.
n But, otherwise my Hangman game for passwords is the same as
the simple Hangman game.
6. Hangman Inheritance
n Inheritance allows us to re-use code for the two
versions of the game.
n Create two sub-classes of an abstract class called
Hangman. Hangman
SimpleHangman PassHangman
n SimpleHangman and PassHangman only differ in the
set of valid characters that they allow
7. Prepare Hangman code for Extension
n Unfortunately, I was not careful to abstract the
operation of mapping a character to a particular
position in the letterGuessed[] array.
n This mapping is carried out explicitly at several points
of the existing code.
8. n Here, I explicitly chose to store the secret word as lowercase
9. n When I checked if a letter is valid, I checked that the
range of characters only included alphabetic
characters
10. n In order to add a new guess into the array, I modified
the character to make it lowercase and find its
position in the array.
11. n When checking if a letter was used, I again explicitly
computed the mapping from character to position in
the lettersGuessed[] array.
12. n A good abstraction would have identified a function
that given a character, maps it to its position in the
array, and returns that position (or -1 if the character
is invalid)
n That function could then be used whenever we need
to consult the letterGuessed[] array.
13.
14.
15. Hangman with Inheritance
n Now the two classes can be identical except for the
way that they implement the function
letterToStoragePosition()
n Changes to the code:
n Change the private fields of Hangman to protected
n Introduce a new method called letterToStoragePosition
which can also have protected access (since external
code does not directly access it).
n Specific that this function must be implemented by
derived classes:
virtual int letterToStoragePosition(char c) const = 0;
n Create two derived classes and implement the function
for each class.
n Note that each function must have its own constructor
too.