diff --git a/.gitignore b/.gitignore index 28f4849..a6313cf 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ build/ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc + +.DS_Store +public/.DS_Store diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..8d65737 --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' + +gem 'sinatra', '~>1.4.7' +gem 'rerun', '~>0.11.0' +gem 'thin', '~>1.6.4' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..30ccb77 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,37 @@ +GEM + remote: https://rubygems.org/ + specs: + daemons (1.2.3) + eventmachine (1.2.0.1) + ffi (1.9.10) + listen (3.0.6) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9.7) + rack (1.6.4) + rack-protection (1.5.3) + rack + rb-fsevent (0.9.7) + rb-inotify (0.9.7) + ffi (>= 0.5.0) + rerun (0.11.0) + listen (~> 3.0) + sinatra (1.4.7) + rack (~> 1.5) + rack-protection (~> 1.4) + tilt (>= 1.3, < 3) + thin (1.6.4) + daemons (~> 1.0, >= 1.0.9) + eventmachine (~> 1.0, >= 1.0.4) + rack (~> 1.0) + tilt (2.0.2) + +PLATFORMS + ruby + +DEPENDENCIES + rerun (~> 0.11.0) + sinatra (~> 1.4.7) + thin (~> 1.6.4) + +BUNDLED WITH + 1.11.2 diff --git a/lib/multiple_scrabble_score.rb b/lib/multiple_scrabble_score.rb new file mode 100644 index 0000000..35f49a7 --- /dev/null +++ b/lib/multiple_scrabble_score.rb @@ -0,0 +1,59 @@ +class ScrabbleMultiple + LETTER_SCORES = {"a"=>1, "b"=>3, "c"=>3, "d"=>2, "e"=>1, "f"=>4, "g"=>2, + "h"=>4, "i"=>1, "j"=>8, "k"=>5, "l"=>1, "m"=>3, "n"=>1, "o"=>1, "p"=>3, + "q"=>10, "r"=>1, "s"=>1, "t"=>1, "u"=>1, "v"=>4, "w"=>4, "x"=>8, "y"=>4, + "z"=>10} + BONUS_NUMBER_OF_LETTERS = 7 + + attr_reader :bonus + + def initialize(words_array, bonus) + @words = words_array + @bonus = bonus + end + + def score_many(words = @words) + scores = words.collect do |word| + score(word) + end + end + + def points_many_words(words = @words) + words_collection = {} + letter_points = words.each do |word| + words_collection[word] = points_by_letter(word) + end + return words_collection + end + + def score(word) # takes a string + return 0 if word.empty? # empty string/pass + + score = 0 + + #Add bonus for word_length corner case. + score = 50 if (bonus == "true" && word.length == BONUS_NUMBER_OF_LETTERS) + + split_word = word.downcase.split('') # downcase for comparing + + split_word.each do |letter| + score += LETTER_SCORES[letter] + end + + return score + end + + def points_by_letter(word) + return 0 if word.empty? + + split_word = word.downcase.split('') # downcase for comparing + + letter_points = split_word.collect do |letter| + LETTER_SCORES[letter] + end + + return split_word.zip(letter_points) + + end + +end diff --git a/lib/scoring.rb b/lib/scoring.rb new file mode 100644 index 0000000..b4809eb --- /dev/null +++ b/lib/scoring.rb @@ -0,0 +1,82 @@ +module Scrabble + class Scoring + LETTER_SCORES = {"a"=>1, "b"=>3, "c"=>3, "d"=>2, "e"=>1, "f"=>4, "g"=>2, + "h"=>4, "i"=>1, "j"=>8, "k"=>5, "l"=>1, "m"=>3, "n"=>1, "o"=>1, "p"=>3, + "q"=>10, "r"=>1, "s"=>1, "t"=>1, "u"=>1, "v"=>4, "w"=>4, "x"=>8, "y"=>4, + "z"=>10} + + + def self.score(word) # takes a string + return 0 if word.empty? # empty string/pass + + score = 0 + + #Add bonus for word_length corner case. + score = 50 if word.length == Scrabble::MAXIMUM_NUMBER_OF_LETTERS + + split_word = word.downcase.split('') # downcase for comparing + + split_word.each do |letter| + score += LETTER_SCORES[letter] + end + + return score + end + + def self.highest_score_from(array_of_words) + + score_array = array_of_words.collect { |word| self.score(word) } + + number_of_highest_scores = self.get_number_of_duplicates(score_array.sort.reverse) + # sort gives ascending + # reverse for descending to compare HIGHEST scores + + highest_scoring_words = array_of_words.max_by(number_of_highest_scores) { |word| self.score(word) } + + return highest_scoring_words[0].to_s if highest_scoring_words.length == 1 + + words_by_length = highest_scoring_words.min_by(number_of_highest_scores) { |word| word.length } + #shortest first - sorting WORDS by length (to analyze ties) + + lengths_of_words = words_by_length.collect { |word| word.length } + + if lengths_of_words.last == MAXIMUM_NUMBER_OF_LETTERS + if self.has_duplicates?(lengths_of_words.reverse) # reverse to change ascending to descending because WORD_LENGTH_MAXIMUM is the longest we expect + winning_word = self.get_first_word_for_length_and_score(lengths_of_words.reverse, words_by_length, array_of_words) + return winning_word + end + + return words_by_length.last + + elsif self.has_duplicates?(lengths_of_words) # we do want this in ascending order because normally smaller words win (based on rules) + winning_word = self.get_first_word_for_length_and_score(lengths_of_words, words_by_length, array_of_words) + return winning_word + else + words_by_length.first + end + end + + def self.has_duplicates?(array_of_words) + self.get_number_of_duplicates(array_of_words) > 1 ? true : false + end + + def self.get_first_word_for_length_and_score(array_of_equal_lengths, high_scores_array, original_array) + + number_of_ties_same_length = self.get_number_of_duplicates(array_of_equal_lengths) + potential_winners = high_scores_array.first(number_of_ties_same_length) + winning_word = original_array.find { |word| potential_winners.include? word } + return winning_word + end + + def self.get_number_of_duplicates(array_of_words) + i = 1 + array_of_words_x = array_of_words.dup # prevents mutation of array_of_words from shift + while (array_of_words_x[0] == array_of_words_x[1]) && (array_of_words_x.length > 1) + array_of_words_x.shift + i +=1 + end + return i + end + + end +end diff --git a/lib/scrabble_score.rb b/lib/scrabble_score.rb new file mode 100644 index 0000000..25d8632 --- /dev/null +++ b/lib/scrabble_score.rb @@ -0,0 +1,29 @@ +class Scrabble + LETTER_SCORES = {"a"=>1, "b"=>3, "c"=>3, "d"=>2, "e"=>1, "f"=>4, "g"=>2, + "h"=>4, "i"=>1, "j"=>8, "k"=>5, "l"=>1, "m"=>3, "n"=>1, "o"=>1, "p"=>3, + "q"=>10, "r"=>1, "s"=>1, "t"=>1, "u"=>1, "v"=>4, "w"=>4, "x"=>8, "y"=>4, + "z"=>10} + MAXIMUM_NUMBER_OF_LETTERS = 7 + + def initialize(options = {}) + @word = options["word"] + end + + def score(word = @word) # takes a string + return 0 if word.empty? # empty string/pass + + score = 0 + + #Add bonus for word_length corner case. + score = 50 if word.length == MAXIMUM_NUMBER_OF_LETTERS + + split_word = word.downcase.split('') # downcase for comparing + + split_word.each do |letter| + score += LETTER_SCORES[letter] + end + + return score + end + +end diff --git a/public/images/nature_scrabble.jpg b/public/images/nature_scrabble.jpg new file mode 100644 index 0000000..86b7c59 Binary files /dev/null and b/public/images/nature_scrabble.jpg differ diff --git a/public/images/typography_Scrabble.jpg b/public/images/typography_Scrabble.jpg new file mode 100644 index 0000000..5c43cc6 Binary files /dev/null and b/public/images/typography_Scrabble.jpg differ diff --git a/public/stylesheets/styles.css b/public/stylesheets/styles.css new file mode 100644 index 0000000..560cb79 --- /dev/null +++ b/public/stylesheets/styles.css @@ -0,0 +1,158 @@ +html { + /* size | family */ + font: 16px "Geneva", "Arial", sans-serif; + color: rgba(11, 11, 11, 1); + margin: 0; +} + +h1 { + margin: 0; +} + +h2 { + margin: 1rem; +} + +a { + text-decoration: none; + display: inline-block; + margin: .5rem; + color: rgba(11, 11, 11, 1); +} + +a:hover { + /* offset-x | offset-y | blur-radius | color */ + text-shadow: 1px 1px 2px rgba(11, 11, 11, .6); +} + +.nav-links { + /*specific to links in navigation so they appear on one line*/ + display: inline-block; + float: left; +} + +/*large rectangle/square elements to have shadow styling like background tiles*/ +.tile-style { + background: rgb(216, 187, 147); + /*for browsers that do not support gradients*/ + background: linear-gradient(to bottom right, rgba(225, 205, 168, 1), rgba(209, 180, 124, .8) 40%); + display: inline-block; + /* offset-x | offset-y | blur-radius | spread-radius | color */ + box-shadow: 0.1rem .1rem 0.2rem 0.1rem rgba(255, 253, 230, .8), 0.25rem .25rem 0.1rem 0.25rem rgba(109, 97, 83, 1), .5rem .5rem 0.1rem 0.5rem rgba(11, 11, 11, 1); + text-align: center; + border-radius: .1rem; +} + +header.tile-style { + display:block; + padding: .5rem; + position:fixed; + top:-6rem; + opacity:.76; + transition:all 1s ease; + text-align: center; +} + +header.tile-style:hover { + opacity:1; + top:0rem; + transition:all 1s ease; +} + +main.tile-style { + display: flex; + justify-content: center; + position: absolute; + bottom: 10%; + top: 10%; + left: 65%; + padding: 3rem; + overflow: auto; +} + +/*styling for user forms */ +label { + display: list-item; + list-style: none; + padding: .25rem; + vertical-align: middle; +} + +input { + margin: .25rem; + padding: .5rem .6rem; + display: inline-block; + border: 0.1rem solid rgba(255, 253, 230, .8); + border-radius: .1rem; + background: rgba(255,253,230,0.4); + vertical-align: middle; +} + +input.scrabble-button { + /*shadowing like scrabble tile on buttons*/ + box-shadow: 0.1rem .1rem 0.1rem 0.1rem rgba(255, 253, 230, .8), 0.2rem .2rem 0.2rem 0.2rem rgba(109, 97, 83, 1), .25rem .25rem 0.25rem 0.25rem rgba(11, 11, 11, 1); + margin-top: 1.5rem; + margin-bottom: .5rem; +} + +/* letter scoring output for user words to look like scrabble tile*/ +ul { + list-style: none; + text-align: center; + padding: 0; +} + +.letter-tile { + display: inline-block; + border: .15rem groove rgba(11, 11, 11, 1); + line-height: 2rem; + min-height: 2rem; + min-width: 2rem; + padding: .25rem; +} + +.letter-tile .letter { + font-weight: bold; + margin-left: .5rem; +} + +.letter-tile .points { + margin-top: .5rem; + margin-bottom: -.5rem; + font-size: .75rem; + display: block; + float: right; +} + +/*footer styling*/ +footer { + position: fixed; + text-align: center; + width: 100%; + bottom: 3%; +} + +footer > p { + color: rgba(225,205, 168, .76); +} + +/*background styling*/ +.background { + position: fixed; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + z-index: -2; +} + +.background img { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + margin: auto; + min-width: 50%; + min-height: 50%; +} diff --git a/scrabble_app.rb b/scrabble_app.rb new file mode 100644 index 0000000..3d48627 --- /dev/null +++ b/scrabble_app.rb @@ -0,0 +1,38 @@ +require 'sinatra' +require_relative 'lib/scrabble_score' +require_relative 'lib/multiple_scrabble_score' + +class ScrabbleScore < Sinatra::Base + + get '/' do + erb :index + end + + get '/score' do + erb :score + end + + post '/score' do + # project specs: only score-many will be able to select bonus/no bonus + @user_input = ScrabbleMultiple.new(params["words"], "true") + + erb :score + end + + get '/score-many' do + erb :score_many + end + + post '/score-many' do + + unless params["words"].nil? + @user_input = ScrabbleMultiple.new(params["words"], params["bonus"]) + end + + @quantity = params["quantity"].to_i + + erb :score_many + end + + run! +end diff --git a/views/index.erb b/views/index.erb new file mode 100644 index 0000000..5d5bd3c --- /dev/null +++ b/views/index.erb @@ -0,0 +1,3 @@ + +

