# Can we spell a third number?

You are given two strings, each consisting of the English word for a number between 1 and 13:

one, two, three, four, five, six, seven, eight, nine, ten, eleven, twelve, thirteen


Your program or function must find out whether it's possible to spell at least one other word from the same list without using any of the letters used in the two input words.

You can follow this link to see a naive, ungolfed implementation along with the table of all possible I/O.

### Examples

• If the input is ['six', 'four'], we can spell 'ten', 'eleven' or 'twelve' so the answer is yes.

• If the input is ['five', 'seven'], we can only spell 'two' but the answer is still yes.

• If the input is ['one', 'six'], we cannot spell any other number so the expected answer is no.

### Rules

• You may take the words in any reasonable format. They can be in either lower case ('one'), upper case ('ONE') or title case ('One'), but it must be consistent.
• You may be given twice the same word.
• The order of the words is not guaranteed (i.e. your code must support both ['four', 'six'] and ['six', 'four']).
• You may return either truthy / falsy values (inverting the meaning is permitted) or two distinct and consistent values of your choice.
• This is .
• May we take input as integers instead of strings? Dec 4, 2020 at 17:04
• @RobinRyder No. I did consider that, but I think there are more possible approaches that way and it's still possible to come up with a shorter answer by turning the strings into 'some' numbers within your code. Dec 4, 2020 at 17:07
• Can we take input as a single string e.g. six four? Dec 4, 2020 at 17:18
• @cairdcoinheringaahing Yes, that's fine. Dec 4, 2020 at 17:19
• @thedefault. Xash's solution actually works up to at least twenty, or even "twentynine" if we concatenate the words. Dec 7, 2020 at 13:44

# J, 19 bytes

Takes input as six four. As the input range is limited, I just deleted characters while the output stayed the same. :-) Reads like "if there is no e in the input, or if there are no t and o in the input, … then we can spell another number."

e.etoforsi-.~&><


Try it online!

e.etoforsi-.~&><
&>< boxing stuff
etoforsi       for each e, to, for, si:
-.~      delete from the input any character from the list
e.                  is the input still in the results, i.e. is there any
case were no character got deleted?

• Nice answer! ;-) Dec 4, 2020 at 18:04

# Jelly, 15 bytes

“Œ}İs~#²ð»Ḳḟ@€i


Try it online!

Adaptation of xash's J answer. Returns a non-zero integer (truthy) for yes and 0 (falsey) for no. The footer generates all test cases and tests them (mapping truthy and falsey to 1 and 0 for readability)

My original answer was 38 bytes:

“}ICẸƁÄĊ}¿ȥ~ṢṄO4⁴ƓX9Ỵ9ÑẠỤẠḣ|¿;»ḲiⱮ€Q§Ạ


Try it online!

Returns a falsey value if the answer is yes and a truthy value otherwise

Basic naive compression approach, I'm sure there's a shorter answer out there that exploits some property that's shorter

Both input in the form six four

## How they work

“Œ}İs~#²ð»Ḳḟ@€i - Main link. Takes s on the left
“Œ}İs~#²ð»      - "e to for si"
Ḳ     - ["e", "to", "for", "si"]
€  - Over each k of these:
ḟ@   -   Yield s with characters in k removed
i - Index of s in this list or 0


And the 38 byte compression version:

“}ICẸƁÄĊ}¿ȥ~ṢṄO4⁴ƓX9Ỵ9ÑẠỤẠḣ|¿;»ḲiⱮ€Q§Ạ - Main link. Takes s on the left
“}ICẸƁÄĊ}¿ȥ~ṢṄO4⁴ƓX9Ỵ9ÑẠỤẠḣ|¿;»        - "one two ... twelve thirteen"
Ḳ       - Split on spaces
Q   - s deduplicated
€    - Over each number n:
Ɱ     -   Over each character c in s:
i      -     Index of c in n else 0
§  - Sums
Ạ - Does not contain 0


# Retina 0.8.2, 23 bytes

Gt|o
Gf|o|r
Gs|i
Ge


Try it online! Link includes all 169 possible inputs. Leaves the input unchanged if no numbers are possible, but outputs nothing if other numbers are possible. Explanation:

Gt|o


The input must contain t or o in order to prevent two from being possible; only two and twelve contain w, so if there's a w then t is already present.

Gf|o|r


The input must contain f, o or r in order to prevent four from being possible; only four contains u, so if there's a u then f, o and r are already present.

Gs|i


The input must contain s or i in order to prevent six from being possible; only six contains x, so if there's an x then s and i are already present.

Ge


The input must contain e in order to prevent eleven from being possible; only eleven and twelve contain l, only five, seven, eleven and twelve contain v, and only one, seven, nine, ten, eleven and thirteen contain n, so if there's an l, a v or an n then e is already present. Additionally, only two, four and six do not contain an e, so no other letters need to be tested.

• You followed the exact same chain of logic I used, just seven hours earlier than me. I don't think I can beat this Retina solution with this approach, so I'll just settle for upvoting yours. Dec 5, 2020 at 3:29
• @SilvioMayolo It looks as if xash beat me to it anyway. (I didn't understand his program, so I didn't realise it at the time, but XCali ported it, so it must be the same.)
– Neil
Dec 5, 2020 at 7:22

{|/(x~x^)'$etoforsi}  A port of @xash's excellent J answer. Try it online! # 05AB1E, 35 34 bytes J“€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁÏ“#€SåO0å  You must compress, if not, be distressed. Inputs as lowercase. Try it online! # How? J # Join the two input numbers into a string “€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š—¿áÓÁÏ“ # Push the number words from "one" to "thirteen" Så # Are each character in the input?numbers? 1 if yes, 0 if not € O # Sum the results for each word 0å # Is there a 0 on a word? # (implicitly) Print the answer  • You'll save a byte by taking input as a single string already (see comments to question). Dec 5, 2020 at 10:22 • You can save a byte by changing #€S to S#. Dec 7, 2020 at 8:23 # Japt-x, 14 bytes Adaptation of xash's J solution so be sure to upvote them, too. Input as a single lowercase delimited string, outputs a positive integer for true and 0 for false. èJ-n£qÍ£¶kX  Try it or try all possible pairs (with 1 used for true) # Python 3, 67 bytes lambda s:sum(max(c in p for c in s)for p in'e to for si'.split())<4  Try it online! Uses xash's idea from his J answer. # C (gcc), 130 128 102 bytes Saved 2 bytes thanks to ceilingcat!!! Saved a whopping 26 bytes thanks to AZTECCO!!! a,b,i;f(s,j)char*s,*j;{for(a=b=0,i=11;i--;i%3||(b+=!a,a=0))for(j=s;*j;)a+="e..to.forsi"[i]==*j++;b=b;}  Try it online! Uses xash's idea from his J answer. Inputs a string of two words separated by a space and returns a truthy value if it's possible to spell at least one other word from the given list without using any of the letters used in the two input words or a falsy value otherwise. • You can get rid of one loop for 102 , I think still golfable Dec 6, 2020 at 3:45 • @AZTECCO Very nice - thanks! :D Dec 6, 2020 at 10:28 • What is the purpose of the b=b;? I don't see it. Dec 27, 2020 at 4:40 • @EasyasPi Because gcc uses the same register for assignment and return value, so this saves bytes over return b;. Dec 27, 2020 at 12:20 # Perl 5-p, 8328 26 bytes Credit to @NahuelFouilleul for saving 2 bytes $_=/e/&/t|o/&/[for]/&/i|s/


Try it online!

Switched to @xash's method. This script inverts the output: 0 means that another number can be formed; 1 means that another number cannot be made.

• 26 bytes Dec 5, 2020 at 10:11
• @NahuelFouilleul Might as well use f|o|r for consistency (I did that in my Retina answer).
– Neil
Dec 6, 2020 at 11:12

# Python 2, 56 bytes

lambda s:all(set(x)&set(s)for x in"e to for si".split())


Try it online!

Take inputs like two four, outputs negated. Checks whether the string has an e, and intersects the non-e numbers of two, four, and six.

52 bytes in Python 3 using {*x} for set(x).

• 52 bytes Dec 5, 2020 at 12:34

# Bash, 857461 53 bytes

Supply the input as an argument of the program. Output is via exit code.

[[ -z for i in e to for si;{ grep -v [$i]<<<$1;} ]]


Try it online!

# Python 3.8 (pre-release), 175164 146 bytes

def f(x):w="oe two tre for fie si se eit ie te e twe tire".split();return[[(w:=[*filter(lambda a:c not in a,w)])for c in i]for i in x][-1][-1]!=[]


Try it online!

saved 8 bytes with the help of member SunnyMoon

saved 18 bytes with the help of member Neil

normal version of the code:

def f(x):
w="oe two tre for fie si se eit ie te e twe tire".split()
for i in x:
for c in i:
w = [*filter(lambda a:c not in a, w)]
return w != []

• You can improve this by removing duplicate characters, i.e one,two,thre,four,five,six,sevn,eight,nie,ten,elvn,twelv,thiren, I guess Dec 4, 2020 at 17:52
• @SunnyMoon You can also remove u, x and g since they never appear in other words.
– Neil
Dec 4, 2020 at 18:51
• @SunnyMoon Also the letters h, l, n and v only appear in words with e, and w only appears in words with t, so they don't make any difference.
– Neil
Dec 4, 2020 at 18:56

# Charcoal, 19 bytes

⊙⪪”&↓εg⌕⁸¡⁼”a⬤ι¬№θλ


Try it online! Port of my Retina answer, but I was able to output a Charcoal boolean, i.e. - for possible, nothing for impossible. Explanation:

  ”&↓εg⌕⁸¡⁼”        Compressed string eatoaforasi
⪪          a       Split on a
⊙                   Any substring satisfies
⬤ι     All characters of substring satisfy
¬№θλ Character not present in input
Implicitly print


# Ruby 2.7-n, 45 bytes

+1 to the idea of xash in his J's answer!

p %w[e to for si].any?{$_.chars&_1.chars==[]}  Try it online! # Ruby 2.7 + gem install humanize, 61 bytes require'humanize' f=->v{(1..13).any?{_1.humanize.count(v)<1}}  # Ruby 2.7-n, 104 90 bytes Saved 10 bytes by removing duplicate chars from number names. p %w[one two thre four five six sevn eight nie ten elvn twelv thiren].any?{_1.count($_)<1}


Try it online!

TIO uses an older version of Ruby, while in Ruby 2.7, we've numbered parameters, i.e., _1, which saves 2 bytes.

# Jelly, 39 37 bytes

ị“½ĠWufṠßṡƝ0:Ƒ’bȷ¤æ»
OUḅ96%191%⁵)ç/Ḃ


