loading...

Daily Challenge #8 - Scrabble Word Calculator

thepracticaldev profile image dev.to staff ・2 min read

Daily Challenge (273 Part Series)

1) Daily Challenge #1 - String Peeler 2) Daily Challenge #2 - String Diamond 3 ... 271 3) Daily Challenge #3 - Vowel Counter 4) Daily Challenge #4 - Checkbook Balancing 5) Daily Challenge #5 - Ten Minute Walk 6) Daily Challenge #6 - Grandma and her friends 7) Daily Challenge #7 - Factorial Decomposition 8) Daily Challenge #8 - Scrabble Word Calculator 9) Daily Challenge #9 - What's Your Number? 10) Daily Challenge #10 - Calculator 11) Daily Challenge #11 - Cubic Numbers 12) Daily Challenge #12 - Next Larger Number 13) Daily Challenge #13 - Twice Linear 14) Daily Challenge #14 - Square into Squares 15) Daily Challenge #15 - Stop gninnipS My sdroW! 16) Daily Challenge #16 - Number of People on the Bus 17) Daily Challenge #17 - Double Trouble 18) Daily Challenge #18 - Triple Trouble 19) Daily Challenge #19 - Turn numbers into words 20) Daily Challenge Post #20 - Number Check 21) Daily Challenge #21 - Human Readable Time 22) Daily Challenge #22 - Simple Pig Latin 23) Daily Challenge #23 - Morse Code Decoder 24) Daily Challenge #24 - Shortest Step 25) Daily Challenge #25 - Double Cola 26) Daily Challenge #26 - Ranking Position 27) Daily Challenge #27 - Unlucky Days 28) Daily Challenge #28 - Kill the Monster! 29) Daily Challenge #29 - Xs and Os 30) Daily Challenge #30 - What is the price? 31) Daily Challenge #31 - Count IPv4 Addresses 32) Daily Challenge #32 - Hide Phone Numbers 33) Daily Challenge #33 - Did you mean...? 34) Daily Challenge #34 - WeIrD StRiNg CaSe 35) Daily Challenge #35 - Find the Outlier 36) Daily Challenge #36 - Let's go for a run! 37) Daily Challenge #37 - Name Swap 38) Daily Challenge #38 - Middle Name 39) Daily Challenge #39 - Virus 40) Daily Challenge #40 - Counting Sheep 41) Daily Challenge #41 - Greed is Good 42) Daily Challenge #42 - Caesar Cipher 43) Daily Challenge #43 - Boardgame Fight Resolver 44) Daily Challenge #44 - Mexican Wave 45) Daily Challenge #45 - Change Machine 46) Daily Challenge #46 - ??? 47) Daily Challenge #47 - Alphabets 48) Daily Challenge #48 - Facebook Likes 49) Daily Challenge #49 - Dollars and Cents 50) Daily Challenge #50 - Number Neighbor 51) Daily Challenge #51 - Valid Curly Braces 52) Daily Challenge #52 - Building a Pyramid 53) Daily Challenge #53 - Faro Shuffle 54) Daily Challenge #54 - What century is it? 55) Daily Challenge #55 - Building a Pile of Cubes 56) Daily Challenge #56 - Coffee Shop 57) Daily Challenge #57 - BMI Calculator 58) Daily Challenge #58 - Smelting Iron Ingots 59) Daily Challenge #59 - Snail Sort 60) Daily Challenge #60 - Find the Missing Letter 61) Daily Challenge #61 - Evolution Rate 62) Daily Challenge #62 - Josephus Survivor 63) Daily Challenge #63- Two Sum 64) Daily Challenge #64- Drying Potatoes 65) Daily Challenge #65- A Disguised Sequence 66) Daily Challenge #66- Friend List 67) Daily Challenge #67- Phone Directory 68) Daily Challenge #68 - Grade Book 69) Daily Challenge #69 - Going to the Cinema 70) Daily Challenge #70 - Pole Vault Competition Results 71) Daily Challenge #71 - See you next Happy Year 72) Daily Challenge #72 - Matrix Shift 73) Daily Challenge #73 - ATM Heist 74) Daily Challenge #74 - Free Pizza 75) Daily Challenge #75 - Set Alarm 76) Daily Challenge #76 - Bingo! (or not...) 77) Daily Challenge #77 - Bird Mountain 78) Daily Challenge #78 - Number of Proper Fractions with Denominator d 79) Daily Challenge #79 - Connect Four 80) Daily Challenge #80 - Longest Vowel Change 81) Daily Challenge #81 - Even or Odd 82) Daily Challenge #82 - English Beggars 83) Daily Challenge #83 - Deodorant Evaporator 84) Daily Challenge #84 - Third Angle of a Triangle 85) Daily Challenge #85 - Unwanted Dollars 86) Daily Challenge #86 - Wouldn't, not Would. 87) Daily Challenge #87 - Pony Express 88) Daily Challenge #88 - Recursive Ninjas 89) Daily Challenge #89 - Extract domain name from URL 90) Daily Challenge #90 - One Step at a Time 91) Daily Challenge #91 - Bananas 92) Daily Challenge #92 - Boggle Board 93) Daily Challenge #93 - Range Extraction 94) Daily Challenge #94 - Last Digit 95) Daily Challenge #95 - CamelCase Method 96) Daily Challenge #96 - Easter Egg Crush Test 97) Daily Challenge #97 - Greed is Good 98) Daily Challenge #98 - Make a Spiral 99) Daily Challenge #99 - Balance the Scales 100) Daily Challenge #100 - Round Up 101) Daily Challenge #101 - Parentheses Generator 102) Daily Challenge #102 - Pentabonacci 103) Daily Challenge #103 - Simple Symbols 104) Daily Challenge #104 - Matrixify 105) Daily Challenge #105 - High-Sum Matrix Drop 106) Daily Challenge #106 - Average Fuel Consumption 107) Daily Challenge #107 - Escape the Mines 108) Daily Challenge #108 - Find the Counterfeit Coin 109) Daily Challenge #109 - Decorate with Wallpaper 110) Daily Challenge #110 - Love VS. Friendship 111) Daily Challenge #111 - 99 Bottles of Beer 112) Daily Challenge #112 - Functions of Integers on the Cartesian Plane 113) Daily Challenge #113 - Iterative Rotation Cipher 114) Daily Challenge #114 - Speed Control 115) Daily Challenge #115 - Look and Say Sequence 116) Daily Challenge #116 - Shortest Knight Path 117) Daily Challenge #117 - MinMinMax 118) Daily Challenge #118 - Reversing a Process 119) Daily Challenge #119 - Adding Big Numbers 120) Daily Challenge #120 - Growth of a Population 121) Daily Challenge #121 - Who has the most money? 122) Daily Challenge #122 - Clockwise Spirals 123) Daily Challenge #123 - Curry me Softly 124) Daily Challenge #124 - Middle Me 125) Daily Challenge #125 - 23 Matches or More 126) Daily Challenge #126 - The Supermarket Line 127) Daily Challenge #127 - Playing with Passphrases 128) Daily Challenge #128 - Blackjack Scorer 129) Daily Challenge #129 - Clay Pigeon Shooting 130) Daily Challenge #130 - GCD Sum 131) Daily Challenge #131 - Remove Anchor from URL 132) Daily Challenge #132 - Is my friend cheating? 133) Daily Challenge #133 - Suitcase Packing 134) Daily Challenge #134 - Rice and Chessboard Problem 135) Daily Challenge #135 - The Wide Mouthed Frog! 136) Daily Challenge #136 - The Deaf Rats of Hamelin 137) Daily Challenge #137 - Help the Bookseller 138) Daily Challenge #138 - Do I get a Bonus? 139) Daily Challenge #138 - Keep Up the Hoop 140) Daily Challenge #140 - I love you, a little, a lot, passionately ... not at all 141) Daily Challenge #141 - Two Sum 142) Daily Challenge #142 - Parts of a Whole 143) Daily Challenge #143 - Big Arithmetic 144) Daily Challenge #144 - Box Office Clerk 145) Daily Challenge #145 - SET Card Game 146) Daily Challenge #146 - The Dollar Game 147) Daily Challenge #147 - NIM 148) Daily Challenge #148 - Disemvowel Trolls 149) Daily Challenge #149 - Fun with Lamps 150) Daily Challenge #150 - Boggle Guess Validator 151) Daily Challenge #151 - Reverse Parentheses 152) Daily Challenge #152 - Strongest Number in an Interval 153) Daily Challenge #153 - Horse Race Gamble 154) Daily Challenge #154 - Stable Arrangement 155) Daily Challenge #155 - Royal Arranged Marriages 156) Daily Challenge #162 - Taxi Dispatching 157) Daily Challenge #163 - Significant Figures 158) Daily Challenge #164 - Jump 159) Daily Challenge #165 - Password Lost in a Grid 160) Daily Challenge #166 - Cat and Mouse 161) Daily Challenge #167 - Return String As Sorted Blocks 162) Daily Challenge #168 - [Code golf] f (f (f b)) = f b 163) Daily Challenge #169 - Christmas Tree 164) Daily Challenge #170 - Pokemon Damage Calculator 165) Daily Challenge #171 - Ordering Beers in Poland 166) Daily Challenge #172 - Find All in an Array 167) Daily Challenge #173 - Pandemia 168) Daily Challenge #174 - Soccer League Table 169) Daily Challenge #175 - Complementary DNA 170) Daily Challenge #176 - Loopover 171) Daily Challenge #177 - Supersize Me 172) Daily Challenge #178 - Create Phone Numbers 173) Daily Challenge #179 - Hide Phone Numbers 174) Daily Challenge #180 - SMS Shortener 175) Daily Challenge #181 - Is King in Check? 176) Daily Challenge #182 - Arrh, grabscrab! 177) Daily Challenge #183 - Automorphic Numbers 178) Daily Challenge #184 - Form the Minimum 179) Daily Challenge #185 - House Numbers Sum 180) Daily Challenge #186 - Jumping Frog 181) Daily Challenge #187 - Most Sales 182) Daily Challenge #188 - Break camelCase 183) Daily Challenge #189 - Convert Number into Reversed Array 184) Daily Challenge #190 - capitalizeFirstLast 185) Daily Challenge #191 - Alphabetical Addition 186) Daily Challenge #192 - Can you Survive the Zombies? 187) Daily Challenge #193 - What's the Real Floor? 188) Daily Challenge #194 - Spread Number 189) Daily Challenge #195 - No Zeroes for Heroes 190) Daily Challenge #196 - Flou 191) Daily Challenge #197 - Population Growth 192) Daily Challenge #198 - 21 Blackjack 193) Daily Challenge #199 - List of All Rationals 194) Daily Challenge #200 - Longest Linear Palindromic Substring 195) Daily Challenge #201 - Complete the Pattern 196) Daily Challenge #202 - Complete the Pattern II 197) Daily Challenge #203 - Pascal's Triangle 198) Daily Challenge #204 - Partial Keys 199) Daily Challenge #205 - Consonant String Value 200) Daily Challenge #206 - Pound Means Backspace 201) Daily Challenge #207 - Snakes and Ladders 202) Daily Challenge #208 - Delete Occurrences of an Element 203) Daily Challenge #209 - Roman Numerals 204) Daily Challenge #210 - Separate Capitalization 205) Daily Challenge #211 - Product Partitions 206) Daily Challenge #212 - DNA to RNA 207) Daily Challenge #213 - Are they the "same"? 208) Daily Challenge #214 - Persistent Bugger 209) Daily Challenge #215 - Difference of 2 210) Daily Challenge #216 - Rainfall 211) Daily Challenge #217 - SMS w/ an Old Phone 212) Daily Challenge #218 - Possible Sides of a Non-Right Triangle 213) Daily Challenge #219 - Compare Strings 214) Daily Challenge #220 - What Dominates Your Array? 215) Daily Challenge #221 - The Merchant of York 216) Daily Challenge #222 - Parse Bank Account Numbers 217) Daily Challenge #223 - Responsible Drinking 218) Daily Challenge #224 - Password Validator 219) Daily Challenge #225 - Square'n'Sum 220) Daily Challenge #226 - Array to HTML Table 221) Daily Challenge #227 - Android Lock Screen 222) Daily Challenge #228 - Best Profit in Single Sale 223) Daily Challenge #229 - Haiku Validator 224) Daily Challenge #230 - Beeramid 225) Daily Challenge #231 - Perfect Powers 226) Daily Challenge #232 - Regex Pattern 227) Daily Challenge #233 - Get Planet Name by ID 228) Daily Challenge #234 - Happy Birthday! 229) Daily Challenge #235 - Reversing a Process 230) Daily Challenge #236 - RGB to Hex Conversion 231) Daily Challenge #237 - Delete Extra Occurrences 232) Daily Challenge #238 - One is the Loneliest Number 233) Daily Challenge #239 - Graceful Tipping 234) Daily Challenge #240 - ATM 235) Daily Challenge #241 - Tip Calculator 236) Daily Challenge #242 - Expressions Matter 237) Daily Challenge #243 - Redacted! 238) Daily Challenge #244 - Search for Letters 239) Daily Challenge #245 - Sort Santa's Reindeer 240) Daily Challenge #246 - Readable Specification Pattern 241) Daily Challenge #247 - Get Planet Name By ID 242) Daily Challenge #248 - Chinese Numerals 243) Daily Challenge #249 - Incremental Changes 244) Daily Challenge #250 - Last Digit of a Large Number 245) Daily Challenge #251 - Largest Number in a Sequence 246) Daily Challenge #252 - Everybody hates Mondays 247) Daily Challenge #253 - Sort Sentences Pseudo-alphabetically 248) Daily Challenge #254 - The Vowel Code 249) Daily Challenge #255 - Is There an Odd Bit? 250) Daily Challenge #256 - How Many Are Smaller Than I? 251) Daily Challenge #257 - Halving Sum 252) Daily Challenge #258 - Ranking Poker Hands 253) Daily Challenge #259 - Duplicate Encoder 254) Daily Challenge #260 - Subtract the Sum 255) Daily Challenge #261 - Diagonal Strings 256) Daily Challenge #262 - No One Likes Spare Change 257) Daily Challenge #263 - Reverse Words 258) Daily Challenge #264 - Digital Root 259) Daily Challenge #265 - Equal Sides 260) Daily Challenge #266 - Who Likes It? 261) Daily Challenge #267 - Braking Speed 262) Daily Challenge #268 - Swapping Characters in Strings 263) Daily Challenge #269 - Decompose n! 264) Daily Challenge #270 - Fix String Case 265) Daily Challenge #271 - Simulate Population Growth 266) Daily Challenge #272 - Printer Errors 267) Daily Challenge #273 - Remove Duplicates 268) Daily Challenge #274 - Aerial Firefighting 269) Daily Challenge #275 - Casino Chips 270) Daily Challenge #276 - Unwanted Dollar Signs 271) Daily Challenge #277 - Over the Road 272) Daily Challenge #278 - Find all non-consecutive numbers 273) Daily Challenge #279 - Playing with Sandpiles

