# Scrabble scorer

### Challenge:

Take a string of upper or lower case letters as input (optional), and calculate the score that string would get in a game of Scrabble in English.

### Rules:

The score of each letter is as follows (use this even if there are other versions of the game):

1 point: E, A, I, O, N, R, T, L, S, U
2 points: D, G
3 points: B, C, M, P
4 points: F, H, V, W, Y
5 points: K
8 points: J, X
10 points: Q, Z


The score of a string is simply the sum of the scores of each of the letters used. You may assume that you have plenty of tiles available, so long words, and words with many of the same letters are valid input.

### Test cases:

ABC       ->    7
PPCG      ->   11
STEWIE    ->    9
UGPYKXQ   ->   33
FIZZBUZZ  ->   49
ABCDEFGHIJKLMNOPQRSTUVWXYZ  -> 87


The shortest answer in each language wins! The input and output formats are flexible, so you may take the input as an array of characters (upper or lower case) if you want.

• I'm hoping to see a MATLAB/Octave solution. All my attempts were horribly long... =/ – Stewie Griffin Apr 17 '18 at 19:04
• I'm hoping to see a Beatnik solution. Cuz, you know, that would be the right tool for the job. – Giuseppe Apr 17 '18 at 19:28
• @StewieGriffin Does 85 bytes count as horribly long? – Luis Mendo Apr 17 '18 at 21:11
• Hasn't Mathematica a built-in for it? – sergiol Apr 18 '18 at 0:30
• @manassehkatz you should definitely give it a go! I highly recommend that you post the challenge in the Sandbox to get some feedback and help with it before posting it on the main site. Complex challenges are notoriously difficult to get right without any feedback. – Stewie Griffin Apr 18 '18 at 19:37

# PowerShell, 92 bytes

$args|% T*y|%{$i+=switch -r($_){[DG]{2}[BCMP]{3}[FHVWY]{4}K{5}[JX]{8}[QZ]{10}default{1}}};$i


Try it online!

Didn't notice @Add-TheNewOne's answer before writing this, but I think it's fairly different in any case.

# 05AB1E, 18 bytes

•Q<ß÷λv¸Ïàœ¶•IÇè>O


Try it online!

Explanation:

•Q<ß÷λv¸Ïàœ¶•           # compressed integer 30740200290000337390221031
IÇ         # codepoints of the input
è        # index into the digits of the large integer
>       # increment each
O      # sum


The large integer encodes the point value of each letter. Since encoding numbers in the range 1-10 would be inconvenient, we subtract 1 so that each one fits on a single digit (this is why the > is needed).

Note that indexing in 05AB1E wraps around, so the first digit of the number actually corresponds to "h" ("h"'s codepoint is 104, which is 0 mod 26). This is convenient: since numbers can't start with 0, we don't want the first digit to correspond to "a".

Alternative 18-byter:

A•Θ¡₆öηÖ&'/α°•R‡>O


Try it online!

A pushes "abcdefghijklmnopqrstuvwxyz". ‡ transliterates, replacing each letter in the input with the corresponding digit in the compressed integer. A‡ saves one byte over IÇè; unfortunately, this encoding puts "a" first, so we have to use R (reverse) to get around the issue that numbers can't start with 0.

Yet another 18-byter:

žW•Δÿ¦ÝZ=áí4_ø•‡>O


Try it online!

Same idea as above, but this one uses the obscure žW built-in to push "qwertyuiopasdfghjklzxcvbnm". žW is one byte longer than A, but it saves the R since "q" isn't a 1-point letter.

# Beatnik, 379 bytes

K ZZZZKF ZD ZD ZD ZD ZD ZD ZD
K ZZZZZZZZA J Z ZD ZB B
K XA KD ZD ZF F ZA ZD KF KF ZD ZB B
K D Z ZD ZB B
K ZF Z ZD ZF KA ZA ZD ZD KF KF KF ZD ZB B
K A KD ZD ZF D ZA KF ZD ZB B
K ZF KD ZD ZB B
K D Z ZD ZB B
K A Z ZD ZB B
K ZF Z ZD ZB B
K D Z ZD ZF D ZA KF ZD ZB B
K Z KD ZD ZB B
K B Z ZD ZB B
K Z Z ZD ZB B
K A Z ZD ZF F ZA KF ZB Z
K K KD ZD ZB B
K B Z ZF A KF
KF
XX ZZZZZZZZZZZZZX


Try it online!

# JavaScript (ES6), 69 bytes

Takes input as an array of characters.

s=>s.map(c=>t-=~'9200204703130122093733'[parseInt(c,36)*25%26],t=0)|t


Try it online!

# Bash + GNU utilities, 64

sed -es/[{QZ]/JD,JX]/KB,K]/FE,FHVWY]/BE,BCMP]/DE,DG]/EE}/g|wc -c


