Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sockets: Shubha & Grace #4

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
fbed0bc
first version of wave 1 utilizing 26 times loops to gen array
gracemshea Feb 19, 2019
541805b
second version of wave 1, so much prettier
gracemshea Feb 20, 2019
86b08b6
first version of wave 2, succesful return of true and false
gracemshea Feb 20, 2019
c626fff
first version partial wave 3
gracemshea Feb 20, 2019
e2e11a1
Merge branch 'master' of https://github.com/gracemshea/adagrams
gracemshea Feb 20, 2019
347ac6a
Moved adagrams.rb into lib folder
shubha-rajan Feb 20, 2019
0c8ca9e
Wave 3 Partially Complete
gracemshea Feb 20, 2019
287aecc
adds up point totals without accounting for word length
shubha-rajan Feb 20, 2019
89fe603
score_word(word) is functional with no failures
shubha-rajan Feb 20, 2019
4007f5a
Working on Wave 4
gracemshea Feb 21, 2019
b8864b5
wave 4 complete- accurately handles ties
gracemshea Feb 21, 2019
e6d4112
Added comments
shubha-rajan Feb 21, 2019
c58b935
Cleaned up and refactored code
shubha-rajan Feb 21, 2019
d000c4d
Wave 5 complete. Now can test valid English word against external CSV…
gracemshea Feb 22, 2019
04366af
All Waves reviewed, minute adjustments to syntax
gracemshea Feb 22, 2019
b8f677f
added conditions to raise exceptions and wrote test for is_an_english…
shubha-rajan Feb 22, 2019
76687c7
Added conditional argument errors to adagrams.rb and added correspond…
gracemshea Feb 22, 2019
f1581d5
Edited error messages
shubha-rajan Feb 22, 2019
85f3740
added case insensitivity to is_in_english_dict? and uses_available_le…
shubha-rajan Feb 26, 2019
b323c73
used clone method to make uses_available_letters non-destructive
shubha-rajan Feb 28, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Debug Local File",
"type": "Ruby",
"request": "launch",
"cwd": "${workspaceRoot}",
"program": "${file}"
}
]
}
89 changes: 89 additions & 0 deletions lib/adagrams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
require "csv"

# Helper method that creates array of letters that are available to be drawn
def array_gen(hash)
array = []
hash.each do |key, value|
value.times do
array << key.to_s
end
end
return array
end

# Returns an array of 10 letters chosen at random from available letters
def draw_letters
letter_freq = {
A: 9, N: 6, B: 2, O: 8, C: 2, P: 2, D: 4, Q: 1, E: 12, R: 6, F: 2, S: 4,
G: 3, T: 6, H: 2, U: 4, I: 9, V: 2, J: 1, W: 2, K: 1, X: 1, L: 4, Y: 2, M: 2, Z: 1,
}

avail_letters = array_gen(letter_freq)
used_letters = avail_letters.sample(10)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is lovely! I can see everything I need to see about how this works, and if I get confused about array_gen it's close at hand!


return used_letters
end

# Validates input word by determining if it can be formed with letters in hand
def uses_available_letters?(input, letters_in_hand)
if !(input.is_a?(String))
raise ArgumentError, "Ummmmmm the value for the first argument needs to be a string, ok? Given value: #{input}"
elsif !(letters_in_hand.is_a?(Array))
raise ArgumentError, "The second argument should be an array. That doesn't look right...Given value: #{letters_in_hand}"
end
if input.length > letters_in_hand.length
return false
else

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small semantic note: If you don't return above or raise, then you won't hit the code in this else anyway. In cases like this, it's nice to leave the meat of the method outside of an else block.