Everyone loves a game of Scrabble! Your challenge today is to calculate the scrabble score of a given word.

Scoring per tile:

Here is the scoring per tile

To make things even more challenging, please consider additional scoring as follows:

Double letter (doubles the value of the letter)
-A double letter will be represented with an asterisk after the letter. he*llo would make a double letter on the e.

Triple letter (triples the value of the letter)
-A triple letter will be represented with two asterisks after the letter. he**llo would make a triple letter on the e.

Double word (double the value of the word after letter rules have been applied)
-A double word is represented by the word ending in (d)

Triple word (triple the value of the word after letter rules have been applied)
-A triple word is represented by the word ending in (t)

A blank (the letter given will score 0)
-A blank tile will be represented with a caret after the letter or asterisk is the letter has a double or triple letter value. he^llo would mean the e scores 0.

Bonus 50!
-If the word is a seven letter word an additional 50 points are awarded.

Good luck and happy coding!

This challenge comes from user grantw1991 on Codewars

Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge for a future post? Email yo+challenge@dev.to with your suggestions!

Daily Challenge (273 Part Series)

1) Daily Challenge #1 - String Peeler 2) Daily Challenge #2 - String Diamond 3 ... 271 3) Daily Challenge #3 - Vowel Counter 4) Daily Challenge #4 - Checkbook Balancing 5) Daily Challenge #5 - Ten Minute Walk 6) Daily Challenge #6 - Grandma and her friends 7) Daily Challenge #7 - Factorial Decomposition 8) Daily Challenge #8 - Scrabble Word Calculator 9) Daily Challenge #9 - What's Your Number? 10) Daily Challenge #10 - Calculator 11) Daily Challenge #11 - Cubic Numbers 12) Daily Challenge #12 - Next Larger Number 13) Daily Challenge #13 - Twice Linear 14) Daily Challenge #14 - Square into Squares 15) Daily Challenge #15 - Stop gninnipS My sdroW! 16) Daily Challenge #16 - Number of People on the Bus 17) Daily Challenge #17 - Double Trouble 18) Daily Challenge #18 - Triple Trouble 19) Daily Challenge #19 - Turn numbers into words 20) Daily Challenge Post #20 - Number Check 21) Daily Challenge #21 - Human Readable Time 22) Daily Challenge #22 - Simple Pig Latin 23) Daily Challenge #23 - Morse Code Decoder 24) Daily Challenge #24 - Shortest Step 25) Daily Challenge #25 - Double Cola 26) Daily Challenge #26 - Ranking Position 27) Daily Challenge #27 - Unlucky Days 28) Daily Challenge #28 - Kill the Monster! 29) Daily Challenge #29 - Xs and Os 30) Daily Challenge #30 - What is the price? 31) Daily Challenge #31 - Count IPv4 Addresses 32) Daily Challenge #32 - Hide Phone Numbers 33) Daily Challenge #33 - Did you mean...? 34) Daily Challenge #34 - WeIrD StRiNg CaSe 35) Daily Challenge #35 - Find the Outlier 36) Daily Challenge #36 - Let's go for a run! 37) Daily Challenge #37 - Name Swap 38) Daily Challenge #38 - Middle Name 39) Daily Challenge #39 - Virus 40) Daily Challenge #40 - Counting Sheep 41) Daily Challenge #41 - Greed is Good 42) Daily Challenge #42 - Caesar Cipher 43) Daily Challenge #43 - Boardgame Fight Resolver 44) Daily Challenge #44 - Mexican Wave 45) Daily Challenge #45 - Change Machine 46) Daily Challenge #46 - ??? 47) Daily Challenge #47 - Alphabets 48) Daily Challenge #48 - Facebook Likes 49) Daily Challenge #49 - Dollars and Cents 50) Daily Challenge #50 - Number Neighbor 51) Daily Challenge #51 - Valid Curly Braces 52) Daily Challenge #52 - Building a Pyramid 53) Daily Challenge #53 - Faro Shuffle 54) Daily Challenge #54 - What century is it? 55) Daily Challenge #55 - Building a Pile of Cubes 56) Daily Challenge #56 - Coffee Shop 57) Daily Challenge #57 - BMI Calculator 58) Daily Challenge #58 - Smelting Iron Ingots 59) Daily Challenge #59 - Snail Sort 60) Daily Challenge #60 - Find the Missing Letter 61) Daily Challenge #61 - Evolution Rate 62) Daily Challenge #62 - Josephus Survivor 63) Daily Challenge #63- Two Sum 64) Daily Challenge #64- Drying Potatoes 65) Daily Challenge #65- A Disguised Sequence 66) Daily Challenge #66- Friend List 67) Daily Challenge #67- Phone Directory 68) Daily Challenge #68 - Grade Book 69) Daily Challenge #69 - Going to the Cinema 70) Daily Challenge #70 - Pole Vault Competition Results 71) Daily Challenge #71 - See you next Happy Year 72) Daily Challenge #72 - Matrix Shift 73) Daily Challenge #73 - ATM Heist 74) Daily Challenge #74 - Free Pizza 75) Daily Challenge #75 - Set Alarm 76) Daily Challenge #76 - Bingo! (or not...) 77) Daily Challenge #77 - Bird Mountain 78) Daily Challenge #78 - Number of Proper Fractions with Denominator d 79) Daily Challenge #79 - Connect Four 80) Daily Challenge #80 - Longest Vowel Change 81) Daily Challenge #81 - Even or Odd 82) Daily Challenge #82 - English Beggars 83) Daily Challenge #83 - Deodorant Evaporator 84) Daily Challenge #84 - Third Angle of a Triangle 85) Daily Challenge #85 - Unwanted Dollars 86) Daily Challenge #86 - Wouldn't, not Would. 87) Daily Challenge #87 - Pony Express 88) Daily Challenge #88 - Recursive Ninjas 89) Daily Challenge #89 - Extract domain name from URL 90) Daily Challenge #90 - One Step at a Time 91) Daily Challenge #91 - Bananas 92) Daily Challenge #92 - Boggle Board 93) Daily Challenge #93 - Range Extraction 94) Daily Challenge #94 - Last Digit 95) Daily Challenge #95 - CamelCase Method 96) Daily Challenge #96 - Easter Egg Crush Test 97) Daily Challenge #97 - Greed is Good 98) Daily Challenge #98 - Make a Spiral 99) Daily Challenge #99 - Balance the Scales 100) Daily Challenge #100 - Round Up 101) Daily Challenge #101 - Parentheses Generator 102) Daily Challenge #102 - Pentabonacci 103) Daily Challenge #103 - Simple Symbols 104) Daily Challenge #104 - Matrixify 105) Daily Challenge #105 - High-Sum Matrix Drop 106) Daily Challenge #106 - Average Fuel Consumption 107) Daily Challenge #107 - Escape the Mines 108) Daily Challenge #108 - Find the Counterfeit Coin 109) Daily Challenge #109 - Decorate with Wallpaper 110) Daily Challenge #110 - Love VS. Friendship 111) Daily Challenge #111 - 99 Bottles of Beer 112) Daily Challenge #112 - Functions of Integers on the Cartesian Plane 113) Daily Challenge #113 - Iterative Rotation Cipher 114) Daily Challenge #114 - Speed Control 115) Daily Challenge #115 - Look and Say Sequence 116) Daily Challenge #116 - Shortest Knight Path 117) Daily Challenge #117 - MinMinMax 118) Daily Challenge #118 - Reversing a Process 119) Daily Challenge #119 - Adding Big Numbers 120) Daily Challenge #120 - Growth of a Population 121) Daily Challenge #121 - Who has the most money? 122) Daily Challenge #122 - Clockwise Spirals 123) Daily Challenge #123 - Curry me Softly 124) Daily Challenge #124 - Middle Me 125) Daily Challenge #125 - 23 Matches or More 126) Daily Challenge #126 - The Supermarket Line 127) Daily Challenge #127 - Playing with Passphrases 128) Daily Challenge #128 - Blackjack Scorer 129) Daily Challenge #129 - Clay Pigeon Shooting 130) Daily Challenge #130 - GCD Sum 131) Daily Challenge #131 - Remove Anchor from URL 132) Daily Challenge #132 - Is my friend cheating? 133) Daily Challenge #133 - Suitcase Packing 134) Daily Challenge #134 - Rice and Chessboard Problem 135) Daily Challenge #135 - The Wide Mouthed Frog! 136) Daily Challenge #136 - The Deaf Rats of Hamelin 137) Daily Challenge #137 - Help the Bookseller 138) Daily Challenge #138 - Do I get a Bonus? 139) Daily Challenge #138 - Keep Up the Hoop 140) Daily Challenge #140 - I love you, a little, a lot, passionately ... not at all 141) Daily Challenge #141 - Two Sum 142) Daily Challenge #142 - Parts of a Whole 143) Daily Challenge #143 - Big Arithmetic 144) Daily Challenge #144 - Box Office Clerk 145) Daily Challenge #145 - SET Card Game 146) Daily Challenge #146 - The Dollar Game 147) Daily Challenge #147 - NIM 148) Daily Challenge #148 - Disemvowel Trolls 149) Daily Challenge #149 - Fun with Lamps 150) Daily Challenge #150 - Boggle Guess Validator 151) Daily Challenge #151 - Reverse Parentheses 152) Daily Challenge #152 - Strongest Number in an Interval 153) Daily Challenge #153 - Horse Race Gamble 154) Daily Challenge #154 - Stable Arrangement 155) Daily Challenge #155 - Royal Arranged Marriages 156) Daily Challenge #162 - Taxi Dispatching 157) Daily Challenge #163 - Significant Figures 158) Daily Challenge #164 - Jump 159) Daily Challenge #165 - Password Lost in a Grid 160) Daily Challenge #166 - Cat and Mouse 161) Daily Challenge #167 - Return String As Sorted Blocks 162) Daily Challenge #168 - [Code golf] f (f (f b)) = f b 163) Daily Challenge #169 - Christmas Tree 164) Daily Challenge #170 - Pokemon Damage Calculator 165) Daily Challenge #171 - Ordering Beers in Poland 166) Daily Challenge #172 - Find All in an Array 167) Daily Challenge #173 - Pandemia 168) Daily Challenge #174 - Soccer League Table 169) Daily Challenge #175 - Complementary DNA 170) Daily Challenge #176 - Loopover 171) Daily Challenge #177 - Supersize Me 172) Daily Challenge #178 - Create Phone Numbers 173) Daily Challenge #179 - Hide Phone Numbers 174) Daily Challenge #180 - SMS Shortener 175) Daily Challenge #181 - Is King in Check? 176) Daily Challenge #182 - Arrh, grabscrab! 177) Daily Challenge #183 - Automorphic Numbers 178) Daily Challenge #184 - Form the Minimum 179) Daily Challenge #185 - House Numbers Sum 180) Daily Challenge #186 - Jumping Frog 181) Daily Challenge #187 - Most Sales 182) Daily Challenge #188 - Break camelCase 183) Daily Challenge #189 - Convert Number into Reversed Array 184) Daily Challenge #190 - capitalizeFirstLast 185) Daily Challenge #191 - Alphabetical Addition 186) Daily Challenge #192 - Can you Survive the Zombies? 187) Daily Challenge #193 - What's the Real Floor? 188) Daily Challenge #194 - Spread Number 189) Daily Challenge #195 - No Zeroes for Heroes 190) Daily Challenge #196 - Flou 191) Daily Challenge #197 - Population Growth 192) Daily Challenge #198 - 21 Blackjack 193) Daily Challenge #199 - List of All Rationals 194) Daily Challenge #200 - Longest Linear Palindromic Substring 195) Daily Challenge #201 - Complete the Pattern 196) Daily Challenge #202 - Complete the Pattern II 197) Daily Challenge #203 - Pascal's Triangle 198) Daily Challenge #204 - Partial Keys 199) Daily Challenge #205 - Consonant String Value 200) Daily Challenge #206 - Pound Means Backspace 201) Daily Challenge #207 - Snakes and Ladders 202) Daily Challenge #208 - Delete Occurrences of an Element 203) Daily Challenge #209 - Roman Numerals 204) Daily Challenge #210 - Separate Capitalization 205) Daily Challenge #211 - Product Partitions 206) Daily Challenge #212 - DNA to RNA 207) Daily Challenge #213 - Are they the "same"? 208) Daily Challenge #214 - Persistent Bugger 209) Daily Challenge #215 - Difference of 2 210) Daily Challenge #216 - Rainfall 211) Daily Challenge #217 - SMS w/ an Old Phone 212) Daily Challenge #218 - Possible Sides of a Non-Right Triangle 213) Daily Challenge #219 - Compare Strings 214) Daily Challenge #220 - What Dominates Your Array? 215) Daily Challenge #221 - The Merchant of York 216) Daily Challenge #222 - Parse Bank Account Numbers 217) Daily Challenge #223 - Responsible Drinking 218) Daily Challenge #224 - Password Validator 219) Daily Challenge #225 - Square'n'Sum 220) Daily Challenge #226 - Array to HTML Table 221) Daily Challenge #227 - Android Lock Screen 222) Daily Challenge #228 - Best Profit in Single Sale 223) Daily Challenge #229 - Haiku Validator 224) Daily Challenge #230 - Beeramid 225) Daily Challenge #231 - Perfect Powers 226) Daily Challenge #232 - Regex Pattern 227) Daily Challenge #233 - Get Planet Name by ID 228) Daily Challenge #234 - Happy Birthday! 229) Daily Challenge #235 - Reversing a Process 230) Daily Challenge #236 - RGB to Hex Conversion 231) Daily Challenge #237 - Delete Extra Occurrences 232) Daily Challenge #238 - One is the Loneliest Number 233) Daily Challenge #239 - Graceful Tipping 234) Daily Challenge #240 - ATM 235) Daily Challenge #241 - Tip Calculator 236) Daily Challenge #242 - Expressions Matter 237) Daily Challenge #243 - Redacted! 238) Daily Challenge #244 - Search for Letters 239) Daily Challenge #245 - Sort Santa's Reindeer 240) Daily Challenge #246 - Readable Specification Pattern 241) Daily Challenge #247 - Get Planet Name By ID 242) Daily Challenge #248 - Chinese Numerals 243) Daily Challenge #249 - Incremental Changes 244) Daily Challenge #250 - Last Digit of a Large Number 245) Daily Challenge #251 - Largest Number in a Sequence 246) Daily Challenge #252 - Everybody hates Mondays 247) Daily Challenge #253 - Sort Sentences Pseudo-alphabetically 248) Daily Challenge #254 - The Vowel Code 249) Daily Challenge #255 - Is There an Odd Bit? 250) Daily Challenge #256 - How Many Are Smaller Than I? 251) Daily Challenge #257 - Halving Sum 252) Daily Challenge #258 - Ranking Poker Hands 253) Daily Challenge #259 - Duplicate Encoder 254) Daily Challenge #260 - Subtract the Sum 255) Daily Challenge #261 - Diagonal Strings 256) Daily Challenge #262 - No One Likes Spare Change 257) Daily Challenge #263 - Reverse Words 258) Daily Challenge #264 - Digital Root 259) Daily Challenge #265 - Equal Sides 260) Daily Challenge #266 - Who Likes It? 261) Daily Challenge #267 - Braking Speed 262) Daily Challenge #268 - Swapping Characters in Strings 263) Daily Challenge #269 - Decompose n! 264) Daily Challenge #270 - Fix String Case 265) Daily Challenge #271 - Simulate Population Growth 266) Daily Challenge #272 - Printer Errors 267) Daily Challenge #273 - Remove Duplicates 268) Daily Challenge #274 - Aerial Firefighting 269) Daily Challenge #275 - Casino Chips 270) Daily Challenge #276 - Unwanted Dollar Signs 271) Daily Challenge #277 - Over the Road 272) Daily Challenge #278 - Find all non-consecutive numbers 273) Daily Challenge #279 - Playing with Sandpiles

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

