hangman-cli 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'gallows'
4
+
5
+ # Module to display all in game text.
6
+ module Display
7
+ def self.welcome_message
8
+ puts "Welcome to Hangman.\n\n"
9
+ end
10
+
11
+ def self.instruction_intro
12
+ puts "If you'd like instructions enter 'i'."
13
+ puts 'Otherwise press return to continue.'
14
+ end
15
+
16
+ def self.instructions
17
+ puts <<-MSG
18
+ Reveal the hidden word before your man is hung.
19
+
20
+ You may guess a single letter at a time.
21
+ A correct guess will result in that letter being filled in.
22
+ Incorrect guesses will result in a part of the stick man being drawn.
23
+ You have 6 incorrect guesses to play with to save your man.
24
+ You may also guess the whole word at any time. But be careful; an incorrect guess is game over.
25
+
26
+ The game is auto saved after each round.
27
+ Use the load function at game start to load a previously saved game.
28
+ Enter 'quit game' at any time to end session.
29
+
30
+ MSG
31
+ end
32
+
33
+ def self.enter_name
34
+ puts 'Enter your name: '
35
+ end
36
+
37
+ def self.play_again
38
+ puts "Would you like to play again? Enter 'yes' or 'no': "
39
+ end
40
+
41
+ def self.leave
42
+ puts 'Okay, bye.'
43
+ end
44
+
45
+ def self.validation_errors(errors)
46
+ puts errors.join(', ') unless errors.empty?
47
+ end
48
+
49
+ def self.thank_player(player)
50
+ puts "Thanks #{player.name}"
51
+ end
52
+
53
+ def self.word_to_guess(guess_logic)
54
+ puts " Word to guess: #{guess_logic.guessed_word}"
55
+ end
56
+
57
+ def self.gallows(guess_logic)
58
+ puts Gallows::GALLOWS[guess_logic.incorrect_guesses]
59
+ end
60
+
61
+ def self.beginning_of_guess_round(guess_logic)
62
+ puts <<~MSG
63
+ #{gallows(guess_logic)}
64
+ #{word_to_guess(guess_logic)}
65
+ Wrong letters: #{guess_logic.incorrect_letters.join(', ')}
66
+ Incorrect guesses: #{guess_logic.incorrect_guesses}\n\n
67
+ Make your guess:
68
+ MSG
69
+ end
70
+
71
+ def self.end_of_guess_round(guess_logic)
72
+ puts guess_logic.messages.pop.to_s
73
+ end
74
+
75
+ def self.victory(word_to_guess)
76
+ puts "\n Yes! The word was #{word_to_guess.word.upcase}."
77
+ puts "\n You win!\n\n"
78
+ end
79
+
80
+ def self.defeat(word_to_guess)
81
+ puts Gallows.finish
82
+ puts "\n Sorry, you lose!"
83
+ puts "\n The word was #{word_to_guess.word.upcase}\n\n"
84
+ end
85
+
86
+ def self.load_game
87
+ puts "Enter 'load' to load previously saved game."
88
+ puts 'Or press return to start a new game.'
89
+ end
90
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Module to hold Gallow graphics
4
+ module Gallows
5
+ def self.start
6
+ <<-GALLOWS
7
+ ===========
8
+ |/ |
9
+ |
10
+ |
11
+ |
12
+ |\\
13
+ ============
14
+ GALLOWS
15
+ end
16
+
17
+ def self.head
18
+ <<-GALLOWS
19
+ ===========
20
+ |/ |
21
+ | O
22
+ |
23
+ |
24
+ |\\
25
+ ============
26
+ GALLOWS
27
+ end
28
+
29
+ def self.body
30
+ <<-GALLOWS
31
+ ===========
32
+ |/ |
33
+ | O
34
+ | |
35
+ |
36
+ |\\
37
+ ============
38
+ GALLOWS
39
+ end
40
+
41
+ def self.right_arm
42
+ <<-GALLOWS
43
+ ===========
44
+ |/ |
45
+ | O
46
+ | /|
47
+ |
48
+ |\\
49
+ ============
50
+ GALLOWS
51
+ end
52
+
53
+ def self.left_arm
54
+ <<-GALLOWS
55
+ ===========
56
+ |/ |
57
+ | O
58
+ | /|\\
59
+ |
60
+ |\\
61
+ ============
62
+ GALLOWS
63
+ end
64
+
65
+ def self.right_leg
66
+ <<-GALLOWS
67
+ ===========
68
+ |/ |
69
+ | O
70
+ | /|\\
71
+ | /
72
+ |\\
73
+ ============
74
+ GALLOWS
75
+ end
76
+
77
+ def self.finish
78
+ <<-GALLOWS
79
+ ===========
80
+ |/ |
81
+ | O
82
+ | /|\\
83
+ | / \\
84
+ |\\
85
+ ============
86
+ GALLOWS
87
+ end
88
+
89
+ GALLOWS = { 0 => start,
90
+ 1 => head,
91
+ 2 => body,
92
+ 3 => right_arm,
93
+ 4 => left_arm,
94
+ 5 => right_leg,
95
+ 6 => finish }
96
+ .freeze
97
+ end
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'player'
4
+ require_relative 'dictionary'
5
+ require_relative 'word_to_guess'
6
+ require_relative 'gallows'
7
+ require_relative 'guess_logic'
8
+ require_relative 'guess'
9
+ require_relative 'display'
10
+ require_relative 'player_name'
11
+ require_relative 'game_save'
12
+ require_relative 'answer'
13
+ require 'yaml'
14
+
15
+ # Class to hold all main game elements and behaviour
16
+ class Game
17
+ attr_accessor :player, :word_to_guess, :guess_logic
18
+
19
+ def initialize
20
+ @player = nil
21
+ @word_to_guess = word
22
+ @guess_logic = GuessLogic.new(word_to_guess)
23
+ end
24
+
25
+ def start
26
+ welcome
27
+ load_game
28
+ instructions
29
+ player_setup
30
+ main_game_loop
31
+ end
32
+
33
+ def main_game_loop
34
+ loop do
35
+ Gallows::GALLOWS[guess_logic.incorrect_guesses]
36
+ # puts word_to_guess.word TESTING
37
+ guess
38
+ victory if win?
39
+ defeat if game_over?
40
+ GameSave.save(self)
41
+ end
42
+ end
43
+
44
+ def player_setup
45
+ loop do
46
+ Display.enter_name
47
+ player_name = PlayerName.new($stdin.gets)
48
+ Display.validation_errors(player_name.errors)
49
+ redo unless player_name.valid?
50
+ self.player = Player.new(player_name.answer)
51
+ Display.thank_player(player)
52
+ break
53
+ end
54
+ end
55
+
56
+ def guess
57
+ loop do
58
+ Display.beginning_of_guess_round(guess_logic)
59
+ guess = Guess.new($stdin.gets, word_to_guess)
60
+ Display.validation_errors(guess.errors)
61
+ redo unless guess.valid?
62
+ full_word_check(guess) if guess_logic.full_word_guess?(guess)
63
+ guess_logic.compare(guess)
64
+ Display.end_of_guess_round(guess_logic)
65
+ break
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def welcome
72
+ Display.welcome_message
73
+ end
74
+
75
+ def instructions
76
+ Display.instruction_intro
77
+ response = Answer.new($stdin.gets)
78
+ Display.instructions if response.answer == 'i'
79
+ end
80
+
81
+ def load_game
82
+ Display.load_game
83
+ response = Answer.new($stdin.gets)
84
+ begin
85
+ GameSave.load.main_game_loop if response.answer == 'load'
86
+ rescue StandardError
87
+ puts 'No current save game.'
88
+ end
89
+ end
90
+
91
+ def full_word_check(guess)
92
+ if guess_logic.correct_word?(guess)
93
+ victory
94
+ else
95
+ defeat
96
+ end
97
+ end
98
+
99
+ def word
100
+ dictionary = Dictionary.new('words.txt')
101
+ WordToGuess.new(dictionary.word)
102
+ end
103
+
104
+ def game_over?
105
+ guess_logic.incorrect_guesses > 5
106
+ end
107
+
108
+ def win?
109
+ guess_logic.guessed_word == word_to_guess.word
110
+ end
111
+
112
+ def victory
113
+ Display.victory(word_to_guess)
114
+ reload
115
+ end
116
+
117
+ def defeat
118
+ Display.defeat(word_to_guess)
119
+ reload
120
+ end
121
+
122
+ def reload
123
+ Display.play_again
124
+ answer = $stdin.gets.chomp.downcase
125
+ if answer == 'yes'
126
+ Game.new.main_game_loop
127
+ else
128
+ Display.leave
129
+ exit
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'fileutils'
5
+
6
+ # Class to save and load game
7
+ class GameSave
8
+ def self.save(game)
9
+ game_data = YAML.dump(game)
10
+ save_file = File.join(File.dirname(__FILE__), '../lib/save_games/savegame.txt')
11
+ dirname = File.dirname(save_file)
12
+
13
+ FileUtils.mkdir(dirname) unless File.directory?(dirname)
14
+
15
+ File.open(save_file, 'w') do |f|
16
+ f.write game_data
17
+ end
18
+ end
19
+
20
+ def self.load
21
+ save_file = File.join(File.dirname(__FILE__), '../lib/save_games/savegame.txt')
22
+
23
+ return nil unless File.exist?(save_file)
24
+
25
+ game_data = File.open(save_file, 'r', &:read)
26
+ YAML.load(game_data)
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'answer'
4
+
5
+ # Class to model answers that are guesses
6
+ class Guess < Answer
7
+ attr_reader :word_to_guess
8
+ attr_accessor :errors
9
+
10
+ def initialize(answer, word_to_guess)
11
+ super(answer)
12
+ @word_to_guess = word_to_guess.word
13
+ valid?
14
+ end
15
+
16
+ def valid?
17
+ self.errors = []
18
+ errors << 'Must be a letter' unless letter?
19
+ errors << 'Must be a single letter or guessing the full word' unless single_letter? || full_word_guess?
20
+ errors.empty?
21
+ end
22
+
23
+ private
24
+
25
+ def letter?
26
+ answer.match?(/[a-z]/)
27
+ end
28
+
29
+ def single_letter?
30
+ answer.size == 1
31
+ end
32
+
33
+ def full_word_guess?
34
+ answer.size == word_to_guess.size
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class for processing guesses
4
+ class GuessLogic
5
+ attr_reader :word_to_guess, :guessed_letters
6
+ attr_accessor :incorrect_guesses, :incorrect_letters,
7
+ :messages
8
+
9
+ def initialize(word_to_guess)
10
+ @word_to_guess = word_to_guess.word
11
+ @guessed_letters = []
12
+ @incorrect_letters = []
13
+ @incorrect_guesses = 0
14
+ @messages = []
15
+ end
16
+
17
+ def guessed_word
18
+ word_to_guess.chars.map { |char| guessed_letters.include?(char) ? char : '-' }.join
19
+ end
20
+
21
+ def compare(guess)
22
+ if correct_guess?(guess)
23
+ add_letters(guessed_letters, guess)
24
+ messages << "\n That's Correct!"
25
+ else
26
+ add_letters(incorrect_letters, guess)
27
+ self.incorrect_guesses += 1
28
+ messages << "\n Sorry, that's incorrect."
29
+ end
30
+ end
31
+
32
+ def full_word_guess?(guess)
33
+ word_to_guess.length == guess.answer.length
34
+ end
35
+
36
+ def correct_word?(guess)
37
+ word_to_guess == guess.answer
38
+ end
39
+
40
+ private
41
+
42
+ def correct_guess?(guess)
43
+ word_to_guess.include?(guess.answer)
44
+ end
45
+
46
+ def add_letters(collection, guess)
47
+ collection << guess.answer
48
+ end
49
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+ require_relative 'game'
6
+
7
+ Game.new.start
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Class to model a player
4
+ class Player
5
+ attr_reader :name
6
+
7
+ def initialize(name = 'anonymous')
8
+ @name = name.capitalize
9
+ end
10
+ end