Try it online!

Input read from STDIN. Uses a brace expansion to generate sed expressions equivalent to those in my sed answer.

# Perl 6, 55 bytes

{sum .map:{:36<Z3P8JOBRZ4X1FBXLWSVL>+>(.ord*4-260)%16}}


Try it online!

Takes an array of characters. Uses a 4-bit lookup table encoded in base-36.

# Perl 5-pF, 73 bytes

$\+=(1,3,3,2,1,4,2,4,1,8,5,1,3,1,1,3,10,(1)x4,4,4,8,4,10)[-65+ord]for@F}{  Try it online! • Managed to save a few using =~/./g, but can't get it down as far as @nwellnhof's answer... Try it online! – Dom Hastings Apr 18 '18 at 11:48 • My Perl6 solution is pretty similar to this, I opted to use value-1 thus only needing 0-9 which are single digits and then split 022103... – Phil H Apr 19 '18 at 21:11 # Red, 97 bytes func[s][t: :to-integer n: 0 foreach c s[n: n - 47 + t pick{02210313074020029000033739}t c - 64]n]  Takes a string as input. ## Explanation of the ungolfed solution: f: func[s][ n: 0 ; n will store the sum foreach c s [ ; for each character in the argument n: n - 47 + to-integer pick {02210313074020029000033739} to-integer c - 64 ; find its offset from "A" (to-integer c - 64) ; use this as an index in the string with scores (pick {...} ...) ; to extract the score and convert it to an integer ; increase it with 1 and add it to the sum ] n ; return the sum ]  Try it online! # Pip, 34 33 bytes 1+("3V1S1QFRU1SMQ12W7"FB36)@A_MSa  Takes input in lowercase as a command-line argument. Try it online! ### Explanation We map a function to each character of the command-line argument a and sum the results using MS. In the function, we convert the argument _ to its ASCII code using A, and then use that to index into the magic number 30740200290000337390221031. With cyclic indexing, this maps a -> 0, b -> 2, ... , z -> 9 (one less than the Scrabble score). We then add 1 to get the correct score of each letter. We save one byte by encoding the number in base 36 (the highest base Pip's builtin base conversion can handle) as the string "3V1S1QFRU1SMQ12W7" and then converting it from base 36 to decimal using FB. # SmileBASIC, 8785 78 bytes INPUT S$WHILE""<S$S=S+VAL(@2210313074020029000033739[ASC(POP(S$))-65])+1WEND?S


Old method:

INPUT S$WHILE""<S$S=S+(INSTR(@DG+@___BCMP_FHVWYK*2+"JX"*4+@QZ,POP(S$))+4)DIV 5+1WEND?S  # Go, 96 94 bytes func(i string){a,s:=  ,0;for _,c:=range i{s+=int(a[c-65])};print(s)}  Go allows any byte sequence in a raw string, except \r and , this saves about 3 bytes off the total. This is just a remix of existing solutions in other languages, so no real new innovation here. Edit: I missed the memo where we dont have to name our functions Try it online! # Powershell with amazing 297 Bytes Any idea to make the script shorter? $1=read-Host
$s=0$l=$1.ToCharArray()$l|%{switch($_){{'E','A','I','O','N','R','T','L','S','U'-contains$_}{$s+=1}{'D','G'-contains$_}{$s+=2}{'B','C','M','P'-contains$_}{$s+=3}{'F','H','V','W','Y'-contains$_}{$s+=4}{'J','X'-contains$_}{$s+=8}{'Q','Z'-contains$_}{$s+=10}{'K'-contains$_}{$s+=5}}}$s

• You can remove the string $s=0. The -in is sorter than -contains. switch can returns a value $s+=$(switch($_){...{1}...{2}... ...{5}}). and etc :) Welcome! – mazzy Mar 1 at 14:50
• Thank you :D !!! I'm not very experienced in Code golfing so can you explain me what you did in your Code? – Add-TheNewOne Mar 1 at 15:08
• Step 1: obvious thing 240 bytes – mazzy Mar 1 at 17:05
• Step 2: big case to default 195 bytes – mazzy Mar 1 at 17:07
• Step 3: to take out repeating code 171 bytes – mazzy Mar 1 at 17:09

# IBM PC DOS, 8088 assembly, 36 bytes

bb33 01ac 2c41 d0d8 d772 0651 b104 d2e8 5924 0f02 d0e2 ec13 3214 2418 5131 13a1 1114 484a


Unassembled.