markdown guide
 

Here's my solution in Perl, along with a few tests.

#!/usr/bin/env perl

use v5.24;
use strict;
use warnings;
use feature qw(signatures);
no warnings "experimental::signatures";
use List::Util qw(sum);
use Carp;

my %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,
);

my %multiplier = ( D => 2, T => 3 );

sub scrabble_score ($word) {
    $word = uc($word);
    my $score = 0;
    my $mult  = 1;
    my $count = 0;

    if ( $word =~ s/\((D|T)\)// ) {
        $mult = $multiplier{$1};
    }

    while ( $word =~ s/([[:alpha:]])(\^|\*{0,2})// ) {
        ++$count;
        $score += ( $2 ne '^' ) * ( $scores{$1} + $scores{$1} * length($2) );
    }

    return ( $score * $mult ) + 50*($count == 7);
}


use Test::More tests => 7;

my $word = "quintessential";
is( scrabble_score($word), 23, "Score for $word is 23" );
$word = "he*llo**";
is( scrabble_score($word), 11, "Score for $word is 11" );
$word = "quintessential(t)";
is( scrabble_score($word), 69, "Score for $word is 69" );
$word = "q^uintessential(t)";
is( scrabble_score($word), 39, "Score for $word is 39" );
$word = "he*llo**(d)";
is( scrabble_score($word), 22, "Score for $word is 22" );
$word = "he^llo**(d)";
is( scrabble_score($word), 18, "Score for $word is 18" );
$word = "wordier(d)";
is( scrabble_score($word), 72, "Score for $word is 72" );

