Ruby Sequel MySQL Insert Error - mysql

I am learning Ruby and I am using the Sequel gem to handle my model. but I keep running into an error I can't seem to hunt down. The thing that doesn't make sense is that is it failing on an insert because a field doesn't exist in a table that I am inserting into. However, I am not attempting to use the field that doesn't exist.
Here is my error:
0
{:id=>5, :name=>"barcelona"} : {:id=>4, :name=>"berlin"}
/Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `query': Mysql::Error: Unknown column 'name' in 'field list' (Sequel::DatabaseError)
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `block in _execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/logging.rb:33:in `log_yield'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:175:in `_execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/shared/mysql_prepared_statements.rb:34:in `block in execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/connecting.rb:250:in `block in synchronize'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/connection_pool/threaded.rb:98:in `hold'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/database/connecting.rb:250:in `synchronize'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/shared/mysql_prepared_statements.rb:34:in `execute'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/adapters/mysql.rb:160:in `execute_insert'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/dataset/actions.rb:927:in `execute_insert'
from /Users/username/.rvm/gems/ruby-2.2.0/gems/sequel-4.20.0/lib/sequel/dataset/actions.rb:336:in `insert'
from travellingAmerican.rb:70:in `addDist'
from travellingAmerican.rb:64:in `block (2 levels) in addLocations'
from travellingAmerican.rb:61:in `each'
from travellingAmerican.rb:61:in `block in addLocations'
from travellingAmerican.rb:58:in `each'
from travellingAmerican.rb:58:in `addLocations'
from travellingAmerican.rb:93:in `<main>'
Here is models.rb:
#Database
require 'sequel'
def create
DB.create_table(:locations) do
primary_key :id
String :name, :unique=>true
end
DB.create_table(:distances) do
primary_key :id
foreign_key :to, :locations
foreign_key :from, :locations
Float :miles, :default=>-1
TrueClass :valid, :default=>0
unique [:to, :from]
end
end
def drop
begin
DB.drop_table(:distances)
rescue
puts "Couldn't drop Distances"
end
begin
DB.drop_table(:locations)
rescue
puts "Couldn't drop locations"
end
end
DB = Sequel.connect(:adapter=>'mysql', :host=>'myHost', :user=>'myUser', :password=>'myPass', :database=>'myDB')
if __FILE__ == $PROGRAM_NAME
puts "Will Execute"
drop
create
puts "Done Executing"
end
Now the file the error is actually in, travellingAmerican.rb:
#Traveling American
require './models.rb'
require 'json'
def urlCreator(cities)
urls = []
rootUrl = "https://maps.googleapis.com/maps/api/distancematrix/json?"
origin = "origins="
dest = "destinations="
key = "myApiKey"
cities.each do |city|
city = city.gsub(/[" "]/, '+')
newOrigin = origin + city + "|"
newDest = dest
cities.each do |inCity|
newDest += inCity + "|"
end
newUrl = rootUrl + newOrigin + "&" + newDest + "&" + key
urls.push(newUrl)
end
urls
end
def processFile(file)
cities = []
File.readlines(file).each do |line|
line = line.strip
if line.count(",") == 1
line = line.split()
else
cities.push(line)
end
end
return cities
end
def addLocations(cities)
cities.each do |city|
begin
DB[:locations].insert(:name => city.downcase)
rescue Sequel::UniqueConstraintViolation
puts "Duplicate, not added"
end
end
allLocs = DB[:locations].where(:name => cities).order(:name).all
#if you puts allLocs it works beautifully
for i in 0...allLocs.length
puts i
toLoc = allLocs[i]
for j in (i+1)...allLocs.length
fromLoc = allLocs[j]
puts toLoc.to_s + " : " + fromLoc.to_s
#If you comment out the line below everything runs fine, minus the insertion obviously
addDist(toLoc, fromLoc)
end
end
end
def addDist(tos, froms)
#the line with the error
DB[:distances].insert(:to=>tos, :from=>froms)
end
if __FILE__ == $PROGRAM_NAME
popSize = -1
file = ""
count = 0
ARGV.each do|arg|
if count == 0
popSize = arg.to_i
else
file = arg
end
count += 1
end
if popSize == -1 or file == ""
abort("Usage: ruby travellingAmerican.rb popSize cityList")
end
cities = processFile(file)
addLocations(cities)
puts urlCreator(cities)
end
Lastly here is cities.csv if you would like to run this on your own machine:
San Diego
Munich
Paris
Berlin
Barcelona
Monte Carlo
Cinque Terre
Turin
Milan
Florence
Rome
Venice
To run this on your own machine just execute ruby travellingAmerican.rb 1000 cities.csv in a shell.
I hope I have provided enough info for everyone! Thanks for looking.

There are some problems I detected:
Here you add the cities with downcase:
cities.each do |city|
begin
DB[:locations].insert(:name => city.downcase)
rescue Sequel::UniqueConstraintViolation
puts "Duplicate, not added"
end
end
The you read them in a Hash:
allLocs = DB[:locations].where(:name => cities).order(:name).all
The condition is without the downcase! So you get no result.
You could do:
allLocs = DB[:locations].where(:name => cities.map(&:downcase)).order(:name).all
Later you use
addDist(toLoc, fromLoc)
toLoc and fromLoc are both Hashes, but the should be the key for the table cities.
This should work:
addDist(toLoc[:id], fromLoc[:id])
As an alternative you can adapt the insertion in addDist
DB[:distances].insert(:to=>tos[:id], :from=>froms[:id])
The usage of for is not ruby-like. I would use directly Sequel::Dataset#each:
selection = DB[:locations].where(:name => cities.map(&:downcase)).order(:name)
selection.each{|toLoc|
selection.each{|fromLoc|
puts toLoc.to_s + " : " + fromLoc.to_s
#If you comment out the line below everything runs fine, minus the insertion obviously
addDist(toLoc[:id], fromLoc[:id])
}
}
(You could discuss, if the where and order methods are really needed here)

Related

Deserializing an object with other objects in it

I'm making a two-player game of chess played on the command line. I have a class for every type of chess piece and a board class. The board class looks like this:
class Board
attr_accessor :board, :choice
def initialize
#board = Array.new(8){Array.new(8," ")}
#choice = choice
end
end
My other classes look like this:
class Bishop
attr_accessor :x_position, :y_position, :piece, :color, :counter, :moves
def initialize(position,boolean)
#x_position = position[0]
#y_position = position[1]
#piece = boolean ? "♝" : "♗"
#color = boolean ? "white" : "black"
#counter = 0
#moves = [[+1,-1],
[+1,+1],
[-1,+1],
[-1,-1]]
end
I added my pieces to the board like this:
#board[0][0] = Rook.new([0,0],false)
These are my methods to serialize and deserialize the data:
def to_json
JSON.generate({board: #board})
end
def save_game(string)
File.open("saved.json", "w") do |game_file|
game_file.write(string)
end
end
def load_game
game_file = File.read("saved.json")
data = JSON.parse(game_file)
#board = data["board"]
end
After saving, the saved.json file looks like this:
{"board":[[" ","#<Knight:0x00000000e4fc28>","#<Bishop:0x00000000e4fa20>","#<Queen:0x00000000e4f890>","#<King:0x00000000e4f610>","#<Bishop:0x00000000e4f3e0>","#<Knight:0x00000000e4f278>","#<Rook:0x00000000e4e1c0>"],[" "," "," "," "," "," "," "," "],[" "," "," "," "," "," "," "," "],[" "," "," "," "," "," "," "," "],[" "," "," "," "," "," "," "," "],[" "," "," "," "," "," "," "," "],[" "," "," "," "," "," "," "," "],["#<Rook:0x00000000e4fd90>","#<Knight:0x00000000e4ed78>","#<Bishop:0x00000000e4eb70>","#<Queen:0x00000000e4ea08>","#<King:0x00000000e4e7b0>","#<Bishop:0x00000000e4e580>","#<Knight:0x00000000e4e3f0>"," "]]}
When I try to load back the data, the method that displays the board throws this error:
0 1 2 3 4 5 6 7
+----+----+----+----+----+----+----+----+
0|   /home/jacob/Desktop/chess/board.rb:30:in `block (2 levels) in display': undefined method `piece' for "#<Knight:0x00000000e4fc28>":String (NoMethodError)
from /home/jacob/Desktop/chess/board.rb:27:in `each'
from /home/jacob/Desktop/chess/board.rb:27:in `each_with_index'
from /home/jacob/Desktop/chess/board.rb:27:in `block in display'
from /home/jacob/Desktop/chess/board.rb:20:in `each'
from /home/jacob/Desktop/chess/board.rb:20:in `each_with_index'
It looks like my problem is that the objects come back as strings?
my display method:
def display
axis = 0
print " 0 1 2 3 4 5 6 7"
#board.each_with_index do |row,index|
print "\n"
#draw = " +----+----+----+----+----+----+----+----+"
puts #draw
print axis
axis +=1
if index.even?
row.each_with_index do|column,i|
if i.odd?
if column != " "
print "|"+" #{column.piece} ".bruno
else print "|"+" #{column} ".bruno
end
else
if column != " "
print "|"+" #{column.piece} "
else print "|"+" #{column} "
end
end
end
else
row.each_with_index do|column,j|
if j.even?
if column != " "
print "|"+" #{column.piece} ".bruno
else print "|"+" #{column} ".bruno
end
else
if column != " "
print "|"+" #{column.piece} "
else print "|"+" #{column} "
end
end
end
end
print "|"
end
print "\n"
print #draw
end
No, the problem is that your objects are saved as strings. Deserialization works fine, in this case. You'll have to explicitly specify what should be the json representation of your game pieces. Something like this:
class Rook
def to_json(*)
{ name: 'rook', position: 'A1', status: 'in_game' }.to_json
end
end
pieces = [Rook.new]
pieces.to_json # => "[{\"name\":\"rook\",\"position\":\"A1\",\"status\":\"in_game\"}]"
JSON.parse(pieces.to_json) # => [{"name"=>"rook", "position"=>"A1", "status"=>"in_game"}]
On deserialization you'll have to do the reverse. Construct proper game classes from plain ruby hashes, which you get from parsing JSON file.
Or if you don't actually care about JSON and just want to create some form of save file, then Marshal is your best friend. No need to override anything. Zero friction.
pieces = [Rook.new]
Marshal.dump(pieces) # => "\x04\b[\x06o:\tRook\x00" # write this to a file
# restore it later
Marshal.load("\x04\b[\x06o:\tRook\x00") # => [#<Rook:0x007fb50f825570>]

Trying to serialize with JSON a save method in my Ruby Hangman game

I'm trying to get my save_game() method to work, nothing is getting written to the JSON file. This is my first assignment working with JSON and serialization in general. I'm not quite sure where I'm even going wrong.
These are my serialization methods:
def to_json
JSON.generate({array: #array, filestuff: #filestuff, random_word: #random_word, cipher: #cipher, random_word2: #random_word2, counter: #counter})
end
def load
game_file = File.read("saved.json")
data = JSON.parse(game_file)
#cipher = data["cipher"]
#random_word2 = data["random_word2"]
#counter = data["counter"]
end
def save_game(string)
game_file = File.new("saved.json","w")
game_file.write(string)
game_file.close
end
This is my program, on line 92 I try to call my save_game method.
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!
"
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
def to_json
JSON.generate({array: #array, filestuff: #filestuff, random_word: #random_word, cipher: #cipher, random_word2: #random_word2, counter: #counter})
end
def load
game_file = File.read("saved.json")
data = JSON.parse(game_file)
#cipher = data["cipher"]
#random_word2 = data["random_word2"]
#counter = data["counter"]
end
def save_game(string)
game_file = File.new("saved.json","w")
game_file.write(string)
game_file.close
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."
puts "To save press 1"
save = gets.chomp
if save == "1"
#Will not save
save_game($b.to_json)
end
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
puts #cipher.join
end
#counter = 5
while #counter > 0
choice(gets.chomp)
end
end
end
Hangman.new
$b = Gameplay.new
You need to close the file in order to make sure your output is actually written to the disk ("flushed"). You can manually, call close:
def save_game(string)
game_file = File.new("saved.json","w")
game_file.write(string)
game_file.close
end
or, you can use File.open, which takes a block and closes the file when the block ends:
File.open("saved.json", "w") do |game_file|
game_file.write(string)
end
Since, writing to the disk is a slow operation, Ruby (and all languages that I can think of right now) will hold off on actually writing the file until it has accumulated a certain amount of text in a buffer. Once it has reached this limit, it will flush the buffer and write everything in it to disk. In order to make sure all your text is actually written when trying to write a file, you need to call close on the file, and as part of closing it, Ruby will flush whatever is left in its buffer.
There are other ways of making sure your content is flushed but when you're just starting to learn about this stuff, it should suffice to just make sure to always close files when you're done reading or writing them.

Ruby: calling method within another method's conditional statement

I'm trying to call the method print_json within a conditional statement that is contained in another method named list_trends. I did this becauese my code was starting to look too nested. However I get an error when I run that says:
syntax error, unexpected tSTRING_BEG, expecting keyword_do or '{' or '('
...i_key]) ? print_trends : puts "Invalid API Key, operation ab...
Here is my code:
#!/usr/bin/ruby
require 'thor'
require 'json'
class ListTrends < Thor
desc "list trends", "list out trends from JSON file"
option :api_key, :aliases => "--api-key", :type => :string, :required => true
def print_json
json = File.read('trends_available.json')
trends_hash = JSON.parse(json)
trends_hash.each do |key|
key.each do |k,v|
puts "Trend #{k}: #{v}"
end
puts ""
end
end
def list_trends
re = /^(?=.*[a-zA-Z])(?=.*[0-9]).{8,}$/
if options[:api_key]
if re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
end
end
ListTrends.start(ARGV)
This
if options[:api_key]
if re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
Should just be
if options[:api_key]
re.match(options[:api_key]) ? print_json : puts "Invalid API Key, operation abort..."
end
Though I would prefer:
if options[:api_key]
if re.match(options[:api_key])
print_json
else
puts "Invalid API Key, operation abort..."
end
end
Or if you must put it on one line:
if options[:api_key]
if re.match(options[:api_key]) then print_json else puts "Invalid API Key, operation abort..." end
end

Trying to import JSON string in to database using Rails

Exercise.rb - Model
def self.import!
#request = Net::HTTP.get(URI.parse('https://example.com/output'))
#exercises = JSON.parse(#request)
#exercises.each do |e|
existing = Exercise.exists?(e)
unless existing === false
tmp = existing.first
end
e[:sections_attributes] = e.delete("sections")
e[:questions_attributes] = e.delete("questions")
e[:answers_attributes] = e.delete("answers")
record = Exercise.create(e)
puts "Record #{record["id"]} updated / created"
end
end
I'm getting the following error when I run the import:
(0.9ms) COMMIT
TypeError: no implicit conversion of String into Integer
My gut feeling is because every item in there is a String. How do I go about converting the items or get the insert to ignore column types?
Excerpt of #request
> `[2] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections"=>
[{"name"=>"Vocab",
"order"=>0,
"questions"=>
[{"question"=>"rgrthth",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"aa", "correct"=>true, "order"=>0}]},
{"question"=>"uh67jy7k",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"bb", "correct"=>true, "order"=>0}]},
{"question"=>"rgtdyjuyik",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"cc", "correct"=>true, "order"=>0}]}]}]}`
Output from updated code
2.1.0 :040 > Exercise.import!
(0.2ms) SELECT COUNT(*) FROM `exercises` WHERE `exercises`.`week` = 1 AND `exercises`.`exercise_type` = 3 AND `exercises`.`grade_id` = 2
From: /Users/pc-a/Sites/mailbox/app/models/exercise.rb # line 99 Exercise.import!:
92: def self.import!
93: #request = Net::HTTP.get(URI.parse('example.com/output'))
94: #exercises = JSON.parse(#request)
95:
96: #exercises.map(&:with_indifferent_access).each do |e|
97: next if Exercise.exists?(e[:week], e[:exercise_type], e[:grade_id])
98:
=> 99: binding.pry
100:
101:
102: e[:sections_attributes] = e.delete(:sections)
103: e[:sections_attributes].map! do |section_attributes|
104: section_attributes[:questions_attributes] = section_attributes.delete(:questions)
105: section_attributes[:questions_attributes].map! do |question_attributes|
106: question_attributes[:answers_attributes] = question_attributes.delete(:answers)
107: end
108: end
109:
110: binding.pry
111:
112: exercise = Exercise.new(e)
113: if exercise.save
114: puts "Exercise #{exercise.id} created!"
115: else
116: puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
117: end
118: end
119: end
[1] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections"=>
[{"name"=>"Vocab",
"order"=>0,
"questions"=>
[{"question"=>"rgrthth",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"aa", "correct"=>true, "order"=>0}]},
{"question"=>"uh67jy7k",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"bb", "correct"=>true, "order"=>0}]},
{"question"=>"rgtdyjuyik",
"type"=>3,
"order"=>0,
"answers"=>[{"answer"=>"cc", "correct"=>true, "order"=>0}]}]}]}
[2] pry(Exercise)> exit
From: /Users/pc-a/Sites/mailbox/app/models/exercise.rb # line 110 Exercise.import!:
92: def self.import!
93: #request = Net::HTTP.get(URI.parse('example.com/output'))
94: #exercises = JSON.parse(#request)
95:
96: #exercises.map(&:with_indifferent_access).each do |e|
97: next if Exercise.exists?(e[:week], e[:exercise_type], e[:grade_id])
98:
99: binding.pry
100:
101:
102: e[:sections_attributes] = e.delete(:sections)
103: e[:sections_attributes].map! do |section_attributes|
104: section_attributes[:questions_attributes] = section_attributes.delete(:questions)
105: section_attributes[:questions_attributes].map! do |question_attributes|
106: question_attributes[:answers_attributes] = question_attributes.delete(:answers)
107: end
108: end
109:
=> 110: binding.pry
111:
112: exercise = Exercise.new(e)
113: if exercise.save
114: puts "Exercise #{exercise.id} created!"
115: else
116: puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
117: end
118: end
119: end
[1] pry(Exercise)> e
=> {"publish_date"=>"2013-12-11",
"grade_id"=>2,
"exercise_type"=>3,
"week"=>1,
"content"=>"<hr />\r\n\r\nQuestions:\r\n\r\n",
"grammar_list"=>"",
"title_append"=>nil,
"sections_attributes"=>
[[[{"answer"=>"aa", "correct"=>true, "order"=>0}],
[{"answer"=>"bb", "correct"=>true, "order"=>0}],
[{"answer"=>"cc", "correct"=>true, "order"=>0}]]]}
Try the following:
def self.import!
#request = Net::HTTP.get(URI.parse('https://example.com/output'))
#exercises = JSON.parse(#request)
#exercises.map(&:with_indifferent_access).each do |e|
next if Exercise.exists?(name: e[:name]) # or whatever the attribute(s) you use to determine the uniqueness of an Exercise
e[:sections_attributes] = e.delete(:sections)
e[:sections_attributes].map! do |section_attributes|
section_attributes[:questions_attributes] = section_attributes.delete(:questions)
section_attributes[:questions_attributes].map! do |question_attributes|
question_attributes[:answers_attributes] = question_attributes.delete(:answers)
end
end
exercise = Exercise.new(e)
if exercise.save
puts "Exercise #{exercise.id} created!"
else
puts "Could not create Exercise: #{exercise.errors.full_messages.join('; ')}"
end
end
end
end

Lua - Error repeating a function?

I'm working on an 'impossible' game, where you are basically asked a bunch of trick questions.
The first time I run the script, everything works perfectly. If the user decides to play again by typing in 'y', it will re-run the mainScript function. However, the script automatically re-runs the mainScript after finishing it a second time, without taking user input. I might be making a simple mistake, I'm not sure. Here is the script: (Sorry, I know it is kind of long)
math.randomseed(os.time())
local lives = 3
local points = 0
Questions = {
{"What is the magic word?", "A) Please", "B) Abra-Cadabra", "C) Lotion", "D) Cheese", "c"},
{"Does anyone love you?", "A) Yes", "B) No", "C) Everyone loves me!", "D) My mother does", "b"},
{"How many fingers do you have?", "A) None", "B) Eight", "C) Seventeen", "D) Ten", "d"},
{"What is 1 + 1?", "A) Window", "B) Door", "C) Two", "D) That's a stupid question", "a"}
}
savedQuestions = {} --Load the Questions table into savedQuestions
for i, v in pairs(Questions) do
table.insert(savedQuestions, v)
end
function loadTable() --Load the savedQuestions into Questions
for i = 1, #savedQuestions do
table.insert(Questions, savedQuestions[i])
end
end
function waitForStart()
local chk = io.read() tostring(chk)
if (chk:sub(1, 5)):lower() == "start" then
return true
end
waitForStart()
end
function lookForAnswer(ans)
table.remove(Questions, number)
local input = io.read() tostring(input)
if input:lower() == ans then
points = points + 1
return true
end
lives = lives - 1
return false
end
function mainScript()
lives = 3
points = 0
print("Welcome to the Impossible quiz!")
print("Type 'start' when you are ready to begin\n")
waitForStart() io.write("\n")
for i = 1, #Questions do
number = math.random(1, #Questions)
local prob = Questions[number]
local q = prob[1]
local a = prob[6]
print(q)
print(prob[2] .. "\n" .. prob[3] .. "\n" .. prob[4] .. "\n" .. prob[5] .. "\n")
if lookForAnswer(a) then
print("Correct! Points: " .. points .. " Lives: " .. lives .. "\n\n")
else
print("WRONG! Points: " .. points .. " Lives: " .. lives .. "\n\n")
if lives <= 0 then
return false
end
end
end
return true
end
function checkForReplay()
print("Would you like to play again? (Y / N)")
local chk = io.read() tostring(chk)
if (chk:sub(1, 1)):lower() == "y" then
return true
end
return false
end
function checkWin()
if mainScript() then
print("You won!")
print("Points: " .. points .. "\n")
if checkForReplay() then
Questions = {}
loadTable()
mainScript()
else
exit()
end
else
print("You lose!")
print("Points: " .. points .. "\n")
if checkForReplay() then
Questions = {}
loadTable()
mainScript()
else
exit()
end
end
end
while true do
checkWin()
end
You should factor out the "startover" logic into the loop, you would see better. Then you notice how there is common code in both if chunks of your checkWin, factor that out too:
function checkWin()
if mainScript() then
print("You won!")
else
print("You lose!")
end
print("Points: " .. points .. "\n")
if not checkForReplay() then
exit()
end
end
while true do
checkWin()
-- if you get here you have not exited so start over:
Questions = {}
loadTable()
mainScript() -- oops! what's that doing here?
end
Note also that it is better to let the script return than call os.exit() (assuming that is what exit() is in your code -- see for example How to terminate Lua script?):
function checkWin()
if mainScript() then
print("You won!")
else
print("You lose!")
end
print("Points: " .. points .. "\n")
return checkForReplay()
end
local playAgain = checkWin()
while playAgain do
Questions = {}
loadTable()
playAgain = checkWin()
end