Saving data in a command-line game, no database [Ruby] - ruby

I'm making a simple command line game with Ruby and I'm having trouble saving some information without a database/HTTP dynamic.
For example, let's say I have to make a sandwich (in the game). I am presented with an array of ingredients to choose from, like so:
[1] Carrot
[2] Banana
[3] Cheese
[4] Tomato
I cannot hardcode a direct correspondence between number and ingredient because, before that, I was forbidden to use a couple of ingredients, at random (so the complete ingredients array is two items longer). And I don't want to present a list numbered like [1] [2] [4] [6] because it gets confusing.
What I'm doing right now is hardcoding a direct correspondence between a letter and an item, so for Banana press B, for Cheese press C and so on. But it's less than ideal, particularly because this is a pattern used throughout the game, and in some contexts it will get very inconvenient, both for me and the player.
So, is there a better way for me to do this? How can I associate an input with an item of a list that is generated randomly, and also save that information for further use down the line)?

Here's how I solved it:
Mario Zannone's comment made me realize I could use the index of the array elements as an id, whereas I had been looking at the whole thing as if it was sort of just text.
So here's the code I came up with to take advantage of that:
(0...#ingredients.length).each do |i|
puts "[#{i+1}] #{#ingredients[i]}"
end
That way I now have a direct correspondence between element and input with:
choice = gets.chomp.to_i - 1
#selected_ingredient = #ingredients[choice]

Related

Logic for parsing names

I am wanting to solve this problem, but am kind of unsure how to correctly structure the logic for doing this. I am given a list of user names and I am told to find an extracted name for that. So, for example, I'll see a list of user names such as this:
jason
dooley
smith
rob.smith
kristi.bailey
kristi.betty.bailey
kristi.b.bailey
robertvolk
robvolk
k.b.dula
kristidula
kristibettydula
kristibdula
kdula
kbdula
alexanderson
caesardv
joseluis.lopez
jbpritzker
jean-luc.vey
dvandewal
malami
jgarciathome
christophertroethlisberger
How can I then turn each user name into an extracted name? The only parameter I am given is that every user name is guaranteed to have at least a partial person's name.
So for example, kristi.bailey would be turned into "Kristi Bailey"
alexanderson would be turned into "Alex Anderson"
So, the pattern I see is that, if I see a period I will turn that into two strings (possibly a first and last name). If I see three periods then it will be first, middle. The problem I am having trouble finding the logic for is when the name is just clumped up together like alexanderson or jgarciathome. How can I turn that into an extracted name? I was thinking of doing something like if I see 2 consonants and a vowel in a row I would separate the names, but I don't think that'll work.
Any ideas?
I'd use a string.StartsWith method and a string.EndsWith method and determine the maximum overlap on each. As long as it's more than 2 characters, call that the common name. Sort them into buckets based on the common name. It's a naive implementation, but it that's where I'd start.
Example:
string name1 = "kristi.bailey";
string name2 = "kristi.betty.bailey";
// We've got a 6 character overlap for first name:
name2.StartsWith(name1.Substring(0,6)) // this is true
// We've got a 6 character overlap for last name:
name2.EndsWith(name1.Substring(7)) // this is true
HTH!

Active Record Association after ".where" query

I've got three models: Decks, Slots and Cards. I put them together like so...
Decks are made of many slots, each slot contains one card and any one card can show up in a number of different slots.
I modeled it after the "Order - Order Line Item - Product" structure, hope that makes sense.
Anyways, Decks have an integer field called :deck_type, and suppose I want to get all of the decks of a certain type and then see all of their cards. I EXPECT to be able to run this query but I get an error of undefined method 'cards':
Deck.where(:deck_type => 1).cards
To get all decks of type 1 and then spit out their cards. I have an association established of "deck has many cards through slots", and when I call ".cards" on a single deck it works fine to return the cards.
I feel like this should be a pretty basic query - what am I missing?
Thanks in advance for any insight.
The method cards is for one deck only. So the following should work:
Deck.where(deck_type: 1).first.cards
The first will fetch 1 deck.
If you want cards that belong to decks with deck_type 1, then you've got a few options:
Deck.where(deck_type: 1).map(&:cards).flatten.uniq
That will apply the cards method on each found deck and then get all cards. The flatten will make the results into a 1D array and then uniq will ensure that no duplicates are present, if any.
But the following might be faster:
deck_ids = Deck.where(deck_type: 1).pluck(:id)
Card.where(deck_id: deck_ids)
I think it's safe to assume your Card model has a deck_id attribute. From the above, you will fetch only those cards that have deck_id in the deck_ids variable.
Even better however would be the following as it'll be a single database query. Assuming you've got the right associations setup, you can do:
# replace 'decks' with Deck.table_name if necessary
Card.joins(:deck).where(decks: {deck_type: 1})
I hope that last one is self-explanatory.

Parsing one large array into several sub-arrays

I have a list of adjectives (found here), that I would like to be the basis for a "random_adjective(category)" method.
I'm really just taking a stab at this, as my first real attempt at a useful program.
Step 1: Open file, remove formatting. No problem.
list=File.read('adjectivelist')
list.gsub(/\n/, " ")
The next step is to break the string up by category..
list.split(" ")
Now I have an array of every word in the file. Neat. The ones with a tilde before them represent the category names.
Now I would like to break up this LARGE array into several smaller ones, based on category.
I need help with the syntax here, although the pseudocode for this would be something like
Scan the array for an element which begins with a tilde.
Now create a new array based on the name of that element sans the tilde, and ALSO place this "category name" into the "categories" array. Now pull all the elements from the main array, and pop them into the sub-array, until you meet another tilde. Then repeat the process until there are no more elements in the array.
Finally I would pull a random word from the category named in the parameter. If there was no category name matching the parameter, it would return false and exit (this is simply in case I want to add more categories later.)
Tips would be appreciated
You may want to go back and split first time around like this:
categories = list.split(" ~")
Then each list item will start with the category name. This will save you having to go back through your data structure as you suggest. Consider that a tip: sometimes it's better to re-think the start of a coding problem than to head inexorably forwards
The structure you are reaching towards is probably a Hash, where the keys are category names, and the values are arrays of all the matching adjectives. It might look like this:
{
'category' => [ 'word1', 'word2', 'word3' ]
}
So you might do this:
words_in_category = Hash.new
categories.each do |category_string|
cat_name, *words = category_string.split(" ")
words_in_category[cat_name] = words
end
Finally, to pick a random element from an array, Ruby provides a very useful method sample, so you can just do this
words_in_category[ chosen_category ].sample
. . . assuming chosen_category contains the string name of an actual category. I'll leave it to you to figure out how to put this all together and handle errors, bad input etc
Use slice_before:
categories = list.split(" ").slice_before(/~\w+/)
This will create an sub array for each word starting with ~, containing all words before the next matching word.
If this file format is your original and you have freedom to change it, then I recommend you save the data as yaml or json format and read it when needed. There are libraries to do this. That is all. No worry about the mess. Don't spend time reinventing the wheel.

Best data structure for maintaining a list of object-types sorted by frequency

So, I'm going through a long list with different types of things. Let's say that it has names of different kinds of foods. The list might look something like this:
olive
potato
strawberry
potato
potato
strawberry
I want to store each object type and the number of times that object type occurs. Moreover, I cannot enumerate all of the object types in advance. I don't know what all of the foods will be beforehand.
I want to have something like this as the output:
potato (3)
strawberry (2)
olive (1)
Basically, a list of the object types in order of their frequency. What's the best data structure for this? Are there any built-in classes in Java that I could use that would prevent me from having to reinvent the wheel?
You can use HashMap<K,V>
Map<String,int> map = new HashMap<String,int>();
I would use a dictionary-like structure. Then basically your algorithm would look like this:
-Begin Loop
If current element not a key in dictionary:
dictionary(element) -> 0 (Dictionary at key 'element' refers to 0)
Else:
dictionary(element)++ (increment dictionary at key)
Then you could later loop through the keys and find their frequencies.
Michael G.

Storing cvs data for further manipulation using Ruby

I am dealing with a csv file that has some customer information (email, name, address, amount, [shopping_list: item 1, item 2]).
I would like work with the data and produce some labels for printing... as well as to gather some extra information (total amounts, total items 1...)
My main concern is to find the appropriate structure to store the data in ruby for future manipulation. For now I have thought about the following possibilities:
multidimensional arrays: pretty simple to build, but pretty hard to access the data in a beautiful ruby way.
hashes: having the email as key, and storing the information in different hashes (one hash for name, another hash for address, another hash for shopping list...)
(getting the cvs data in to a Database and working with the data from ruby??)
I would really appreciate your advice and guidance!!
Once you have more than a couple pieces of information that you need to group together, it's time to consider moving from a generic hash/array to something more specialized. A good candidate for what you've described is Ruby's struct module:
Customer = Struct.new(:email, :name, :address) # etc.
bill = Customer.new('bill#asdf.com', 'Bill Foo', '123 Bar St.')
puts "#{bill.name} lives at #{bill.address} and can be reached at #{bill.email}"
Output:
Bill Foo lives at 123 Bar St. and can be reached at bill#asdf.com
Struct#new simply creates a class with an attr_accessor for each symbol you pass in. Well, it actually creates a bit more than that, but for starters, that's all you need to worry about.
Once you've got the data from each row packed into an object of some sort (whether it's a struct or a class of your own), then you can worry about how to store those objects.
A hash will be ideal for random access by a given key (perhaps the customer's name or other unique ID)
A one-dimensional array works fine for iterating over the entire set of customers in the same order they were inserted

Resources