Edit: fixed a bug, stray print, and added the 7 letter bonus

 

Erlang:

-module(devto8).
-export([scrabble_score/1]).

scrabble_score(Input) ->
    LS = #{$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},
    LCInput = string:lowercase(Input),
    score_word(LS, LCInput, []).

score_word(_, [], Scores) when length(Scores) == 7 ->
    score_sum(Scores) + 50;
score_word(_, [$(,$t,$)], Scores) when length(Scores) == 7 ->
    score_sum(Scores) * 3 + 50;
score_word(_, [$(,$d,$)], Scores) when length(Scores) == 7 ->
    score_sum(Scores) * 2 + 50;
score_word(_, [$(,$t,$)], Scores) ->
    score_sum(Scores) * 3;
score_word(_, [$(,$d,$)], Scores) ->
    score_sum(Scores) * 2;
score_word(_, [], Scores) ->
    score_sum(Scores);
score_word(LS, [$^, _ | Rest], Scores) ->
    score_word(LS, Rest, Scores ++ 0);
score_word(LS, [Letter, $*, $* | Rest], Scores) ->
    score_word(LS, Rest, Scores ++ [maps:get(Letter,LS) * 3]);
score_word(LS, [Letter, $* | Rest], Scores) ->
    score_word(LS, Rest, Scores ++ [maps:get(Letter,LS) * 2]);
