diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..72bf4d3 Binary files /dev/null and b/.DS_Store differ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..10f2f39 --- /dev/null +++ b/.vscode/launch.json @@ -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}" + } + ] +} \ No newline at end of file diff --git a/lib/adagrams.rb b/lib/adagrams.rb index e69de29..d538385 100644 --- a/lib/adagrams.rb +++ b/lib/adagrams.rb @@ -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) + + 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 + # 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) + else + return false + 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 diff --git a/specs/adagrams_spec.rb b/specs/adagrams_spec.rb index ae2ccd0..4d7233c 100644 --- a/specs/adagrams_spec.rb +++ b/specs/adagrams_spec.rb @@ -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,81 +26,89 @@ 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 @@ -108,13 +116,13 @@ 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 @@ -122,13 +130,13 @@ 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 @@ -136,13 +144,13 @@ 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 @@ -150,13 +158,13 @@ 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