I am writing a program that will write a diary for the user, however i'm having a bit of trouble... Here's my code:
Shoes.app :title => "Diario", :width => 640, :height => 430 do
name = ask("Name")
n1 = ask("Yesterday's Date")
n2 = ask("Today's Date")
n3 = ask("Tommorow's Date")
w1 = ask("Yesterday's weather")
w2 = ask("Today's Weather")
w3 = ask("Tommorow's Weather")
a1 = ask("Yesterday's Activity")
a2 = ask("Today's Activity")
a3 = ask("Tommorow's Activity")
m = ask("Mood")
tw = ask("Today was...")
sn = ask("Special Notes")
#entry
para "Dear diary, The date is " + n2 + ". It is " + w2 + ". I will go to " + a2 + "."
para "Yesterday was " + n1 + ". It is " + w1 + ". I will go to " + a1 + "."
para "Tomorrow is " + n3 + ". It is " + w3 + ". I will go to " + a3 + "."
para "Today was " + tw + ". " + sn + "I am feeling " + m + "."
end
button "Save", :width => 85 do
file = ask_save_file
File.open(file, "w+") do |f|
#file.text = File.write(#entry.text)
end
end
- But when I run the code I get this-
Error in <unknown> line 0 | 2017-03-15 20:44:14 -0400
undefined method `button' for main:Object
I know this is an ametuer mistake, but please help me anyway?
Thanks, Daniel M.
UPDATE:
Problem solved; I just had to move the first 'END' to the end - it was closing the app block. However, When I save to a file now, it saves as a blank file... any ideas?
button is outside Shoes.app block
require 'shoes'
Shoes.app :title => "Diario", :width => 640, :height => 430 do
name = ask("Name")
n1 = ask("Yesterday's Date")
n2 = ask("Today's Date")
n3 = ask("Tommorow's Date")
w1 = ask("Yesterday's weather")
w2 = ask("Today's Weather")
w3 = ask("Tommorow's Weather")
a1 = ask("Yesterday's Activity")
a2 = ask("Today's Activity")
a3 = ask("Tommorow's Activity")
m = ask("Mood")
tw = ask("Today was...")
sn = ask("Special Notes")
#entry
para "Dear diary, The date is " + n2 + ". It is " + w2 + ". I will go to " + a2 + "."
para "Yesterday was " + n1 + ". It is " + w1 + ". I will go to " + a1 + "."
para "Tomorrow is " + n3 + ". It is " + w3 + ". I will go to " + a3 + "."
para "Today was " + tw + ". " + sn + "I am feeling " + m + "."
button "Save", :width => 85 do
file = ask_save_file
File.open(file, "w+") do |f|
#file.text = File.write(#entry.text)
end
end
end
Related
In a text based game that I'm making with Ruby, I wanted to have multiple colors on a single line of text. The paint gem would only seem to work with two colors but I wanted more, so I looked up those terminal codes to manipulate the cursor position so I could move up a line and print a string in a new color.
Is there a more efficient way to do this? Here is the code for the buy function from the shop:
clr
draw_stats_main
shopbag = Game_DB.weapons_array
bagkeys = shopbag.keys
bagkeys.delete_if {|i| i == 0}
shopbag.each { |id, value|
if id != 0
if id >= 10
string1 = " (" + id.to_s + ")" + " " + value[0]
str1 = string1.size
else
string1 = " (" + id.to_s + ")" + " " + value[0]
str1 = string1.size
end
string2 = "ATTACK: #{value[1]}"; str2 = string2.size
string3 = "SPEED: #{value[2]}"; str3 = string3.size
string4 = "" if !value[3]
string4 = "TWO HANDED WEAPON" if value[3]
str3 = string3.size
pa "#{string1}"
pa "\033[1A \033[#{str1}C #{string2}", :red, :bright
pa "\033[1A \033[#{str1+str2+4}C #{string3}", :yellow, :bright if value[1] < 10
pa "\033[1A \033[#{str1+str2+str3+9}C #{string4}", :red if value[1] < 10
pa "\033[1A \033[#{str1+str2+3}C #{string3}", :yellow, :bright if value[1] > 10 && value[1] < 100
pa "\033[1A \033[#{str1+str2+str3+8}C #{string4}", :red if value[1] > 10 && value[1] < 100
pa "\033[1A \033[#{str1+str2+2}C #{string3}", :yellow, :bright if value[1] >= 100
pa "\033[1A \033[#{str1+str2+str3+7}C #{string4}", :red if value[1] >= 100
pa " >> Cost: #{value[4]}", :yellow
end
}
pa "#{Game_DB.tx(:other, 0)}"
pa "#{Game_DB.tx(:common, 22)}", :green, :bright
loop do
key = gets.chomp.to_i
if bagkeys.include?(key)
if #player.gold >= shopbag[key][4]
#player.remove_gold(shopbag[key][4])
#player.add_item(:weapon, key)
weap = shopbag[key][0]; weapstr = weap.delete " "
pa "#{Game_DB.tx(:other, 0)}"
pa " You purchased #{weapstr} for #{shopbag[key][4]} gold! Dont forget to equip it!", :green, :bright
key = gets
break
else
pa " You don't have enough gold!", :red
key = gets
break
end
elsif key == 0
#shopmenu[0] = false
break
end
end
Here is a screenshot of what the player sees with this block of code: Weapons Shop screenshot
Trying to create a ceaser cipher in Ruby.
The problem I'm facing is that when the program reaches the while loop, it only performs the desired operation on the very last letter of the inputted word. Before I delve further into what I've tried, please find the code:
#!/usr/bin/ruby
#print 65.chr ASCII code for A
#print 97.chr ASCII code for a
a = 0
b = 97
d = []
e = 0
# Just to print the alphabet alongside the ASCII value
# (For sanity checking)
while a <= 25
print b.chr + " "
print b.to_s + "\n"
a = a + 1
b = b + 1
end
puts "\n Please enter a word to translate"
word = gets.strip
# The desired effect is to move the letter along by key value
puts "Please enter a key"
k = gets.chomp.to_i
# In its current state, what happens is only the last char
# is moved along by the key value.
while e <= word.length
word.each_byte do |c|
d[e] = c + k
end
e = e + 1
end
puts d
I'm thinking that the problem lies with the logic for the while loop. The way I am going to attack this is by reading the pre-converted word into an array, as opposed to using the .each_byte object.
I don't know how to do that and the guides/questions I've found don't quite answer the question. If anyone knows how to do this, or knows a better way of solving this- I'd be much appreciative.
you don't need the last while loop
word.each_byte do |c|
d[e] = c + k
e = e + 1
end
Something a bit more verbose:
alphabet = ('a'..'z').to_a
new_word = ''
puts "\n Please enter a word to translate"
word = gets.strip
puts "Please enter a key"
k = gets.chomp.to_i
word.split('').each_with_index do |letter, index|
alphabet_index = alphabet.index(letter)
new_index = alphabet_index + key
new_word[index] = alphabet[new_index]
end
puts "Your translated word is #{new_word}"
Caesar cipher is a simple shift cipher
word.each_byte do |c|
p c + k
end
Managed to get it working, thanks for all the help... Code for anyone interested:
#!/usr/bin/ruby
#print 65.chr A
#print 97.chr a
a = 0
b = 65
y = 97
d = []
e = 0
while a <= 25
print y.chr + " = " + y.to_s + " "
print b.chr + " = " + b.to_s + " " + "\n"
a = a + 1
b = b + 1
y = y + 1
end
puts "\n Please enter a word to translate"
word = gets.strip
puts "Please enter a key"
k = gets.chomp.to_i
word.each_byte do |c|
d[e] = c + k
e = e + 1
end
print "\n"
a = 0
arlen = d.count
while a != arlen
print d[a].chr
a = a + 1
end
print k
This shows an error because ruby scope rules prevent me from accessing outer variables inside an if else block.
puts "Enter Line 1 m and c:"
m1 = gets.to_f
c1 = gets.to_f
puts "Enter Line 2 m and c:"
m2 = gets.to_f
c2 = gets.to_f
if ((m1==m2) and (c1==c2))
puts "infinite solutions"
elsif ((m1==m2) and (c1!=c2))
puts "no solution"
else
x = (c1 - c2)/(m2 - m1)
y = m1*x + c1
puts "(x,y) = (" + x + "," + y+")"
end
Can you please tell me a way to get around this error ?
Update:
actually the error i get is:
undefined local variable or method 'c1'
for main:Object from :7
from C;/Ruby200-x64/bin/irb:12;in ''
Use interpolation to get rid of this.
puts "(x,y) = (#{x}, #{y})"
You were trying to concatenate String object with Float object. That's not possible, so you have to convert those Float to String objects before concatenation.
modified code:
puts "Enter Line 1 m and c:"
m1 = gets.to_f
c1 = gets.to_f
puts "Enter Line 2 m and c:"
m2 = gets.to_f
c2 = gets.to_f
if m1 == m2 and c1 == c2
puts "infinite solutions"
elsif m1 == m2 and c1 != c2
puts "no solution"
else
x = (c1 - c2)/(m2 - m1)
y = m1*x + c1
puts "(x,y) = (#{x}, #{y})"
end
output
[arup#Ruby]$ ruby a.rb
Enter Line 1 m and c:
14
21
Enter Line 2 m and c:
12
44
(x,y) = (11.5, 182.0)
[arup#Ruby]$
It doesn't prevent you from accessing outer variables, the error you see is:
`+': no implicit conversion of Float into String (TypeError)
which is completely different and has nothing to do with variables visibility scopes. What error says is that you can't sum up String and Float(try 'a' + 1.0 in console).
To fix it you should convert variables to strings by yourself with:
puts "(x,y) = (" + x.to_s + "," + y.to_s + ")"
or by using interpolation(which is preferable):
puts "(x,y) = (#{x}, #{y})"
I wrote a tic-tac-toe program which is user vs user. There is s while loop in the code which makes it run over and over for turns. However, this loop doesn't break when someone wins. Any suggestions?
Here is My code:
class Game
def initialize
#board=Array.new
#board[1]="__|"
#board[2]="__"
#board[3]="|__"
#board[4]="\n__|"
#board[5]="__"
#board[6]="|__"
#board[7]="\n |"
#board[8]=" "
#board[9]="| "
#turn="x"
#win_status = false
end
def win_status
return #win_status
end
def show_board
#board.each do |i|
print i
end
end
def set_turn #switches turns
if #turn == "x"
#turn = "o"
else #turn == "o"
#turn = "x"
end
end
def make_move
puts "Enter x coordinate"
x=gets.to_i
puts "Enter y coordinate"
y=gets.to_i
#board[1]="_"+#turn+"|" if y==1 && x==1
#board[2]="_"+#turn if y==2 && x==1
#board[3]="|_"+#turn if y==3 && x==1
#board[4]="\n_"+#turn+"|" if y==1 && x==2
#board[5]="_"+#turn if y==2 && x==2
#board[6]="|_"+#turn if y==3 && x==2
#board[7]="\n "+#turn+"|" if y==1 && x==3
#board[8]=" "+#turn if y==2 && x==3
#board[9]="|"+#turn+" \n" if y==3 && x==3
end
def win_combo
#win_combo = [*[#board[1][1] + #board[2][1] + #board[3][2]], [#board[4][2] + #board[5][1] + #board[6][2]], [#board[7][1] + #board[8][1] + #board[9][1]],[#board[1][1] + #board[4][2] + #board[7][1]], [#board[2][1] + #board[5][1] + #board[8][1]], [#board[3][2] + #board[6][2] + #board[9][1]], [#board[1][1] + #board[5][1] + #board[9][1]], [#board[3][2] + #board[5][1] + #board[7][1]]]
end
def check_win
#if some row or column or diagonal is "xxx" or "ooo" then set #win_status = true
#win_combo.each do |str|
if str == "xxx" or str == "ooo"
#win_status = true
end
end
puts #win_status
end
end
g = Game.new
while g.win_status != true
g.set_turn
g.make_move
g.show_board
g.win_combo
g.check_win
end
You don't check if you won (check_win) and you don't change #win_combo
while g.win_status != true
#puts g.check_win
g.set_turn
g.make_move
g.show_board
g.win_combo #this line
g.check_win #and this line
end
And in your #win_combo suppose to be array of strings not array of arrays of strings.
For example, your old code:
[["ooo"], ["_xx"], [" "], ["o_ "], ["ox "], ["ox "], ["ox "], ["ox "]]
new one:
["ooo", ["_x_"], [" "], ["o_ "], ["ox "], ["o_ "], ["ox "], ["ox "]]
Just add * ad the beginning(as I did here) or just don't make arrays:
#win_combo = [*[#board[1][1] + #board[2][1] + #board[3][2]], [#board[4][2] + #board[5][1] + #board[6][2]], [#board[7][1] + #board[8][1] + #board[9][1]],[#board[1][1] + #board[4][2] + #board[7][1]], [#board[2][1] + #board[5][1] + #board[8][1]], [#board[3][2] + #board[6][2] + #board[9][1]], [#board[1][1] + #board[5][1] + #board[9][1]], [#board[3][2] + #board[5][1] + #board[7][1]]]
Edit:
Ok, * applied only to the first array, my bad.
This is a correct version.
You can see where I've put () instead of []; By this I made array of strings.
Additionally you had you have checked wrong position on following combinations.
#win_combo = [
(#board[1][1] + #board[2][1] + #board[3][2]), # ok
(#board[4][2] + #board[5][1] + #board[6][2]), # ok
(#board[7][2] + #board[8][1] + #board[9][1]), # this # [7][2] not [7][1]
(#board[1][1] + #board[4][2] + #board[7][2]), # this # [4][2] not [4][1]; [7][2]
(#board[2][1] + #board[5][1] + #board[8][1]), # ok
(#board[3][2] + #board[6][2] + #board[9][1]), # ok
(#board[1][1] + #board[5][1] + #board[9][1]), # ok
(#board[3][2] + #board[5][1] + #board[7][2]) # this [7][2] not [7][1]
]
puts "\n##win_combo\n"
#win_combo
end
ps. puts "\n##win_combo\n" is for debuging your application. Delete it in release version.
I'm playing around with the new yahoo API. I'd like to scrap some dummy data using the following address
http://query.yahooapis.com/v1/public/yql?q=desc%20social.updates.search&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=cbfunc
When I run this I get an authenticaion error (Need to be logged into Yahoo) This is fine obviously for me messing around on the internet. However I'd like to call this from a ruby script. Any ideas how I go about authenticating? I can only seem to find some web enabled version.
You might try the Mechanize gem for this. I've used it for other authenticated services
in the past.
I'd also recomment httparty -- It is ridiculously easy to map JSON services with this. Try this:
require 'rubygems'
require 'httparty'
class Yahoo
include HTTParty
# i don't think you need auth for this endpoint -- but if you do, uncomment below and fill it in
#basic_auth 'username', 'password'
format :json
def self.load
self.get 'http://query.yahooapis.com/v1/public/yql', :query => {:q => 'desc social.updates.search', :format => 'json', :diagnostics => true, :env => 'store://datatables.org/alltableswithkeys'}
end
end
puts Yahoo.load
You could try omniauth-yahoo for authorization, but it's seen didn't support get the new token after expired.
Public Function ScanColumns(SheetName As String, thisMany As Double, ShowWhat As String)
e = 0
For a = 1 To thisMany
aa = Application.WorksheetFunction.CountA(Sheets(SheetName).Cells(1, a).EntireColumn)
If aa > 0 Then
r = a
If e = 0 Then
e = a
End If
End If
Next a
If ShowWhat = "MIN" Then
ScanColumns = e
End If
If ShowWhat = "MAX" Then
ScanColumns = r
End If
End Function
Public Function ScanRows(SheetName As String, thisMany As Double, ShowWhat As String)
e = 0
For a = 1 To thisMany
aa = Application.WorksheetFunction.CountA(Sheets(SheetName).Cells(a, 1).EntireRow)
If aa > 0 Then
r = a
If e = 0 Then
e = a
End If
End If
Next a
If ShowWhat = "MIN" Then
ScanRows = e
End If
If ShowWhat = "MAX" Then
ScanRows = r
End If
End Function
Public Function FindInArea(SheetName As String, startRow As String, endRow As String, startCol As String, endCol As String, FindThis As String, ShowWhat As String)
CalendarMonthFormat1 = "Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec,"
CalendarMonthFormat2 = "January, Feburary,March,April,May,June,July,August,September,October,November,December,"
earliestDate = 999999999
latestDate = 0
If Left(FindThis, 7) = "[LENGTH" Then
LengthLook = Replace(FindThis, "[LENGTH", "")
LengthLook = Replace(LengthLook, "]", "")
End If
For a = startRow To endRow
For b = startCol To endCol
ThisCell = Sheets(SheetName).Cells(a, b)
thisCellAddr = Sheets(SheetName).Cells(a, b).Address
If ThisCell = FindThis Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
If FindThis = "[MONTHS1]" Then
If ThisCell <> "" And InStr(LCase(CalendarMonthFormat1), LCase((ThisCell) & ",")) > 0 And Len(ThisCell) = 3 Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
End If
If FindThis = "[MONTHS2]" Then
If ThisCell <> "" And InStr(LCase(CalendarMonthFormat2), LCase((ThisCell) & ",")) > 0 Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
End If
If FindThis = "[DATEFORMAT]" Then
If InStr(ThisCell, "/") > 0 Then
slash_count = 0
For sc = 1 To Len(ThisCell)
If Mid(ThisCell, sc, 1) = "/" Then
slash_count = slash_count + 1
End If
Next sc
If slash_count = 2 Then
On Error Resume Next
D = Day(ThisCell)
M = Month(ThisCell)
Y = Year(ThisCell)
If D > 0 And M > 0 And Y > 0 Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
If earliestDate > DateValue(ThisCell) Then
earliestDate = DateValue(ThisCell)
If Len(D) = 1 Then
D = "0" & D
End If
If Len(M) = 1 Then
M = "0" & M
End If
eDateLocation = thisCellAddr
eDate_Format = D & "-" & M & "-" & Y
End If
If latestDate < DateValue(ThisCell) Then
latestDate = DateValue(ThisCell)
If Len(D) = 1 Then
D = "0" & D
End If
If Len(M) = 1 Then
M = "0" & M
End If
lDateLocation = thisCellAddr
lDate_Format = D & "-" & M & "-" & Y
End If
End If
End If
End If
End If
If Left(FindThis, 7) = "[LENGTH" Then
If Len(ThisCell) = Val(LengthLook) Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
End If
If FindThis = "[DECIMAL]" Then
If InStr((ThisCell), ".") > 0 Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
End If
If FindThis = "[PERC]" Then
If InStr((ThisCell), ".") > 0 And ThisCell <> "" And ThisCell <> 0 And Val(ThisCell) >= -1 And Val(ThisCell) <= 1 Then
addrList = addrList & "[" & thisCellAddr & "]"
rc_list = rc_list & "[" & a & "," & b & "]"
c = c + 1
End If
End If
Next b
Next a
If ShowWhat = "COUNT" Then
FindInArea = c
End If
If ShowWhat = "ADDR" Then
FindInArea = addrList
End If
If ShowWhat = "RC" Then
FindInArea = rc_list
End If
If ShowWhat = "EARLIESTDATE" Then
FindInArea = eDate_Format
End If
If ShowWhat = "EARLIESTDATEADDR" Then
FindInArea = eDateLocation
End If
If ShowWhat = "LATESTDATE" Then
FindInArea = lDate_Format
End If
If ShowWhat = "LATESTDATEADDR" Then
FindInArea = lDateLocation
End If
End Function