score_word(LS, [Letter | Rest], Scores) ->
    score_word(LS, Rest, Scores ++ [ maps:get(Letter, LS)]).

score_sum(Scores) ->
    lists:foldl(fun(X, Sum) -> X + Sum end, 0, Scores).
devto8:scrabble_score("z**z**z**z**z**z**z**(t)").
680

devto8:scrabble_score("thiswasfun").
19
 

Ah, neat. Pattern matching was definitely the way to go about it functionally, wish I'd done that instead!

 

Good old C. Be advised though there are ways to bork this one with some inputs not consistent with the rubric.

int score(char *word) {
  // Digits are one less than score values for each letter
  // This maps 1-10 to 0-9, allowing one-character representation of each score
  char *letter_scores = "02210313074020029000033739";
  int score = 0, letter_count = 0, mult=1;
  for(char *ptr = word; *ptr; ptr++) {
    if (isalpha(*ptr)) {
      letter_count++;
      int letter_score = letter_scores[toupper(*ptr)-'A']-'0'+1;
      score += letter_score;
      if (*(ptr+1) == '*') {
        score += letter_score;
        if (*(ptr+2) == '*') {
          score += letter_score;
        }
      }
    }
    if (*ptr == '(') {
      mult = *(ptr+1) == 'd' ? 2 : 3;
      break;
    }
  }
  return score*mult+50*(letter_count == 7);
}
 

JavaScript

const scrabbleWordValue = word => {

  // scrabble letter values
  const letterValues = { 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 };

  // Pre-requesites - check that the string fulfills a good pattern:
  //   - it must start with a letter
  //   - followed by have any combination of letters and asterisks
  //   - optionally at the end it can have a (t) or (d) modifier
  // if it doesn't follow that pattern (invalid or empty), return 0 points
  if(!word.match(/^([a-z][\*]{0,2})+(\([t|d]\))?$/gi)) {
    return 0;
  }

  // word modifier - calculate the multiplier that will apply to the word:
  //   - 1 (default): the word will not change value
  //   - 2 (if it ends with '(d)'): the word will be multiplied by 2
  //   - 3 (if it ends with '(t)'): the word will be multiplied by 3
  // after calculating the word multiplier, update the word id applicable.
  let wordModifier = 1;
  if (word.indexOf("(") > 0) {
    wordModifier = word.indexOf("(t)") > 0 ? 3 : 2;
    word = word.slice(0,-3);
  }

  // calculate the addition of all letters
  //   - if the letter is an asterisk, use the previous letter
  //   - update the previous letter to current letter
  //   - add the value of the letter to the total
  let previous = 0;
  let valueWord = word.split('')
                      .reduce((acc, curr) => {
                        if (curr == '*') curr = previous;
                        previous = curr;
                        return letterValues[curr] + acc;
                      }, 0);

  // if the words has seven letters, add 50 extra points!
  const allLettersBonus = word.replace(/\*/g,'').length == 7 ? 50 : 0;

  // return the value of the word considering all modifiers
  return valueWord * wordModifier + allLettersBonus;
}

