48
\$\begingroup\$

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.

\$\endgroup\$
11
  • 7
    \$\begingroup\$ I'm hoping to see a MATLAB/Octave solution. All my attempts were horribly long... =/ \$\endgroup\$ Apr 17, 2018 at 19:04
  • 4
    \$\begingroup\$ I'm hoping to see a Beatnik solution. Cuz, you know, that would be the right tool for the job. \$\endgroup\$
    – Giuseppe
    Apr 17, 2018 at 19:28
  • \$\begingroup\$ @StewieGriffin Does 85 bytes count as horribly long? \$\endgroup\$
    – Luis Mendo
    Apr 17, 2018 at 21:11
  • 3
    \$\begingroup\$ Hasn't Mathematica a built-in for it? \$\endgroup\$
    – sergiol
    Apr 18, 2018 at 0:30
  • 1
    \$\begingroup\$ @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. \$\endgroup\$ Apr 18, 2018 at 19:37

56 Answers 56

1
2
2
\$\begingroup\$

Wolfram Language (Mathematica), 74 bytes

Of course Wolfram|Alpha supports Scrabble scoring! This is an anonymous function.

Plus@@(First[WolframAlpha["Scrabble "<>##,"NumberData"]]&/@Characters[#])&

This doesn't work on TIO.

To run, go here, scroll down and click "Create a New Notebook »". The code to use in the notebook is in this TIO program so you can copy it. Paste each function call in its own code block. If you run too many in a single block, the execution won't complete.

Note that WolframAlpha sends a request using the Internet. Though there are other answers on PPCG that use it, I thought you should know.

This program uses the below shorter function, but calls it on each individual character of the input (sending a separate call to Wolfram|Alpha each time!)


This only works for input up to length 15, the width of a Scrabble board. (49 bytes)

First[WolframAlpha["Scrabble "<>#,"NumberData"]]&

Same as above, but will display the result in a box, along with whether the input is a valid Scrabble word. (45 bytes)

First[WolframAlpha["Scrabble "<>#,"Result"]]&
\$\endgroup\$
2
\$\begingroup\$

C# (.NET Core), 50 + 18 = 68 bytes

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

+18 bytes for using System.Linq;

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Japt -x, 43 39 35 30 bytes

£2+`dglbcÛghvwylk¥ljx¥qz`qÊaøX

Try it online!

35 byte solution:

¬£Ò('0+#Ý03#740#È29e4+33739 g65nXc

Run it online

\$\endgroup\$
2
\$\begingroup\$

APL (Dyalog Extended), 40 bytes

+/1+⍎¨'02210313074020029000033739'[⎕A⍳⎕]

The same method as the K answer, index into a list of scores, add 1 to them, and sum.

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ nice answer. You should post it here. \$\endgroup\$
    – Razetime
    Sep 27, 2020 at 15:18
  • \$\begingroup\$ Bounty will be delivered here. \$\endgroup\$
    – Adám
    Oct 21, 2020 at 5:10
2
\$\begingroup\$

Zsh + bc, 54 bytes

bc<<<$#1`tr a-z 02210313074020029000033739<<<${1///+}`

Try it online!

Pure Zsh, 55 bytes

<<<$[$#1`tr a-z 02210313074020029000033739<<<${1///+}`]

Try it online!

\$\endgroup\$
2
\$\begingroup\$

Python 3, 70 bytes

This isn't any better than Rod's answer (which is also 70 bytes) but it is a different approach than the other answers I see in this thread so I figured I'd submit it anyway.

lambda s:sum(0xa48441111a3113158142412331>>4*(ord(c)-97)&15for c in s)

Try it online!

Shorter version, 68 bytes

-2 bytes thanks to xnor, now making this better than the previous Python answer!

lambda s:sum(0xa48441111a3113158142412331>>ord(c)%97*4&15for c in s)

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ Welcome! It looks like you can shave a byte by distributing the 4*: Try it online! \$\endgroup\$
    – xnor
    May 19, 2023 at 21:12
  • 1
    \$\begingroup\$ Or, better, replace the subtraction with a mod: TIO \$\endgroup\$
    – xnor
    May 19, 2023 at 21:15
  • \$\begingroup\$ @xnor That's a couple good ideas. I'm sometimes too shy of order of operations when golfing! (And I entirely missed the idea of mod) \$\endgroup\$ May 21, 2023 at 3:48
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
2
  • \$\begingroup\$ Managed to save a few using =~/./g, but can't get it down as far as @nwellnhof's answer... Try it online! \$\endgroup\$ Apr 18, 2018 at 11:48
  • \$\begingroup\$ 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... \$\endgroup\$
    – Phil H
    Apr 19, 2018 at 21:11
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

SmileBASIC, 87 85 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
\$\endgroup\$
1
\$\begingroup\$

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!

\$\endgroup\$
1
\$\begingroup\$

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
\$\endgroup\$
8
  • \$\begingroup\$ 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! \$\endgroup\$
    – mazzy
    Mar 1, 2019 at 14:50
  • \$\begingroup\$ Thank you :D !!! I'm not very experienced in Code golfing so can you explain me what you did in your Code? \$\endgroup\$ Mar 1, 2019 at 15:08
  • \$\begingroup\$ Step 1: obvious thing 240 bytes \$\endgroup\$
    – mazzy
    Mar 1, 2019 at 17:05
  • \$\begingroup\$ Step 2: big case to default 195 bytes \$\endgroup\$
    – mazzy
    Mar 1, 2019 at 17:07
  • \$\begingroup\$ Step 3: to take out repeating code 171 bytes \$\endgroup\$
    – mazzy
    Mar 1, 2019 at 17:09
1
\$\begingroup\$

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
  [                     addition loop
    ->+                     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!

\$\endgroup\$
1
\$\begingroup\$

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'
	I =INPUT			;* read input
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
\$\endgroup\$
1
\$\begingroup\$

x86-machine code, IBM PC DOS, 37 bytes

00000000: bb18 0133 d2ac 2c41 d0e8 9cd7 d410 9d72  ...3..,A.......r
00000010: 0286 e002 d0e2 eec3 1332 1424 1851 3113  .........2.$.Q1.
00000020: a111 1448 4a                             ...HJ

Listing:

BB 0118     MOV  BX, OFFSET TBL     ; load score table into BX 
33 D2       XOR  DX, DX             ; clear letter count 
        LOOP_LETTER: 
AC          LODSB                   ; load next char from DS:SI into AL, advance SI 
2C 41       SUB  AL, 'A'            ; convert letter to zero-based index 
D0 E8       SHR  AL, 1              ; divide index by 2, set CF if odd index 
9C          PUSHF                   ; save CF 
D7          XLAT                    ; AL = packed score byte 
D4 10       AAM  16                 ; unpack nibbles into AH/AL (clobbers CF though) 
9D          POPF                    ; restore CF
72 02       JC   ODD                ; if odd index, use low nibble 
86 E0       XCHG AH, AL             ; otherwise is even, use high nibble 
        ODD: 
02 D0       ADD  DL, AL             ; add tile to score
E2 EE       LOOP LOOP_LETTER        ; loop through all letters
C3          RET                     ; return to caller
        TBL:
            DB 013H,032H,014H,024H,018H,051H,031H,013H,0A1H,011H,014H,048H,04AH

Try it online!

Note: using link above, re-run with input on command line like ASM ABC, etc.

As a callable function, input string at [SI], length in CX. Output to DX.

Explanation

Uses a score table of 4-bit nibbles for each tile's score. 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.

Test Program I/O

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Use a different BX so no need to sub al, 'A' \$\endgroup\$
    – l4m2
    May 21, 2023 at 4:36
1
\$\begingroup\$

Rockstar, 187 184 156 154 bytes

listen to W
cut W in S
cut W
while W
roll W in X
P's 1
cut "DG1BCMP1FHVWY1K111JX11QZ" in T
while T
roll T in L
let P be+L's 1
let S be+L's X and P


say S

Try it here (Code will need to be pasted in)

Abuses a nice little feature in Rockstar whereby the variable (S in this case) an array is assigned to can be used to reference both the array (e.g., S at index) or, by itself, the length of the array. So, by cutting the input Word into the array S we, straight away, have a base score of 1 point per letter.

listen to W        :Read input into variable W
cut W in S         :Split W into variable S (our score)
cut W              :Split W
while W            :While W is not empty
roll W in X        :  Pop first element of W into variable X
P's 1              :  Initialise P as 1 (base score for each tile)
cut "..." in T     :  Split "DG1BCMP1FHVWY1K111JX11QZ" into variable T
while T            :  While T is not empty
roll T in L        :    Pop first element of T into variable L
let P be+          :    Increment P by
  L's 1            :      Is L equal to 1?
let S be           :    Increment S by
  L's X            :      Is L equal to X?
  and P            :      Logical AND with P
                   :  End while loop
                   :End while loop
say S              :Output S
\$\endgroup\$
1
\$\begingroup\$

Thunno 2 S, 20 bytes

Ä⁻»yŒṄȦẏÄb¶Ỵɓæ»11Bsi

Attempt This Online!

Explanation

Ä⁻»yŒṄȦẏÄb¶Ỵɓæ»11Bsi  # Implicit input
Ä⁻                    # Convert input to 0-based indices in alphabet
  »yŒṄȦẏÄb¶Ỵɓæ»       # Compressed integer 140755590392038037755694497
               11B    # Converted to base 11 as a list:
                      # [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]
                      # (A, B, C, D, E, ...)
                  si  # Index into the list
                      # Implicit output of the sum
\$\endgroup\$
1
\$\begingroup\$

Vyxal rs, 20 bytes

øA11»⟑↑Gp→₃ꜝ¬∑"Ż¶»τİ

Try it Online!

port of thunno 2 answer but I needed an extra byte for the compressed number since vyxal cant zero index letters to numbers

\$\endgroup\$
1
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$
0
\$\begingroup\$

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!

\$\endgroup\$
3
  • \$\begingroup\$ Isnt the function signature part of the code? \$\endgroup\$ Apr 20, 2018 at 22:01
  • \$\begingroup\$ @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. \$\endgroup\$
    – Geoffrey
    Apr 21, 2018 at 22:54
  • \$\begingroup\$ I was wrong. It would appear we dont need to name the functions \$\endgroup\$ Apr 23, 2018 at 12:24
0
\$\begingroup\$

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'+@)
\$\endgroup\$
0
\$\begingroup\$

Julia 1.0, 49 bytes

!x=sum(i->b"\1\3\3\2\1\4\2\4\1\b\5\1\3\1\1\3\n\1\1\1\1\4\4\b\4\n"[i-'@'],x)

(the special characters are escaped here for clarity)

Try it online!

\$\endgroup\$
1
2

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.