Score One Word

+

Score Many Words

diff --git a/views/layout.erb b/views/layout.erb new file mode 100644 index 0000000..5561a31 --- /dev/null +++ b/views/layout.erb @@ -0,0 +1,36 @@ + + + + + + + Sinatra Scrabble + + + + +
+

Sinatra Scrabble

+ Score One Word + Score Many Words +
+ +
+
+ <%= yield %> +
+
+ +
+ +
+ + + + + + diff --git a/views/score.erb b/views/score.erb new file mode 100644 index 0000000..a527f11 --- /dev/null +++ b/views/score.erb @@ -0,0 +1,17 @@ +

Score One Word

+ +<%# display word that user scored. %> +<%= erb(:word_scoring) %> + +<%# prompt user for word to score %> +<% if !@user_input %> +
+ + + + +
+<% end %> + +Start Over diff --git a/views/score_many.erb b/views/score_many.erb new file mode 100644 index 0000000..55011b3 --- /dev/null +++ b/views/score_many.erb @@ -0,0 +1,32 @@ + +

Score Many Words

+ +<%# display scored used words %> +<%= erb(:word_scoring) %> + +<%# display prompt for user word input %> +<% if @quantity && !@user_input %> +
+ +
+ Game Options + + +
+ + <% @quantity.times do |word_input| %> + + <% end %> + +
+<% end %> + +<%# prompt user for number of words to score %> +<% if !@user_input && !@quantity %> +
+ + +
+<% end %> + +Start Over diff --git a/views/word_scoring.erb b/views/word_scoring.erb new file mode 100644 index 0000000..52cdb88 --- /dev/null +++ b/views/word_scoring.erb @@ -0,0 +1,18 @@ + +<% # scoring partial %> +<% if @user_input %> + <% scores = @user_input.score_many %> + <% each_letter_points = @user_input.points_many_words %> + + <% words = params["words"] %> + <% words.zip(scores).each do |word , score| %> + <% next if word.empty? %> + <%= "#{word.upcase} has a score of #{score}." %> + + <% end %> +<% end %>