Live demo on CodePen.

 

Because these are fun in languages you don't actually know, here's Haskell:

import Data.Map (Map, (!))
import qualified Data.Map as Map

scores :: Map Char Int
scores = Map.fromList pairs
    where
        pairs = [
            ('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)]

scoreWord :: String -> Int
scoreWord w =
    let
        sevenLetterBonus = if (length $ stripMarkers w) == 7 then 50 else 0
        wordMultiplier =
            let
                suffix = dropWhile (/= '(') w
            in
                if length suffix > 0 then
                    case suffix !! 1 of
                        't' -> 3
                        'd' -> 2
                        _ -> 1
                else 1
        -- 
        preparedWord = expandMarkers $ takeWhile (/= '(') w
        rawScore = sum $ scoreLetters $ preparedWord
    in
        rawScore * wordMultiplier + sevenLetterBonus
    where
        scoreLetters cs = map (\c -> scores ! c) cs

-- transform doubles, triples, carats
-- if we hit an asterisk, replace it with the previous letter
-- if we hit a carat, drop the previus letter
expandMarkers :: String -> String
expandMarkers [] = []
expandMarkers (c:[]) = [c]
expandMarkers (c:rest) =
    case head rest of
        '*' ->
            if (head $ tail rest) == '*' then
                [c] ++ [c] ++ [c] ++ (expandMarkers $ drop 2 rest) else
                [c] ++ [c] ++ (expandMarkers $ tail rest)
        '^' -> expandMarkers $ tail rest
        _ -> [c] ++ expandMarkers rest

-- remove suffix and all markers for deciding on the 7-letter bonus
stripMarkers :: String -> String
stripMarkers w = filter (\c -> c /= '*' && c /= '^') $ takeWhile (/= '(') w

I didn't provide tests, but I think it works. Maybe I'll write some later on.

 

My overly complex (nim) solution :)

from strutils import toLower
from sequtils import filter

type WordType = enum value, multiply, global

type Word = object
  Value: int
  Type: WordType

# a..z
# [97, 122]
const score_mapping = [1, 3, 3, 2, 1, 4, 
                       2, 4, 1, 8, 5, 1, 3, 
                       1, 1, 3, 10, 1, 1, 
                       1, 1, 4, 4, 8 , 4, 10]

# Build a stack, tokenizing the characters
# This will let us apply operations in a reverse order
proc buildStack(word: string): seq[ref Word] =
  result = newSeq[ref Word]()
  let lowerWord = toLower(word)

  for i in 0..(len(lowerWord) - 1):
    let currentWord = new(Word)
    let letter = lowerWord[i]
    let letterAsInt = int(letter)

    if letterAsInt < 97 or letterAsInt > 122:
      if letter == '*':
        currentWord.Value = 2
        currentWord.Type = WordType.multiply
      if letter == '^':
        currentWord.Value = 0
        currentWord.Type = WordType.multiply
      if letter == '(':
        currentWord.Value = if lowerWord[i+1] == 't': 3 else: 2
        currentWord.Type = WordType.global
        result.add(currentWord) # we reached the end of the string
        break
    else:
      let scoreMappingPosition = letterAsInt - 97

      currentWord.Value = score_mapping[scoreMappingPosition]
      currentWord.Type = WordType.value

    result.add(currentWord)

# Gets the value of the operations
proc parseOperations(value: int, operations: seq[ref Word]): int =
  var multiplier = 1

  if len(operations) > 0:
    for operation in operations:
      if operation.Type == Wordtype.multiply:
        if operation.Value == 0:
          return 0
        else:
          multiplier += 1

  result += value * multiplier

proc getScore(stack: seq[ref Word]): int =
  var s = stack # make mutable
  var operations: seq[ref Word]
  var globalMultiplier = 1

  if stack.filter(proc(p: ref Word): bool = p.Type == Wordtype.value).len >= 7:
    result += 50

  while len(s) > 0:
    let item = s.pop()

    if item.Type == WordType.value:
      result += parseOperations(item.Value, operations)
      operations = @[]
    elif item.Type == Wordtype.global:
      globalMultiplier = item.Value
    else:
      operations.add(item)

  result *= globalMultiplier

echo buildStack("d**e*v^(d)").getScore()
 

A few days late, but here's my JavaScript solution, using reduce.

function scoreWord(string) {
    let word = string.toLowerCase();

    const scores = {
        a: 1,
        // ... etc, cut for conciseness
        z: 10,
        q: 10
    }

    let multiplier = 1;

    if(word.substring(word.length - 1) === '2') {
        multiplier = 2;
        word = word.substring(0, word.length - 1);
    } else if(word.substring(word.length - 1) === '3') {
        multiplier = 3;
        word = word.substring(0, word.length - 1);
    }

    let bonus = word.split('').filter(char => {
        return !['*', '^'].includes(char);
    }).length >= 7 ? 50 : 0;

    return word.split('').reduce((score, letter, index, letters) => {
        const next = index + 1 < letters.length ? letters[index + 1] : null;
        if('abcdefghijklmnopqrstuvwxyz'.includes(letter)) {
            if(next && ['*', '^'].includes(next)) {
                if(next === '^') {
                    return score += 0;
                }
                if(next === '*') {
                    if(index + 2 < letters.length && letters[index + 2] === '*') {
                        score += (scores[letter] * 3);
                    } else {
                        score += (scores[letter] * 2);
                    }
                    return score;
                }
            }
            return score += scores[letter];
        } else {
            return score;
        }
    }, 0) * multiplier + bonus;
}

I changed the rules a bit, since it's hard to distinguish between double/triple words and words that naturally end in d or t, I decided to use 2 or 3 instead.

 

Ruby solution

require "minitest/autorun"

class ScrabbleLetter
  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
  }.freeze

  # Parses a string of scrabble letters and separates
  # them with their multiplier still intact.
  #
  # @example
  #
  #   ScrabbleLetter.parse("h^i**")
  #   # => [#<ScrabbleLetter @letter="h^">, #<ScrabbleLetter @letter="i**">]
  #
  def self.parse string
    string.chars.each_with_object([]) do |char, letters|
      SCORES[char] ? letters << char : letters[-1] << char
    end.map { |letter| new letter }
  end

  def initialize letter
    @letter = letter
  end

  def score
    letter_score * multiplier
  end

  private

    def letter_score
      SCORES[@letter.chr]
    end

    def multiplier
      return 0 if @letter.end_with?('^')
      return 3 if @letter.end_with?('**')
      return 2 if @letter.end_with?('*')
      return 1
    end
end