Try it online!

-2 bytes thanks to @xigoi

Takes input as a list of two words in lowercase.

### How it works

Uses a lookup table for all pairs. Instead of a 13×13 lookup table, this uses a 10×10 table because a few number/words (1&3, 2&4, 7&9, 10&12) have the same table values, so I engineered a hash with very specific collisions using a brute force script.

A 9×9 table is theoretically possible, but I doubt that it will save bytes due to a more complex hash function.

Lookup table generator after computing the hashes.

OUḅ96%191%⁵            # hash function
OUḅ96                    # character codepoints interpreted in reverse as a base 96 number
%191%⁵              # mod 191 then mod 10

ị“½ĠWufṠßṡƝ0:Ƒ’bȷ¤æ»  # lookup table
ị“½ĠWufṠßṡƝ0:Ƒ’bȷ¤      # get the correct row from a list of 10 rows corresponding to the hash of the first word
# (base-250 compression then interpret as base 1000)
æ»    # bitshift by the amount corresponding to the hash of the second word

Ñ€ç/Ḃ     # apply the lookup table and hash. For some reason I couldn't get ÑçÑḂ to work.

• ÑçÑ}Ḃ works, not that it saves any bytes Dec 4, 2020 at 19:45
• Why not inline the hash function for 37 bytes? Dec 4, 2020 at 22:31

# Husk, 14 12 bytes

Edit: -2 bytes thanks to Razetime

Λn⁰w¨toƒr¹∫e


Try it online!

