Ruby - Trying to create an unbeatable game - ruby

I am trying to create a version of the game I created where the program(computer) always wins. Game is Rock Paper Scissors.
I am a beginner in Ruby, I have successfully created the "normal" version of the game where the coputer chooses its results at random. I have been searching for awhile and stuck for about a day on this simple problem.
If anyone can point me in the write direction, as I do not really want the solution solved for me as I am really trying to learn this. But I feel I am missing something important. I had the idea of using the Minimax algorithm so I just started reading into that as well.
I am very open to different solutions to this problem.
Below is my current "Normal" version of the game. And also the part I believe the change needs to take place... where the computer makes it selection based on the users input. Then I will show the section I was trying to make in the same game, but having the computer always win.
Question: How do I have the computer makes its selection correctly based on user input? I know many options exit in Ruby, I am open to different solutions or types of solution that I can incorporate into my program.
Thank you for any/all responses in advance.
def get_player_play
prompt
#player_play = gets.chomp.upcase.to_sym
#winner = :invalid if #player_play != :R || :P || :S
#winner = :score if #player_play == :X
#winner = "" if #player_play == :Q
end
def get_computer_play
#computer_play = WINS.keys.sample
end
def get_winner
if #player_play == #computer_play then #winner = nil
else
#winner = :player if WINS[#player_play] == #computer_play
#winner = :computer if WINS[#computer_play] == #player_play
end
end
Here is what I have tried (plus many variations of the same type of if/else statements).
#this makes it a tie
def get_computer_play
if NAME[#player_play] == ( NAME[:R] )
return #computer_play = WIN[:P]
elsif NAME[#player_play] == ( NAME[:P] )
return #computer_play = WIN[:S]
else
NAME[#player_play] == ( NAME[:S] )
return #computer_play = WIN[:R]
end
end

Here is a different, more Ruby-like, approach.
WINNERS = { "rock"=>"paper", "scissors"=>"rock", "paper"=>"scissors" }
def cheat
loop do
puts "rock, paper or scissors?"
computer = WINNERS[gets.downcase.chomp]
if computer
puts "You lose, computer chose #{computer}."
break
end
puts "That entry is invalid. Try again."
end
end
cheat #=> (enter "rock") "You lose, computer chooses paper."
cheat #=> (enter "papter") "That entry is invalid. Try again."
cheat #=> (enter "paper") "You lose, computer chooses scissors."
cheat #=> (enter "scissors") "You lose, computer chooses rock."

To create a rigged game, use a case-expression along the lines of:
puts "Rock, paper or scissors?"
ans = gets.downcase.chomp
case ans
when "rock"
puts "You lose, computer chose paper"
when "paper"
#insert code here
when "scissors"
#insert code here
end

Related

stuck on a multiple choice game on ruby

I am just starting with ruby and tried to create a multiple choice game. I can't seem to see where i get something wrong which makes it so that it either repeats the generic line for a room instead of showing the resulting option.
just for info, the options in the hall are either "north", "look" or "quit"
then in the study, options are "look", "look at desk", "south", "quit", "enter combination 2451"
code below:
def hall_begin
#first line you see
puts "you can either look around or move north"
gets.chomp
end
def look_hall
# first option to look around in the hall
puts "You are standing in a hall with a marble floor. You see a door."
hall_begin
end
def onwards_study
# second option to go forwards into the next room from the hall
puts "You are in the study, you can either look around of move back south"
gets.chomp
end
def back_to_hall
# moving back into the hall from the study
puts "You are back in the hall, either look around or go north"
gets.chomp
end
def look_study
# looking around the study to find the desk and safe
puts "You are in a warm and cosy study. You see a safe. You see a desk."
onwards_study
end
def study_desk
# looking on the study desk to find the combination
puts "You see a piece of paper that reads, The combination is 2451."
onwards_study
end
def study_safe
# if you open the safe with combination
puts "You see some diamonds in the safe, pick them up and make your escape"
end
def first_choice
# all the choices whilst in the hall
while true
direction_1 = hall_begin
if direction_1 == "look"
look_hall
elsif direction_1 == "north"
onwards_study
elsif direction_1 == "quit"
break
end
end
end
while true
# start of the game
first_choice
while true
# all choices you face whilst in the study
direction_2 = onwards_study
if direction_2 == "look"
look_study
elsif direction_2 == "south"
back_to_hall
elsif direction_2 == "look at desk"
study_desk
elsif direction_2 == "enter combination 2451"
study_safe
break
elsif direction_2 == "quit"
break
end
break
end
end
This seems to be a beginner level program. In case if you haven't studied the functions yet. This simple code can help you.
won_condition = false
breaking_condition = false
puts "You are standing in the hall, either look around or go north"
while true
if won_condition == true
break
end
if breaking_condition == true
break
end
user_input = gets.chomp
if user_input == 'quit'
break
elsif user_input == "look"
puts "You are standing in a hall with a marble floor. You see a door."
elsif user_input == 'north'
puts "You are in the study, you can either look around or move back south"
while true
study_input = gets.chomp
if study_input == 'look'
puts "You are in a warm and cosy study. You see a safe. You see a desk."
elsif study_input == 'look at desk'
puts "You see a piece of paper that reads, The combination is 2451."
elsif study_input == 'south'
puts "You are standing in the hall, either look around or go north"
break
elsif study_input == '2451'
puts "You see some diamonds in the safe, pick them up and make your escape."
won_condition = true
break
elsif study_input == 'quit'
breaking_condition = true
break
end
end
end
end
As Chandan pointed out, having this many loops is unnecessary. I think what you are after can be achieved by having one main loop that gets the user input and then handles it.
I don't want to make too complicated suggestions to begin with since you are just starting out, but I think keeping track of a "current_room" variable is helpful (which can later transition into coordinates on a 2D room array or something).
Too give you a few examples, this is how something similar could be achieved.
def describe_room(current_room)
if current_room == "hall"
puts "You are standing in the hall, either look around or go north"
elsif current_room == "study"
puts "You are in the study, you can either look around of move back south"
end
end
def examine_room(current_room)
if current_room == "hall"
puts "You are standing in a hall with a marble floor. You see a door."
elsif current_room == "study"
puts "You are in a warm and cosy study. You see a safe. You see a desk."
end
end
def move(current_room, direction)
if current_room == "hall" and direction == "north"
"study"
elsif current_room == "study" and direction == "south"
"hall"
else
puts "You cannot go that way"
current_room
end
end
def hall_commands(command)
# No hall specific commands at this points
puts "Unknown command"
# Return "hall" since we are never moving anywhere else
"hall"
end
def study_commands(command)
if command == "look at desk"
puts "You see a piece of paper that reads, The combination is 2451."
elsif command == "enter combination 2451"
puts "You see some diamonds in the safe, pick them up and make your escape"
return nil # Use explicit return statement to avoid default return at the end of the method
else
puts "Unknown command"
end
# Return "study" as the default
"study"
end
# Starting position
current_room = "hall"
while true
break if current_room == nil
# Start each loop by a brief description of the current room.
describe_room(current_room)
# Get the user input in the main loop
command = gets.chomp
# Check for global commands (i.e. movements, look, etc.) first
# and then move on to check for room specific commands.
if command.in?(["north", "east", "south", "west"])
current_room = move(current_room, command)
elsif command == "look"
examine_room(current_room)
elsif command == "quit"
break
elsif current_room == "hall"
current_room = hall_commands(command)
elsif current_room == "study"
current_room = study_commands(command)
else
puts "Unknown command"
end
end
Basically I have simplified it into one loop as mentioned earlier, then split up the "global commands" that could be used regardless which room your are in, and the "room specific commands" that only apply in certain rooms.
I hope this helps you getting into Ruby. When you feel more comfortable, I would recommend looking into case/when statements as an alternative to if/elsif/else statements and also Arrays to keep track of rooms and positions.

Undefined Method "attack" for Player::Class

So I am trying to make a text based game with classes for an assignment. I have worked for 2 hours and could not find what the problem is.
class Rankuun
attr_accessor :rankuun_damage, :rankuun_health
def initialize
rankuun_health = 200
rankuun_damage = 100
end
def monolouge
puts 'Rankuun: "So, I see that you have lived this long. I am suprised.'
puts "Not a single libing creature has lived for this long inside my dungeon."
puts "But it's time that your endless slaughter of my brethren are halted."
puts "Now face what true fear really is!"
puts "Hoc vanitas est, et non est fere ut serves!"
puts "You see a mystical aura rise around Rankuun, and hear the shouts of agony"
puts "Rankuun has grown twice in size, and has taken the form of some kind of lich"
puts 'Rankuun: WELCOME TO DIE!"'
end
end
class Player
attr_accessor :health, :gold
def initialize
health = 100
money = 200
puts "Health: #{health}"
puts "Gold: #{money}"
end
def attack
puts "You attack the monster!"
hitmiss = 1
if hitmiss == 1
dmg = rand(5..10)
puts "You hit the monster, and do #{dmg} damage!"
monster_health = monster_health - dmg
elsif hitmiss == 2
puts "You missed!"
end
end
def guard
puts "You attempt to defend yourself"
guard = rand(1..2)
if guard == 1
counter = rand(5..10)
puts "You block the damage, and counterstrike for #{counter} damage"
monster_health = monster_health - counter
elsif guard == 2
monster_counter = rand(1..5)
puts "You try to guard, but the enemy hits harder than you expected, and you get dealt #{monster_counter}"
health = health = monster_counter
end
end
def loot
puts "You search the room and find:"
loot_item = rand (2..3)
if loot_item == 2
puts "You find some gold!"
money = money + 50
puts "Health: #{health}"
puts "Gold: #{money}"
elsif loot_item == 3
puts "You find a curious potion that seems to heal you"
health = health + 50
puts "Health: #{health}"
puts "Gold: #{money}"
end
end
def encounter
encounter = rand(1..2)
if encounter == 1
puts "A monster confronts you!"
monster = Monster.new
elsif encounter == 2
puts "There appears to be no monsters in this room"
end
end
end
class Monster
attr_accessor :monster_health, :monster_damage
def initialize
monster_health = 50
monster_damage = 10
end
def monster_attack
puts "The monster attacks you!"
end
end
puts "There has been a saying in your town for as long as you can remember:"
puts "Ne pas entrer dans le Donjon De Rankuun"
puts 'It means: "Do not enter The Dungeon of Rankuun"'
puts "Many adventurers died inside, and the only living creature in there is the man named Rankuun"
puts "He has great power over the Dungeon, reviving the dead and casting black magic"
puts "You have been selected by the village to go into the Dungeon and exterminate Rankuun"
puts "You have been given a sword, a shield, and some gold. Now you must enter:"
puts "T H E D U N G E O N O F R A N K U U N!"
puts ""
puts ""
player = Player.new
player.encounter
room1 = gets.chomp
if room1 == "attack"
player.attack
elsif room1 == "loot"
player.loot
end
It would be great if this problem were solved. Thanks for responding and aiding me in my assignment.
Welcome to the exciting world of object-oriented design. Many adventurers died inside.
I think you may have a small misunderstanding about the difference between classes and instances. If so, I strongly advise you to read about it before continuing.
You created a new instance of Player when you called Player.new. Your first mistake was not putting it in a variable.
Try something like this:
my_player = Player.new
Secondly, you are trying to call encounter on the Player class, while you should call it on the new instance.
my_player.encounter
You do the same thing inside the Monster class with Player.attack.
I could tell you how to solve each of these problems individually, but I think you would benefit more from redesigning some parts of the project to be easier to change in the future. Hopefully, most of the problems will resolve themselves along the way.
Generally speaking, the shorter a method is, the better. When you tell the Player to attack, that is all it should do. Instead, it does all sorts of things, including getting the monster to attack!
It suddenly becomes apparent that the two classes have quite a lot in common: they both attack; they both take damage, and they both die. It's time to make a superclass. (If you are not familiar with how classical inheritance works, you should learn - this truly is the perfect use case for it.)
class Character
attr_accessor :health
def attack damageable, damage
damageable.take_damage damage
end
def take_damage damage
health -= damage # Equivenent to health = health - damage
potential_death
end
def potential_death
if dead?
die
end
end
def dead?
health <= 0 # With random damage, it could be less than 0.
end
def die # overruled by subclass
end
end
The greatest advantage to doing it like this is you only have to write the code in one place, and it will work for everything. If you change your mind about a design decision, you can change it in one place and know that everything will be adjusted.
You can make a subclass similar to this:
class Monster < Character
def die
super # Call the copy of die in Character, in case it contains something important
reward killer
puts "You kill the monster..."
end
def reward rewardable
rewardable.gain_money 30
end
end
class Player < Character
def die
super # Call the copy of die in Character, in case it contains something important
puts "You died..."
game.over
end
end
(These are only examples; they are not as complete as the code you already have.)
Do you see how each method only does one thing? If you apply that principle to everything you write, it will become much easier to reuse bits and pieces.
I hope this has been useful. If you decide to stick with what you have and just fix the errors, just say so in the comments, and I'll help you with that.
Good luck!

Mini-game. Ruby the hard way exercise 35

I'm currently learning ruby from the Learn Ruby the hard way tutorial. And in that exercise, the author ask us to add things to a simple game. However, I was trying this to improve the bear_room method by doing something like this:
while true
print "> "
choice = gets.chomp.downcase!
if choice.include? ("taunt")
dead("The bear looks at you then slaps your face off.")
elsif choice.include? "taunt" && !bear_moved
puts "The bear has moved from the door. You can go through it now."
bear_moved = true
elsif choice.include? "taunt" && bear_moved
dead("The bear gets pissed off and chews your leg off.")
elsif choice.include? "open" && bear_moved
However, when I write this:
choice = gets.chomp.downcase!
It gives me this error when executing:
ex35.rb:44:in `bear_room': undefined method `include?' for nil:NilClass (NoMethodError)
from ex35.rb:99:in `start'
from ex35.rb:109:in `<main>'
But if do something like this:
choice = gets.chomp.downcase
or this:
choice = gets.chomp
choice.downcase!
It works. Why is that? I would appreciate any kind of help. Also, how works the while true bit? That really gets me confused.
Here is the rest of the program in case that you need it. I'm going to leave "separated" the mentioned method to make it easier to read.
# Creates the 'gold_room' method, so it can be called later.
def gold_room
puts "This room is full of gold. How much do you take?"
print "> "
choice = gets.chomp
# Converts the 'choice' variable to integer type.
choice.to_i
# Checks if 'choice' is equals to 0, OR greater or equal to 1.
if choice == '0' || choice >= '1'
# Saves the integer 'choice' variable in the 'how_much' variable.
how_much = choice.to_i
else
dead("Man, learn to type a number.")
end
# Checks if the 'how_much' variable is lesser than 50, and executes the code below if so.
if how_much < 50
puts "Nice, you're not greedy, you win!"
exit(0)
elsif how_much >= 50 && how_much < 100
puts "Mmm, ok that's enough. Get out!"
else
dead("You greedy bastard!")
end
end
################### bear_room method ###################
# Creates the 'bear_room' method.
def bear_room
puts "There is a bear here."
puts "The bear has a bunch of honey."
puts "The fat bear is in front of another door."
puts "How are you going to move the bear?"
puts "1. Taunt the bear."
puts "2. Steal the bear's honey. "
# Declares the 'bear_moved' variable as a boolean, initialize it to false.
bear_moved = false
while true
print "> "
choice = gets.chomp.downcase
if choice.include? ("taunt")
dead("The bear looks at you then slaps your face off.")
elsif choice.include? "taunt" && !bear_moved
puts "The bear has moved from the door. You can go through it now."
bear_moved = true
elsif choice.include? "taunt" && bear_moved
dead("The bear gets pissed off and chews your leg off.")
elsif choice.include? "open" && bear_moved
gold_room
else
puts "I got no idea what that means."
end
end
end
############### end of method ###############
# Defines the 'cthulhu_room' method.
def cthulhu_room
puts "Here you see the great evil Cthulhu."
puts "He, it, whatever stares at you and you go insane."
puts "Do you flee for your life or eat your head?"
print "> "
choice = gets.chomp
# Checks if the user's input contains the word 'flee'. If so, executes the code below.
if choice.include? "flee"
start
# Checks if the user's input contains the word 'head'. If so, executes the code below instead.
elsif choice.include? "head"
dead("Well that was tasty!")
else
# Otherwise, calls the 'cthulhu_room' method again.
cthulhu_room
end
end
# Defines the 'dead' method. It takes one argument (why). Example: dead("Well that was tasty!")
def dead(why)
puts why, "Nice."
# Succesfully finish the program.
exit(0)
end
# Defines the 'start' method, wich is where the game begins. Duh.
def start
puts "You are in a dark room."
puts "There is a door to your right and left."
puts "Which one do you take?"
print "> "
choice = gets.chomp
# Start the branching. It checks the user's input, and saves that on the 'choice' variable, which is used along the whole program in the other methods.
if choice == "left"
# Calls the 'bear_room' method.
bear_room
elsif choice == "right"
# Calls the 'cthulhu_room' method.
cthulhu_room
else
dead("You stumble around the room until you starve.")
end
end
# Start the game.
start
---------------------------------------------------------------------------
TL;DR: What's the difference between choice = gets.chomp.downcase! and
choice = gets.chomp
choice.downcase!
PS: The comments are part of the exercise. Please, if you have any type of correction (about the comments, how I made the question, code in general, etc) please tell me so I can improve. Thanks and sorry for the length!
-------------------------------------------------------------------------
That is because if the string did not change upon calling downcase! it returns nil. Thus when you try and call include? it says that nil does not have such a method.
Thus, it is safest to use the "non-destructive" version of downcase. The downcase! method mutates the string in place if it can.
Check the docs for further reading.

Ruby: How to exit a function and then return to it

I'm writing a text-adventure game for exercise 36 of Learn Ruby the hard Way: http://ruby.learncodethehardway.org/book/ex36.html
I want to include 'instructions' as an option players can use anytime, but once the player exits the Room() function and enters the intructions() function, I am unsure how to return them to the appropriate room. I can have the instructions() always return player to the start after, but is there a way to get them back to the same location?
Here is a quick example, sorry it's incomplete...I'm still in the middle of building it:
puts
puts <<INTRO
"Welcome to the Cave of Indifference.
It doesn't much care for you. Beware!
There are deadly areas of this cave, but if you seek
it you may find the secret treasure and escape with your life."
INTRO
puts
puts "Type \'Instructions\' at any time for direction"
puts
sword = false
monster = true
treasure = false
def Command()
puts ">>> "
end
def dead(how)
puts how.to_s
puts "PLAYER DEAD!"
Process.exit(0)
end
def instruction()
puts "Rooms will have individual instructions"
puts "but here are some general items."
puts "west, east, north, south: goes that direction"
puts "look: look around the room"
puts "take: to take item or object"
end
def Room1()
puts "You are now at the cave entrance."
puts "You may go west or east. OR exit with your life!"
Command(); choice = gets.chomp()
if choice.downcase == "exit" && treasure = true
puts "Congratulations! You win!"
Process.break
elsif choice.downcase == "exit" && treasure = false
puts "Seriously?! Giving up already?"
puts "Fine. Here is what happens:"
dead("You stumble on your exit from the cave and trip
on a rock. The fall cracks your skull and you bleed
to death. Bye bye!")
elsif choice.downcase.include? "right"
#INPUT
elsif choice.downcase.include? "left"
#INPUT
elsif choice.downcase.include? "instructions"
instructions()
else
"That command makes no sense, try again."
end
end
Room1()
I also assume there are many issues with the code and would be very appreciative of your help, but no worries I am going to keep working on this and make it really fun to play :)
You can give the instruction method the last location.
def instruction(last_room)
#do stuff
last_room.call()
end
You would call that function like so:
instructions(method(:Room1)), where Room1 is the name of the method you want to return to.
The problem you have isn't having instructions return to Room1 (or RoomX). It'll do that without you doing anything special. What you need is something like:
#room = :Room1
while true
send(#room)
end
and then set the variable #room to control which room you're in.
It's not the greatest way in the world to do that, but it'll get you started.

Ruby Blackjack and loops

I am building a command line ruby blackjack game using methods. I have gotten to the point where the player can hit or stick (after having being dealt 2 cards). Right now I can't seem to make the jump to thinking logically about how to limit my player to only four hits. make
This tells me that my problem is looping - that is I am approaching the loop part of the program the wrong way.
Here is my code so far:
def blackjack
promt
end
def promt
puts "Welcome! Would you like to play a game of blackjack? Enter Yes or No"
play = gets.chomp.downcase
if play == "yes"
game_plan
elsif play =="no"
puts "That's too bad. Come back when you feel like playing"
else
puts "Sorry but I don't understand your respones. Please type and enter yes to play Or no to to quit"
blackjack
end
end
def game_plan
wants_to_play = true
hand = []
total = first_move(hand)
wants_to_play = hit_me(hand)
if wants_to_play == true
hit_me(hand)
end
end
def first_move(hand)
deal(hand)
deal(hand)
total(hand)
end
def deal(hand)
card = rand(12)
puts "You have been dealt a card with a value of #{card}"
hand << card
end
def total(hand)
total = 0
hand.each do |count|
total += count
end
puts "The sum of the cards you have been dealt is #{total}"
total
end
def hit_me(hand)
puts "Would you like to hit or stick?"
yay_or_nah = gets.chomp.downcase
if yay_or_nah == "stick" && total(hand) < 21
puts "Sorry! The sum of the cards you have been dealt is less than 21. You lost this round!"
else
deal(hand)
total(hand)
playing = true
end
end
blackjack
What I want to do is limit my player to 2 hits (after the initial first hit, which deals 2 cards). I know this is a totally annoying newbie question but I really would appreciate any feedback that would help me think of the solution in the proper manner.
PS: while I understand how loops work I am STRUGGLING with knowing how and when to implement them … so any feedback would be very much appreciated. Thank you!
Are you looking for something like that?
MAX_HITS = 2
hits = 0
loop do
break if hits > MAX_HITS
puts "Would you like to hit or stick?"
…
else
hits += 1
…
end
end

Resources