class ScrabbleWord
  DOUBLE_WORD_TOKEN = '(d)'.freeze
  TRIPLE_WORD_TOKEN = '(t)'.freeze

  def initialize word
    @word = word
  end

  def score
    letters_score * multiplier + length_bonus
  end

  private

    def letters_score
      letters.map(&:score).reduce(:+)
    end

    def multiplier
      return 2 if @word.end_with?(DOUBLE_WORD_TOKEN)
      return 3 if @word.end_with?(TRIPLE_WORD_TOKEN)
      return 1
    end

    def length_bonus
      letters.count == 7 ? 50 : 0
    end

    def letters
      ScrabbleLetter.parse word_without_multiplier
    end

    def word_without_multiplier
      @word
        .gsub(DOUBLE_WORD_TOKEN, "")
        .gsub(TRIPLE_WORD_TOKEN, "")
    end
end

class ScrabbleWordTest < MiniTest::Test
  def test_simple_word
    assert_equal 23, ScrabbleWord.new("quintessential").score
  end

  def test_double_and_triple_letters
    assert_equal 11, ScrabbleWord.new("he*llo**").score
  end

  def test_triple_word
    assert_equal 69, ScrabbleWord.new("quintessential(t)").score
  end

  def test_blank_tile_with_triple_word
    assert_equal 39, ScrabbleWord.new("q^uintessential(t)").score
  end

  def test_double_and_triple_letters_with_double_word
    assert_equal 22, ScrabbleWord.new("he*llo**(d)").score
  end

  def test_blank_tile_with_double_letter_and_double_word
    assert_equal 18, ScrabbleWord.new("he^llo**(d)").score
  end

  def test_seven_letter_word_bonus
    assert_equal 72, ScrabbleWord.new("wordier(d)").score
  end
end

I borrowed your tests, @yzhernand . Thank you for writing them, so I didn't have to.

 

Elixir. Admittedly my Exercism solution with a bunch of String.replace calls to handle the more sophisticated way the problem is stated here.

defmodule Scrabble do
  @spec slw?(String.t()) :: boolean
  def slw?(word) do
    word
    |> String.replace(~r/\(.*/, "")
    |> String.replace("*", "")
    |> String.length
    |> Kernel.==(7)
  end

  @spec score(String.t()) :: non_neg_integer
  def score(word) do
    word
    |> String.replace(~r/(.)\*\*/, "\\1\\1\\1")
    |> String.replace(~r/(.)\*/, "\\1\\1")
    |> String.replace(~r/^(.*)\(t\)$/, "\\1\\1\\1")
    |> String.replace(~r/^(.*)\(d\)$/, "\\1\\1")
    |> String.downcase
    |> String.to_charlist
    |> Enum.reduce(if(slw?(word), do: 50, else: 0), fn c, acc ->
      acc + cond do
        c == ?^ -> 0
        c in 'urtoenails' -> 1
        c in 'dg' -> 2
        c in 'bcmp' -> 3
        c in 'fhvwy' -> 4
        c == ?k -> 5
        c in 'jx' -> 8
        c in 'qz' -> 10
        true -> 0
      end
    end)
  end
end
 

I’m learning Erlang.

I had forgotten that you can have several elements to the Head in a pattern match (then I saw @stevemoon ’s solution), so I used lists:foldr to process the word from the end, which means I accumulate the multipliers and apply them once I encounter a letter. I could have named variables better, but with short names it’s easier on the eye, with this state tuple I’m moving around.

For fun I decided to allow several word multipliers, and to allow the blank indicator before, after, or in the middle of the asterisks.

I made my own tests, and stole other peoples’ as well.

-module( scrabble ).
-export( [ word_score/1, letter_score/1 ] ).

-include_lib("eunit/include/eunit.hrl").

letter_score( Letter ) ->
    Points = #{
        $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
    },
    maps:get( Letter, Points ).

word_score( Word ) ->
    { Score, Wm, _Lm, Lc, _State } = lists:foldr(
        fun char/2,
        { 0, 1, 1, 0, normal },
        string:lowercase( Word )
    ),
    Bonus = case Lc of 7 -> 50; _ -> 0 end,
    Score * Wm + Bonus.

% Score
% Wm = Word multiplier
% Lm = Letter multiplier
% Lc = Letter count
% Parser state
char( $\), { Score, Wm, Lm, Lc, normal } ) ->
    { Score, Wm, Lm, Lc, word_mult };
char( $d, { Score, Wm, Lm, Lc, word_mult } ) ->
    { Score, 2 * Wm, Lm, Lc, word_mult };
char( $t, { Score, Wm, Lm, Lc, word_mult } ) ->
    { Score, 3 * Wm, Lm, Lc, word_mult };