# reassigning letters_in_hand to new variable in order to avoid destruction of original array
possible_letters = letters_in_hand.clone
input.upcase.split(//).each do |char|
if possible_letters.include?(char)
possible_letters.delete(char)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will never return true for a word with a repeated letter. For example,
ruby hand = ["E", "F", "R", "A", "E", "L", "V", "A", "D", "K"] uses_available_letters?("ADA", hand) # => false
The reason why is that Ruby's Array#delete method will remove all matching elements from an array, not just the first match.

Copy link

@shubha-rajan shubha-rajan Mar 5, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to know!
If we were to write something like:
i = index (char)
possible_letters.delete_at(i)
would it preserve the other repeats of the letter?
And is there a more elegant way of doing it?

else
return false

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work returning when you have the answer!

end
end
end
return true
end

# Scores each word
def score_word(word)
letter_score = {
A: 1, N: 1, B: 3, O: 1, C: 3, P: 3, D: 2, Q: 10, E: 1, R: 1, F: 4, S: 1,
G: 2, T: 1, H: 4, U: 1, I: 1, V: 4, J: 8, W: 4, K: 5, X: 8, L: 1, Y: 4, M: 3, Z: 10,
}

word_score = word.upcase.split(//).reduce(0) do |memo, char|
memo += letter_score[char.to_sym]
end

word_score += 8 if word.length >= 7
return word_score
end

# Returns a single hash that represents the data of a winning word and its score.
def highest_score_from(words)
winner = {
word: "",
score: 0,
}

words.each do |word|
if score_word(word) > winner[:score]
winner = { word: word, score: score_word(word) }
elsif score_word(word) == winner[:score]
if ((word.length < winner[:word].length) || (word.length == 10)) && (winner[:word].length != 10)
winner = { word: word, score: score_word(word) }
end
end
end
return winner
end

# Verifies input word is in the English language CSV file
def is_in_english_dict?(input)
dictionary = CSV.read("assets/dictionary-english.csv")
valid_word = dictionary.include?(input.downcase) ? true : false
return valid_word
end
110 changes: 65 additions & 45 deletions specs/adagrams_spec.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
require 'minitest/autorun'
require 'minitest/reporters'
require 'minitest/skip_dsl'
require "minitest/autorun"
require "minitest/reporters"
require "minitest/skip_dsl"

require_relative '../lib/adagrams'
require_relative "../lib/adagrams"

# Get that nice colorized output
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new

describe 'Adagrams' do
describe 'draw_letters method' do
it 'draws ten letters from the letter pool' do
describe "Adagrams" do
describe "draw_letters method" do
it "draws ten letters from the letter pool" do
drawn_letters = draw_letters
expect(drawn_letters.size).must_equal 10
end

it 'returns an array, and each item is a single-letter string' do
it "returns an array, and each item is a single-letter string" do
drawn_letters = draw_letters
expect(drawn_letters.size).must_equal 10

@@ -26,137 +26,145 @@
end
end

describe 'uses_available_letters? method' do

it 'returns true if the submitted letters are valid against the drawn letters' do
drawn_letters = ['D', 'O', 'G', 'X', 'X', 'X', 'X', 'X', 'X', 'X']
test_word = 'DOG'
describe "uses_available_letters? method" do
it "returns true if the submitted letters are valid against the drawn letters" do
drawn_letters = ["D", "O", "G", "X", "X", "X", "X", "X", "X", "X"]
test_word = "DOG"

is_valid = uses_available_letters? test_word, drawn_letters

expect(is_valid).must_equal true
end

it 'returns false word contains letters not in the drawn letters' do
drawn_letters = ['D', 'O', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X']
test_word = 'DOG'
it "returns false word contains letters not in the drawn letters" do
drawn_letters = ["D", "O", "X", "X", "X", "X", "X", "X", "X", "X"]
test_word = "DOG"

is_valid = uses_available_letters? test_word, drawn_letters

expect(is_valid).must_equal false
end

it 'returns false word contains repeated letters more than in the drawn letters' do
drawn_letters = ['A', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X']
test_word = 'AAA'
it "returns false word contains repeated letters more than in the drawn letters" do
drawn_letters = ["A", "X", "X", "X", "X", "X", "X", "X", "X", "X"]
test_word = "AAA"

is_valid = uses_available_letters? test_word, drawn_letters

expect(is_valid).must_equal false
end

it "raises exception if arguments are invalid type" do
expect {
uses_available_letters?("A", :key)
}.must_raise ArgumentError

expect {
uses_available_letters?(8, ["A", "B", "C", "D", "E", "A", "B", "C", "D", "E"])
}.must_raise ArgumentError
end
end

describe 'score_word method' do
it 'returns an accurate numerical score according to the score chart' do
describe "score_word method" do
it "returns an accurate numerical score according to the score chart" do
expect(score_word("A")).must_equal 1
expect(score_word("DOG")).must_equal 5
expect(score_word("WHIMSY")).must_equal 17
end

it 'returns a score regardless of input case' do
it "returns a score regardless of input case" do
expect(score_word("a")).must_equal 1
expect(score_word("dog")).must_equal 5
expect(score_word("wHiMsY")).must_equal 17
end

it 'returns a score of 0 if given an empty input' do
it "returns a score of 0 if given an empty input" do
expect(score_word("")).must_equal 0
end

it 'adds an extra 8 points if the word is 7 or more characters long' do
it "adds an extra 8 points if the word is 7 or more characters long" do
expect(score_word("XXXXXXX")).must_equal 64
expect(score_word("XXXXXXXX")).must_equal 72
expect(score_word("XXXXXXXXX")).must_equal 80
end
end

describe 'highest_score_from method' do
it 'returns a hash that contains the word and score of best word in an array' do
words = ['X', 'XX', 'XXX', 'XXXX']
describe "highest_score_from method" do
it "returns a hash that contains the word and score of best word in an array" do
words = ["X", "XX", "XXX", "XXXX"]
best_word = highest_score_from words

expect(best_word[:word]).must_equal 'XXXX'
expect(best_word[:word]).must_equal "XXXX"
expect(best_word[:score]).must_equal 32
end

it 'accurately finds best scoring word even if not sorted' do
words = ['XXX', 'XXXX', 'XX', 'X']
it "accurately finds best scoring word even if not sorted" do
words = ["XXX", "XXXX", "XX", "X"]
best_word = highest_score_from words

expect(best_word[:word]).must_equal 'XXXX'
expect(best_word[:word]).must_equal "XXXX"
expect(best_word[:score]).must_equal 32
end

it 'in case of tied score, prefers the word with fewer letters' do
it "in case of tied score, prefers the word with fewer letters" do
# the character 'M' is worth 3 points, 'W' is 4 points
words = ['MMMM', 'WWW']
words = ["MMMM", "WWW"]

# verify both have a score of 12
expect(score_word(words.first)).must_equal 12
expect(score_word(words.last)).must_equal 12

best_word = highest_score_from words

expect(best_word[:word]).must_equal 'WWW'
expect(best_word[:word]).must_equal "WWW"
expect(best_word[:score]).must_equal 12
end

it 'in case of tied score, prefers the word with fewer letters regardless of order' do
it "in case of tied score, prefers the word with fewer letters regardless of order" do
# the character 'M' is worth 3 points, 'W' is 4 points
words = ['WWW', 'MMMM']
words = ["WWW", "MMMM"]

# verify both have a score of 12
expect(score_word(words.first)).must_equal 12
expect(score_word(words.last)).must_equal 12

best_word = highest_score_from words

expect(best_word[:word]).must_equal 'WWW'
expect(best_word[:word]).must_equal "WWW"
expect(best_word[:score]).must_equal 12
end

it 'in case of tied score, prefers most the word with 10 letters' do
it "in case of tied score, prefers most the word with 10 letters" do
# the character 'A' is worth 1 point, 'B' is 3 points
words = ['AAAAAAAAAA', 'BBBBBB']
words = ["AAAAAAAAAA", "BBBBBB"]

# verify both have a score of 10
expect(score_word(words.first)).must_equal 18
expect(score_word(words.last)).must_equal 18

best_word = highest_score_from words

expect(best_word[:word]).must_equal 'AAAAAAAAAA'
expect(best_word[:word]).must_equal "AAAAAAAAAA"
expect(best_word[:score]).must_equal 18
end

it 'in case of tied score, prefers most the word with 10 letters regardless of order' do
it "in case of tied score, prefers most the word with 10 letters regardless of order" do
# the character 'A' is worth 1 point, 'B' is 3 points
words = ['BBBBBB', 'AAAAAAAAAA']
words = ["BBBBBB", "AAAAAAAAAA"]

# verify both have a score of 10
expect(score_word(words.first)).must_equal 18
expect(score_word(words.last)).must_equal 18

best_word = highest_score_from words

expect(best_word[:word]).must_equal 'AAAAAAAAAA'
expect(best_word[:word]).must_equal "AAAAAAAAAA"
expect(best_word[:score]).must_equal 18
end

it 'in case of tied score and same length words, prefers the first word' do
it "in case of tied score and same length words, prefers the first word" do
# the character 'A' is worth 1 point, 'E' is 1 point
words = ['AAAAAAAAAA', 'EEEEEEEEEE']
words = ["AAAAAAAAAA", "EEEEEEEEEE"]

# verify both have a score of 10
expect(score_word(words.first)).must_equal 18
@@ -168,4 +176,16 @@
expect(best_word[:score]).must_equal 18
end
end
describe "is_in_english_dict method" do
it "is a valid English word" do
# Arrange
word = "tyuzxy"

# Act
result = is_in_english_dict?(word)

# Assert
expect(result).must_equal false
end
end
end