Outputs falsy (0) if we can spell another letter without the input letters, truthy (non-zero) otherwise.

Uses approach of checking whether any of the input letters are present in "to", "for", "is" or "e", as pioneered by xash's answer.

Λ               # are all these elements truthy?
n              # are there intersecting elements of
⁰             # input
# in each of
w¨toƒr¹∫e    # "to","for","is","e"

• You can use Λ here: Try it online! Dec 7, 2020 at 8:32
• -2 bytes with n: Try it online! Dec 7, 2020 at 8:33
• @Razetime - Thanks & thanks! Really nice! I was hoping that it would be possible for Husk to be the shortest answer (at least so far), but just needed those extra tips! Dec 7, 2020 at 9:10

for i (e to for si)grep [$i] f  Try it online! (includes all combinations) Takes input from a file named f, outputs via exit code (0 = we can't spell a third word, 1 = we can). The option -F disables globbing; without it, we would have to escape the square-brackets. -e makes zsh exit on the first command that fails - it's like a short-circuiting NOR over all the commands executed, similar to the approach in this great J answer. Also takes inspiration from this Bash answer. # Haskell, 44 bytes f a=any(not.any(elema))$words"e to for si"


Try it online!

• Uses xash's idea from his J answer.
• Takes input as "one,two" and returns True for yes, False for not.
• I think it reads well as it is so no explanation.

# R, 87 bytes

function(x,u=utf8ToInt)all(sapply(c('to','for','si','e'),function(m)any(u(m)%in%u(x))))


Try it online!

Reversed output: TRUE if we cannot spell another number without the input letters.

Started with the full vector "one","two","three" ... "thirteen","fourteen", then removed the duplicate letters, then removed the only-in-one-number letters, then removed the letters in words that consistently had another letter. This brought the vector to "oe","to","tre" ... "e","te","tire". At this point it was obvious that we can delete all numbers containing an "e" except "e" (which is what's left of "eleven").

And then I realised that I'd just re-created xash's answer.

Well done, xash!

• I'd also re-created xash's answer, but I didn't realise until I read XCali's port, as I was sadly unable to understand xash's explanation. (On the other hand I needed no explanation to read XCali's code.)
– Neil
Dec 6, 2020 at 11:12

# 05AB1E, 14 bytes

“e€‡€ˆ€„“#€мQà


Port of @xash' J answer, so make sure to upvote him!

Also takes the input as a single (space-delimited) string.

Explanation:

 “e€‡€ˆ€„“       # Push dictionary string "e for is to"
#      # Split it on spaces: ["e","for","is","to"]
€м    # For each: remove all those characters from the (implicit) input
Q   # Then check for each if they're still equal to the (implicit) input
à  # And check if any of the four were truthy by taking the maximum
# (after which this result is output implicitly)


See this 05AB1E tip of mine (section How to use the dictionary?) to understand why “e€‡€ˆ€„“ is "e for is to".

# JavaScript (Node.js), 9995 78 bytes

x=>y=>!'e to for si'.split .filter(m=>![...m].some(k=>(x+y).includes(k)))[0]


Try it online!

Uses xash's idea from his J answer.

Returns false for yes and true for no (counterintuitive I know, deal with it). Uses currying syntax - (x)(y).

Explanation:

x=>                           //declare function
y=>                         //declare function 2
!                         // necessary for consistent result
'e to for si'             //see xash's J answer
.split                  // to array
.filter(                  //keep value only if following true
m=>                     //function with value m
!                     //if following is false
[...m]                //m into array of letters
.some(                //replace each with
k=>                 //function of k
(x+y).includes(k) //if includes true (input contains one of word
)
)                      // array now has any items only if it contains something
[0]                        //0th item, undefined if no answers, one of strings above if does, then negated by ! at top.


There's got to be a better way to do all the .includes.

^([^e]*|[^to]*|[^for]*|[^si]*)$ Just using @xash's trick again. Takes a single string. # Javascript, 44 bytes (using regex) x=>/^([^e]*|[^to]*|[^for]*|[^si]*)$/.test(x)


I mean it works, but I like the other one because it took more than 2 minutes. Takes a single string.