char( $\(, { Score, Wm, Lm, Lc, word_mult } ) ->
    { Score, Wm, Lm, Lc, normal };
char( $*, { Score, Wm, 0, Lc, normal } ) ->
    { Score, Wm, 0, Lc, normal };
char( $*, { Score, Wm, 1, Lc, normal } ) ->
    { Score, Wm, 2, Lc, normal };
char( $*, { Score, Wm, 2, Lc, normal } ) ->
    { Score, Wm, 3, Lc, normal };
char( $^, { Score, Wm, _Lm, Lc, normal } ) ->
    { Score, Wm, 0, Lc, normal };
char( L, { Score, Wm, Lm, Lc, normal } ) ->
    { Score + Lm * letter_score( L ), Wm, 1, Lc + 1, normal }.

char_test() -> [
    ?assert( char( $\), { 0, 1, 1, 0, normal } ) =:= { 0, 1, 1, 0, word_mult } ),
    ?assert( char( $d, { 0, 1, 1, 0, word_mult } ) =:= { 0, 2, 1, 0, word_mult } ),
    ?assert( char( $d, { 0, 2, 1, 0, word_mult } ) =:= { 0, 4, 1, 0, word_mult } ),
    ?assert( char( $t, { 0, 2, 1, 0, word_mult } ) =:= { 0, 6, 1, 0, word_mult } ),
    ?assert( char( $\(, { 0, 3, 1, 0, word_mult } ) =:= { 0, 3, 1, 0, normal } ),
    ?assert( char( $a, { 0, 1, 1, 0, normal } ) =:= { 1, 1, 1, 1, normal } ),
    ?assert( char( $b, { 1, 1, 1, 1, normal } ) =:= { 4, 1, 1, 2, normal } ),
    ?assert( char( $*, { 4, 1, 1, 2, normal } ) =:= { 4, 1, 2, 2, normal } ),
    ?assert( char( $*, { 4, 1, 2, 2, normal } ) =:= { 4, 1, 3, 2, normal } ),
    ?assert( char( $^, { 4, 1, 1, 2, normal } ) =:= { 4, 1, 0, 2, normal } ),
    ?assert( char( $*, { 4, 1, 0, 2, normal } ) =:= { 4, 1, 0, 2, normal } )
].

score_test() -> [
    1 = word_score("A"),
    2 = word_score("A(d)"),
    3 = word_score("A(t)"),
    6 = word_score("A(dt)"),
    6 = word_score("A(td)"),
    12 = word_score("A(ddt)"),
    12 = word_score("A(dtd)"),
    18 = word_score("A(ttd)"),
    4 = word_score("AB"),
    5 = word_score("A*B"),
    6 = word_score("A**B"),
    14 = word_score("SCRABBLE"),
    28 = word_score("SCRABBLE(d)"),
    42 = word_score("SCRABBLE(t)"),
    21 = word_score("F**OX"),
    38 = word_score("F**O*X**"),
    63 = word_score("PROBLEM"),
    77 = word_score("PR*OB**LE*M**"),
    12 = word_score("ZER^O"),
    12 = word_score("ZER*^O"),
    12 = word_score("ZER**^O"),
    12 = word_score("ZER^*O"),
    12 = word_score("ZER^**O"),
    12 = word_score("ZER*^*O"),
    68 = word_score("P**RO*B^LE*M"),

    23 = word_score("QUINTESSENTIAL"),
    11 = word_score("HE*LLO**"),
    69 = word_score("QUINTESSENTIAL(t)"),
    39 = word_score("Q^UINTESSENTIAL(t)"),
    22 = word_score("HE*LLO**(d)"),
    18 = word_score("HE^LLO**(d)"),
    72 = word_score("WORDIER(d)"),

    680 = word_score("Z**Z**Z**Z**Z**Z**Z**(t)"),
    19 = word_score("THISWASFUN")
].

To run:

% erl
1> c(scrabble).
{ok,scrabble}
2> scrabble:test().
  2 tests passed.
ok
 

codesandbox.io/s/daily-challenges-...

import { pipe, toUpper } from "ramda";

// CHARACTERS, POINTS, BONUSES //////////////////////////////////////
const A = { char: "A", points: 1 } as const;
const B = { char: "B", points: 3 } as const;
const C = { char: "C", points: 3 } as const;
const D = { char: "D", points: 2 } as const;
const E = { char: "E", points: 1 } as const;
const F = { char: "F", points: 4 } as const;
const G = { char: "G", points: 2 } as const;
const H = { char: "H", points: 4 } as const;
const I = { char: "I", points: 1 } as const;
const J = { char: "J", points: 8 } as const;
const K = { char: "K", points: 5 } as const;
const L = { char: "L", points: 1 } as const;
const M = { char: "M", points: 3 } as const;
const N = { char: "N", points: 1 } as const;
const O = { char: "O", points: 1 } as const;
const P = { char: "P", points: 3 } as const;
const Q = { char: "Q", points: 10 } as const;
const R = { char: "R", points: 1 } as const;
const S = { char: "S", points: 1 } as const;
const T = { char: "T", points: 1 } as const;
const U = { char: "U", points: 1 } as const;
const V = { char: "V", points: 4 } as const;
const W = { char: "W", points: 4 } as const;
const X = { char: "X", points: 8 } as const;
const Y = { char: "Y", points: 4 } as const;
const Z = { char: "Z", points: 10 } as const;
// prettier-ignore
const charMap = {Q,W,E,R,T,Y,U,I,O,P,A,S,D,F,G,H,J,K,L,Z,X,C,V,B,N,M} as const;
const tripleWordBonus = "(T)";
const doubleWordBonus = "(D)";
const tripleLetterBonus = "**";
const doubleLetterBonus = "*";

// TYPES ////////////////////////////////////////////////////////////
type ValueOf<T> = T[keyof T];
type Char = ValueOf<typeof charMap>;
type LetterTile = { type: "LETTER" };
type BlankTile = { type: "BLANK" };
type Square = { letterBonus: 1 | 2 | 3; wordBonus: 1 | 2 | 3 };

type Tile = ((LetterTile) | BlankTile) & Char & Square;

// CONVERT STRING TO TILES //////////////////////////////////////////
const REGEX = /[A-Z](\*|\^|\((T|D)\))*/g; // https://bit.ly/31LZ0mZ
const parse = (input: string): Tile[] => {
  const strings: string[] = input.match(REGEX) || [];
  return strings.map(toTile);
};

const type = (input: string) => (input.includes("^") ? "BLANK" : "LETTER");
const letterAndPoints = (char: Tile["char"]) => charMap[char];
const letterBonus = (input: string) => {
  if (input.includes(tripleLetterBonus)) return 3;
  if (input.includes(doubleLetterBonus)) return 2;
  return 1;
};
const wordBonus = (input: string) =>
  input.includes(tripleWordBonus) ? 3 : input.includes(doubleWordBonus) ? 2 : 1;
const toTile = (input: string): Tile => {
  const chars = input.split("");
  const [char, ...rest] = chars;
  const modifiers = rest.join("");
  return {
    type: type(modifiers),
    ...letterAndPoints(char),
    letterBonus: letterBonus(modifiers),
    wordBonus: wordBonus(modifiers)
  };
};

// CALCULATE SCORE //////////////////////////////////////////////////
const letterPoints = (tiles: Tile[]) =>
  tiles.reduce(
    (result, { type, char, letterBonus }) =>
      type === "BLANK" ? result : result + charMap[char].points * letterBonus,
    0
  );
const wordBonusMultiplier = (tiles: Tile[]) =>
  tiles.reduce((result, { wordBonus }) => result * wordBonus, 1);
const BINGO = { length: 7, points: 50 };
const bingoPoints = (tiles: Tile[]) =>
  tiles.length === BINGO.length ? BINGO.points : 0;

const scoreTiles = (tiles: Tile[]) =>
  letterPoints(tiles) * wordBonusMultiplier(tiles) + bingoPoints(tiles);

// WHOLE ENCHILADA //////////////////////////////////////////////////
export const getScore = pipe(
  toUpper,
  parse,
  scoreTiles
);
 

Clojure:

(ns scrabble
  (:require [clojure.string :as s]))

(def values
  (zipmap
    [\a \b \c \d \e \f \g \h \i \j \k \l \m \n \o \p \q \r \s \t \u \v \w \x \y \z]
    [ 1  3  3  2  1  4  2  4  1  8  5  1  3  1  1  3 10  1  1  1  1  4  4  8  4 10]))

(defn letter-score [[a b c]]
  (let [base (values a 0)
        mult (cond (= b \^)                0
                   (and (= b \*) (= c \*)) 3
                   (= b \*)                2
                   :else                   1)]
    (* base mult)))

(defn trim [word]
  (s/replace word #"\(\w\)$" ""))

(defn base-word-score [word]
  (->> (trim word)
       (partition-all 3 1)
       (map letter-score)
       (apply +)))

(defn bonus [word]
  (if (= 7 (count (s/replace (trim word) #"\W" ""))) 50 0))

(defn score [word]
  (let [base (base-word-score word)
        mult (cond (s/ends-with? word "(t)") 3
                   (s/ends-with? word "(d)") 2
                   :else                     1)]
    (+ (bonus word) (* base mult))))
 

Calculates only by letter points


import "strings"

var LETTER_POINTS = map[byte]int{
    'a': 1, 'b': 3, 'c': 3, 'd': 1, '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,
}

func CalculateScrabblePoints(word string) int {
    points := 0

    if len(word) == 7 {
        return 50
    }

    lowerWord := strings.ToLower(word)

    for _, letter := range lowerWord {
        points += LETTER_POINTS[byte(letter)]
    }

    return points
}

 

Ooh I love Scrabble! I'm excited for this one lol

 

Here is my over engineered solution in Rust!

I broke it down into multiple different Rust strucs and enums! I'm getting more and more familiar with the Rust type system, and breaking down a game like this is great practice!

One thing I slightly added, is the ability to parse multiple word modifiers together! I opted for a (t)(d) syntax do indicate both a triple and double word score. This is possible in Scrabble, so I wanted to include support for it

My solution and test cases is just over 250 lines so here is the link to the source file in Github!
github.com/coreyja/dev-to-challeng...

 

Oh no, I didn't get to it today! Tomorrow will have to be a double day!