1
\$\begingroup\$

This was an assignment from "The Odin Project". This is my first program using JSON. I've been told I need work on structuring my classes, any advice will be appreciated!

https://github.com/jmooree30/Hangman/upload/master

require 'json'
load 'display.rb'
class Hangman
 attr_accessor :name
 @name = name
 def initialize
 puts "What is your name?"
 @name = gets.chomp
 puts "
################################################
 HANGMAN
################################################
 _________
 | 
 | |
 | O
 | /|\\
 | |
 | / \\
 |
 -----------------
Welcome #{@name} to Hangman. The computer will generate
a 5-12 letter random word. You will try to guess
that word one letter at a time. Try to solve the
puzzle before time runs out!
\n 
"
 end
end
class Gameplay
 attr_accessor :array, :filestuff, :random_word, :cipher, :random_word2, :counter
 def initialize
 @array = []
 @filestuff = File.foreach('5text.txt') do |x|
 chomped = x.chomp
 @array << chomped if (chomped.length >= 5 and chomped.length <= 12)
 end
 @random_word = @array.sample
 @cipher = @random_word.gsub(/[a-z]/, '*').split(//)
 @random_word2 = @random_word.split(//)
 @counter = 5
 puts "Would you like to load a saved game? Y/N"
 saved_game = gets.chomp
 if saved_game == "Y"
 game_file = File.read("saved.json")
 data = JSON.parse(game_file)
 @filestuff = data["filestuff"]
 @random_word = data["random_word"]
 @cipher = data["cipher"]
 @random_word2 = data["random_word2"]
 @counter = data["counter"]
 end
 puts @cipher.join
 puts "Enter a letter."
 def to_json
 JSON.generate({filestuff: @filestuff, random_word: @random_word, cipher: @cipher, random_word2: @random_word2})
 end
 def save_game(string) 
 File.open("saved.json", "w") do |game_file|
 game_file.write(string)
 end
 end
 def choice(n)
 @random_word2.each_with_index do |i,index|
 if i == n
 @cipher[index] = i 
 end 
 end 
 if n == @random_word2.join.to_s
 puts "You win"
 puts "would you like to start another game? Y/N"
 new_game = gets.chomp
 if new_game == "Y"
 Hangman.new
 else exit 
 end
 end
 if @random_word2.include?(n) == false
 @counter -= 1
 display
 puts "#{@counter} guesses remaining."
 end
 if @counter == 0
 puts "would you like to start another game? Y/N"
 new_game = gets.chomp
 if new_game == "Y"
 else exit 
 end
 end 
 if n == "1"
 save_game(to_json)
 end 
 puts @cipher.join
 puts "Want to save? Press 1 to save." 
 end
 @counter = 5
 while @counter > 0 
 choice(gets.chomp)
 end
 end 
end
Hangman.new
Gameplay.new
asked Aug 24, 2017 at 0:53
\$\endgroup\$
2
  • \$\begingroup\$ Do you have a link to the assignment? Are those classes & names required? \$\endgroup\$ Commented Aug 25, 2017 at 21:38
  • \$\begingroup\$ theodinproject.com/courses/ruby-programming/lessons/… <<link to assignment. I just realized I never implemented it to be case sensitive I will fix that later. The names and classes are not required. I feel my biggest weakness right now is how I go about structuring everything. \$\endgroup\$ Commented Aug 25, 2017 at 22:17

1 Answer 1

1
\$\begingroup\$

One of the ways to structure your objects is to describe your problem in a sentence or two, then turn the nouns into classes, and the verb phrases into methods.

In this case, you may end up with Hangman (the game), Player, and not really much else. You can choose to put the user interaction in Hangman or you can create a separate class for it, as you did with GamePlay.

There are a couple of things to keep in mind:

  • Make sure the interface makes sense. For example Hangman.new; GamePlay.new to start a game is a bit awkward. Whenever the interface is awkward it usually means there's a problem with the design. In this case, you have to manage two classes independently and you may have noticed that there's not much more you can do with your Hangman class as it is without managing it with logic external to either class.
  • Apply the right behavior to the right object. Assuming Hangman represents the game, then it should do all the game stuff: new (begin), save, load, guess, show_word, etc. Then GamePlay would just be user interaction, calling the Hangman game's methods as needed.

So let's think about the interface a bit: instead of

Hangman.new
Gameplay.new

perhaps you want something more like GamePlay.begin, or if you want to specify what game it is, maybe Hangman::GamePlay.begin which means you'd put the classes in an organizing module.

This exercise structures everything around a mental model. Then it's up to you to keep the model clean. Every time you need to add functionality, ask yourself: should this go into Hangman or GamePlay? Make sure that you have the separation of concerns clear.

In your case you have user prompts in two classes which is not a clean separation of concerns and may cause problems (e.g. GamePlay doesn't know the player's name).

Hopefully this makes sense. It tackles just the organizing step, let me know if you want assistance refactoring to a different model.

answered Aug 26, 2017 at 22:33
\$\endgroup\$
1
  • \$\begingroup\$ I'm currently waist deep in the next section trying to write a recursive merge sort. If I ever figure it out I'll get back to you on refactoring a new model. \$\endgroup\$ Commented Aug 27, 2017 at 3:09

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.