Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions Nicks-Game/controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require_relative 'view'
require_relative 'model'

class GameController
include GameView

def run!
hangman = Hangman.new

Print::run_spinner
Print::title_screen

loop do
Print::menu
case Print::fetch_user_input
when "P"
hangman.reset
Print::play(hangman.play)
loop do
hangman.guess(Print::fetch_user_input)
if hangman.done
Print::finish(hangman.word)
break
else
Print::play(hangman.play)
end
end
when "Q"
puts "We're done"
exit
else
Print::error_message
end
end
end
end

GameController.new.run!
50 changes: 50 additions & 0 deletions Nicks-Game/model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
class Hangman
attr_reader :word, :guessed, :tries, :maxtries

def initialize
@word = File.readlines('words.txt').sample.strip.upcase
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only ever use @word.chars. Might as well append a .chars and rename this @word_chars.

The Law of Demeter is more of a suggestion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

word is referred to by the controller for the finish method. Should I handle that some other way?

@guessed = []
@tries = 0
@maxtries = 10
end

# apply a user's guessed character
def guess char
@guessed.push(char.upcase)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the guessed character from the target word might simplify things. Wanna give it a try?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried but only came up with something rather convoluted. I'm not seeing how to ditch @guessed while still tracking the game's state (i.e. show the user how many characters, in which positions, of the word they've guessed).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was looking at this class in isolation and didn't consider the interaction with the controller. Sorry about that. I'll give it another review soon.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The goal of my recommendation was to simplify the guessmatch method. I still think it might be worth the trouble of another instance variable to simplify that method.

Wanna try adding these two lines and see how simple guessmatch could become?

In initialize: @letters_left = @word
In guess: @letters_left.delete! char

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I see what you're after. guessmatch is just a call to empty? now.

@tries += 1
end

# is the game over?
def done
if @tries >= @maxtries
true
elsif guessmatch
true
else
false
end
end

# do the user's combined guesses reveal the secret word?
def guessmatch
@word.chars.all? { |letter| @guessed.include?(letter) }
end

# start a new game
def reset
initialize
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think I've ever done this before. I like the use case.

end

# sends hash of gamestate (string, tries) through controller to view
def play
playString = ''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lower snakecase is the common convention.

@word.chars.each do |letter|
if guessed.include?(letter)
playString += letter + ' '
else
playString += '_ '
end
end
{ playString: playString, tries: @maxtries - @tries }
end
end
57 changes: 57 additions & 0 deletions Nicks-Game/view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module GameView

module Print

class << self
def run_spinner
print "Loading (please wait) "
5.times { print "."; sleep 0.5; }
print "\n"
end

def error_message
puts "That's not a command key. Try again!"
end

def title_screen
title = <<TITLE

********** || **********
* Hangman *
********** || **********

TITLE
puts title
end

def menu
menu = <<EOS

***** Welcome *****
- (P)lay
- (Q)uit
***** *****

EOS
puts menu
end

def play(gamestate)
puts "Guess a letter (#{gamestate[:tries]} tries remaining) (ctrl-c to quit):"
puts gamestate[:playString]
end

def finish(word)
puts "The word was #{word}!"
puts "Thanks for playing!"
Print::run_spinner
end

def fetch_user_input(question=nil)
puts question if question
print "> "
gets.chomp
end
end
end
end
8 changes: 8 additions & 0 deletions Nicks-Game/words.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cats
dogs
moose
geese
horses
elephants
tarsiers
armadillos