; score a Scrabble word string
; input:
;   I: pointer to input string
;   IL: length of input string
;   TBL: pointer to score table
; output:
;   SC: word score (reg8)
SCRAB_SCORE MACRO   I, IL, TBL, SC
LOCAL   LOOP_LETTER, ODD
IFDIFI <I>,<SI>     ; skip if I is already SI
MOV  SI, I              ; load string into SI
ENDIF
IFDIFI <IL>,<CX>    ; skip if IL is already CX
MOV  CX, IL             ; set up loop counter
ENDIF
MOV  BX, OFFSET TBL     ; load score table into BX
LOOP_LETTER:
SUB  AL, 'A'            ; convert letter to zero-based index
RCR  AL, 1              ; divide index by 2, set CF if odd index
XLAT                    ; lookup score
JC   ODD                ; if odd index use low nibble; if even use high nibble
PUSH CX                 ; save loop counter (since SHR can only take CL)
MOV  CL, 4              ; set up right shift for 4 bits
SHR  AL, CL             ; shift high nibble into low nibble
POP  CX                 ; restore loop counter
ODD:
AND  AL, 0FH            ; mask low nibble
LOOP LOOP_LETTER
ENDM

; Score table
SCTBL DB 013H,032H,014H,024H,018H,051H,031H,013H,0A1H,011H,014H,048H,04AH


Explanation

Implemented as a MACRO (essentially a function) this uses a score table of 4-bit nibbles. Loops through the input string and converts each letter to a zero-based index. Each index is divided by two to find the corresponding byte in the table. The low nibble is added if the index is odd, otherwise the high nibble is added if the index is even.

Output

Example test program:

    MOV  SI, 80H            ; point SI to DOS PSP
MOV  CL, AL             ; set up loop counter in CH
DEC  CX                 ; remove leading space from letter count
XOR  DX, DX             ; clear DX to hold total score

SCRAB_SCORE SI, CX, SCTBL, DL

MOV  AX, DX             ; put score in AX for OUTDEC display
CALL OUTDEC             ; generic decimal display routine # brainfuck, 386 382 bytes

->,[>>,]->+>>+++>>+++>>++>>+>>++++>>++>>++++>>+>>++++++++>>+++++>>+>>+++>>+>>+>>+++>>++++++++++>>+>>+>>+>>+>>++++>>++++>>++++++++>>++++>>+++++++++++[-<<+]->+[->++++++++[<-------->-]<-[[->+]>>-<+[-<+]->]+[->+]->[->+>[>>]>++[-<+]->]>[-<+>]<<+<[<<]>-<+[-<+]>>->+]>[>>]>>+[[-]<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->[-]>>+>+<<<]]]]]]]]]<]>>[>]++++++[-<++++++++>]>>]<<<[.[-]<<<]


Try it online!

Pretty much ungolfed, but first brainfuck code for this question. This code can only handle uppercase letters. Any other symbol will lead to an endless loop. Also the maximum score depends on the used bf-interpreter. On tio.run this can handle scores up to 254.

points:
abcde fghij klmno pqrst uvwxyz
13321 42418 51311 3x111 14484x (x = 10)

tape:
[input], 0, [points table], 0, 0, score
input: current letter marker (0 or neg 1), current letter
points table: check letter marker (0 or neg 1), points

code:
-           set current letter marker
>,[>>,]     input characters

->          set check letter marker
fill points table
+>>+++>>+++>>++>>+>>
++++>>++>>++++>>+>>++++++++>>
+++++>>+>>+++>>+>>+>>
+++>>++++++++++>>+>>+>>+>>
+>>++++>>++++>>++++++++>>++++>>++++++++++

+[-<<+]->                   go to first input letter
+                           bugfix: intersecting pointers
[                       main loop
-                         bugfix: intersecting pointers
>++++++++[<-------->-]<-  subtract 65 from current letter (ASCII A)
[                         check loop: mark the entry in points table that's related to the current letter
[->+]                   decrease letter and go to check letter marker
>>-                     set new check letter marker
<+[-<+]-                go back to current letter marker
>                       go to current letter
]
the related points entry is found so we need to add the points to the score
+[->+]->                  go to related points entry
->+                     decrease points entry and save points to temporary cell
>[>>]>+                 go to score and add 1
+[-<+]->                go back to related points entry
]
>[-<+>]                   move points back from temp cell
<<+                       delete "check letter marker"
<[<<]>-                   set "check letter marker" at A
<+[-<+]                   go to current letter marker
>>-                       set new current letter marker
>                         next input letter
+                         exit loop if cell pointer is at "check letter marker" position
]

>[>>]>                      go to score
number printing routine from esolangs
>+[[-]<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->+<[->[-]>>+>+<<<]]]]]]]]]<]>>[>]++++++[-<++++++++>]>>]<<<[.[-]<<<]


if unary output is allowed then this 297 293 bytes code can be used:

->,[>>,]->+>>+++>>+++>>++>>+>>++++>>++>>++++>>+>>++++++++>>+++++>>+>>+++>>+>>+>>+++>>++++++++++>>+>>+>>+>>+>>++++>>++++>>++++++++>>++++>>+++++++++++[-<<+]->+[->++++++++[<-------->-]<-[[->+]>>-<+[-<+]->]+[->+]->[->+>[>>]>++[-<+]->]>[-<+>]<<+<[<<]>-<+[-<+]>>->+]>[>>]<+++++++[>+++++++<-]>>[-<.>]


Try it online!

# SNOBOL4 (CSNOBOL4), 224 bytes

	V =ARRAY(10,0)
V<1> ='EAIONRTLSU'
V<2> ='DG'
V<3> ='BCMP'
V<5> ='FHVWY'
V<8> ='JX'
V<10> ='QZ'
I =INPUT
N	S =I
X =LT(X,10) X + 1	:F(O)
R	S ANY(V<X>) =	:S(R)
O =O + X * (SIZE(I) - SIZE(S))
I =S	:(N)
O	OUTPUT =O
END


Try it online!

Very naive approach. Stores the letters in an ARRAY with indices equal to the scores. It tries to match 0 for point values that don't exist, which ends in a score of 0.

	V =ARRAY(10,0)			;* set up value array of 10 values with contents all 0
V<1> ='EAIONRTLSU'		;* set contents at appropriate indices
V<2> ='DG'
V<3> ='BCMP'
V<5> ='FHVWY'
V<8> ='JX'
V<10> ='QZ'
N	S =I				;* begin Next iteration
X =LT(X,10)	X + 1	:F(O)	;* increment X or GOTO output
R	S ANY(V<X>) =	:S(R)		;* replace ANY letters in V<X> with nothing
O =O + X * (SIZE(I) - SIZE(S))	;* add to the score
I =S	:(N)			;* set I to S and goto N
O	OUTPUT =O
END


## Visual Basic for Applications, 117 bytes

s=inputbox(u):for i=1to 16:s=replace(s,mid("DGBCMPFHVWYKJXQZ",i,1),space(mid("1122223333347799",i,1)+1)):next:?len(s)


Run in immediate (debug) window.

## C# 49 bytes

s.Sum(i=>"02210313074020029000033739"[i-65]-47);


Where s is a string containing the word in uppercase.

Uses the LINQ operator sum which examines each character and subtracts 65 (upper case A) and uses the resultant value to lookup a number in the long string, which represents the scores in alphabetical order starting with 0 as 1, 1 as 2 etc. The final subtraction -47 reduces the score to its ASCII value = 0 becomes 1, 1 becomes 2 etc

• You can not assume input to be present in a predefined variable: codegolf.meta.stackexchange.com/a/8731/56433 – Laikoni Apr 19 '18 at 22:12
• So this is the broken and "cheating" version of my answer posted a day before yours? – TheLethalCoder Apr 20 '18 at 10:17
• @TheLethalCoder No - whacked this out over lunch and forgot about it. Didn't see yours until I l read your comment. There aren't many ways of doing this as succinctly as possible, and I guess I came up with the same method (albeit with a glaring mistake) as you, but if it makes your fragile ego feel better, go ahead and accuse me of cheating. – supermeerkat Apr 23 '18 at 8:54
• The "cheating" is that you haven't included the method signature, in this case i=> and you haven't included the using System.Linq; into your byte count. You can also drop the trailing semi-colon. My ego is, however, very much intact thank you very much. – TheLethalCoder Apr 23 '18 at 8:59

# PHP, 74 bytes

while($c=$argn[$i++])$s+=1+_02210313074020029000033739[ord($c)&31];echo$s;


case insensitive. Run as pipe with -nR or try it online.

# C# (.NET Core), 48 + 18 = 66 bytes

s=>s.Sum(c=>"!#C²!$1$\$XhQJ"[c%13]-16>>c%2*4&15)


+18 bytes is for using System.Linq;

Try it online!

• Isnt the function signature part of the code? – Kristoffer Sall-Storgaard Apr 20 '18 at 22:01
• @KristofferSall-Storgaard I'm not actually sure on the code golf rules since I don't post often. I just mimicked TheLethalCoder's setup and tried to save a few bytes. – Geoffrey Apr 21 '18 at 22:54
• I was wrong. It would appear we dont need to name the functions – Kristoffer Sall-Storgaard Apr 23 '18 at 12:24

# T-SQL, 106 bytes

Accepting uppercase characters.

Inserted a line break to make this readable:

DECLARE @ varchar(max)='ABCDEFGHIJKLMNOPQRSTUVWXYZ'

WHILE'='<@
SET
@=stuff(@,1,1,'')+'-~'+substring('02210313074020029000033739',ascii(@)-64,1)
EXEC('print'+@)
`