52
\$\begingroup\$

Some versions of the standard Android calculator app allow you to press a key, like 'sin' and then the 'del' key to make it 'si'. Probably just a bug which they can't be bothered with removing.

Screenshot of Android calculator

The following letters/letter groupings are typable:

 

sin
si
s
cos
co
c
tan
ta
t
ln
l
log
lo
e

So, 'tasteless' is typable, because ta-s-t-e-l-e-s-s and so is 'clogs' because 'c-log-s'. However 'got' is not typable, neither is 'an' or 'xyz'.

Write a program that takes a single word (or sequence of letters, only a-z in input) as input and produces output to indicate if a word is typable or not.

Output may be a single character/letter/digit/etc. or it may be larger. All typable words should produce the same output. All non-typable words should also produce the same output.

P.S. Just out of curiosity, is 'tasteless' the longest dictionary word that is typable?

\$\endgroup\$
  • 1
    \$\begingroup\$ Just to be clear: We output a single, consistent digit or letter of our choice to indicate the word is typeable, and a different, single, consistent digit or letter of our choice to indicate the word is not typeable. Is that correct? \$\endgroup\$ – Dennis Dec 4 '16 at 16:36
  • 3
    \$\begingroup\$ The longest word I could find is 10 letters, coelostats. \$\endgroup\$ – Conor O'Brien Dec 4 '16 at 21:48
  • 1
    \$\begingroup\$ So, is "πe" not a word? \$\endgroup\$ – Mr Lister Dec 5 '16 at 9:15
  • \$\begingroup\$ @Dennis Ya, more or less. \$\endgroup\$ – ghosts_in_the_code Dec 5 '16 at 14:43
  • 1
    \$\begingroup\$ Another 11: sissinesses \$\endgroup\$ – Chris H Dec 6 '16 at 13:29

15 Answers 15

20
+50
\$\begingroup\$

Perl, 47 43 41 + 1 = 42 bytes

-4 bytes thanks to @Sunny Pun. -2 bytes thanks to @Brad Gilbert b2gills and @Downgoat

Run with the -n flag.

say!/^(s(in?)?|co?|t(an?)?|ln?|log?|e)+$/

It can definitely be golfed futher, but in the spirit of competition, I'm leaving the mostly-original regex I came up with at the beginning. Returns nothing if true, 1 if false.

Try it online!

I downloaded a dictionary file, and the longest word I found was 11 letters -- tattletales

\$\endgroup\$
  • 1
    \$\begingroup\$ I think co? should be sufficient since sin will take care of the s :) Nice playing with /log?/! \$\endgroup\$ – Sunny Pun Dec 4 '16 at 16:49
  • 1
    \$\begingroup\$ It doesn't say that it needs to be case insensitive (remove i), or that the single result has to make sense (remove one !) \$\endgroup\$ – Brad Gilbert b2gills Dec 4 '16 at 18:19
  • \$\begingroup\$ Do you need i flag at very end since input is only a-z? \$\endgroup\$ – Downgoat Dec 5 '16 at 15:04
  • \$\begingroup\$ You can make this simpler: -2: /^(s|sin?|co?|t|tan?|ln?|log?|e)+$/ or if you prefer: /^([celst]|sin?|co|tan?|ln|log?)+$/ \$\endgroup\$ – Not that Charles Dec 5 '16 at 22:49
  • 1
    \$\begingroup\$ Enjoy your bounty! \$\endgroup\$ – ghosts_in_the_code Dec 13 '16 at 17:03
16
\$\begingroup\$

JavaScript (ES6), 44 bytes

s=>/^((si|ta|l)n?|co?|log?|[ste])+$/.test(s)

I think this is the shortest regex possible, but of course I may be wrong.

Explanation

An obvious first place to start would be a regex that simply includes all options separately:

s=>/^(sin|si|s|cos|co|c|tan|ta|t|log|lo|l|ln|e)+$/.test(s)

First, we can observe that cos can be formed from co and s, making it unnecessary:

s=>/^(sin|si|s|co|c|tan|ta|t|log|lo|l|ln|e)+$/.test(s)

Some of these, such as sin and si, can be combined by making the last letter optional:

s=>/^(sin?|s|co?|tan?|t|log?|ln?|e)+$/.test(s)

This works because sin? matches si with or without an n on the end, thus covering both sin and si.

There seems to be a lot of n?s as well. What if we put them all together?

s=>/^((si|ta|l)n?|s|co?|t|log?|e)+$/.test(s)

One more way to golf this would be to combine the remaining single-char options into a character range, but this comes out at the same length:

s=>/^((si|ta|l)n?|co?|log?|[ste])+$/.test(s)

And that's how you golf a simple regex. I believe this is the shortest possible regex that matches every string correctly, but perhaps not. I will award a +100 bounty to anyone who manages to improve upon this regex.

\$\endgroup\$
  • \$\begingroup\$ The one that I used in my answer is sort of similar: ^(s|t|co?|(l|ta|si)n?|log?|e)+$ \$\endgroup\$ – Mama Fun Roll Dec 4 '16 at 21:23
  • \$\begingroup\$ Firstly, I count 44 bytes. Secondly, here's an alternate but longer solution: / /.test.bind(/^((si|ta|l)n?|co?|log?|[ste])+$/). \$\endgroup\$ – Conor O'Brien Dec 4 '16 at 21:41
  • \$\begingroup\$ @ConorO'Brien Whoops, don't know how I miscounted that... \$\endgroup\$ – ETHproductions Dec 4 '16 at 22:48
  • \$\begingroup\$ You can do a=/^((si|ta|l)n?|co?|log?|[ste])+$/;a.test for 42 bytes. I believe this is allowed, because a.test is an anonymous function. \$\endgroup\$ – NoOneIsHere Dec 6 '16 at 1:39
  • \$\begingroup\$ @SeeOneRhino It is, but it's not really allowable because f=a.test doesn't work. I wonder if it's acceptable to call with the alternate name a.test though... \$\endgroup\$ – ETHproductions Dec 6 '16 at 1:52
7
\$\begingroup\$

Pyth, 37 33 29 28 bytes

The code contains an unprintable character, so here is an xxd hexdump.

00000000: 737d 5173 4d5e 733c 5252 6336 2e22 6174  s}QsM^s<RRc6."at
00000010: 14d0 69ba 76f1 ac59 6422 346c            ..i.v..Yd"4l

Try it online.

Extremely Astronomically inefficient. The time and space complexity is O(16n) O(24n).

Explanation

First, a Q is implicitly appended.

s}QsM^s<RRc6."…"4lQ     Implicit: Q = input
            ."…"        Generate "logsincostanlnee"
          c6            Split in 6 parts: ["log", "sin", "cos", "tan", "ln", "ee"]
         R      4       For each n from 0 to 3
       <R               Take the first n chars from each string
      s                 Flatten the results
                 lQ     Get length of input
     ^                  Take that Cartesian power of the list
   sM                   Join each resulting list
 }Q                     Check if the input is found
s                       Cast to integer
\$\endgroup\$
  • \$\begingroup\$ The OP has clarified; you don't need the s. \$\endgroup\$ – Dennis Dec 5 '16 at 20:07
6
\$\begingroup\$

Jelly, 32 31 30 28 26 bytes

ŒṖw@€€“¡Ṡ[ẈKœịḲ-¢ȧ?-»’%3ḌẠ

Outputs 0 if the word is typeable, 1 if not. Thanks to @JonathanAllan for golfing off 1 byte!

Try it online!

How it works

ŒṖw@€€“¡Ṡ[ẈKœịḲ-¢ȧ?-»’%3ḌẠ  Main link. Argument: s (string of lowercase letters)

ŒṖ                          Yield all partitions of s.
      “¡Ṡ[ẈKœịḲ-¢ȧ?-»       Yield "sine  logcostanln". Every third character
                            marks the start of a typeable word.
  w@€€                      Find the indices of all substrings in the partitions
                            in the string to the right (1-based, 0 if not found).
                     ’      Decrement. "Good" indices are now multiples of 3.
                      %3    Modulo 3. "Good" indices are mapped to 0, "bad"
                            indices are mapped to 1 or 2.
                        Ḍ   Convert from decimal to integer. A partition will
                            yield 0 iff all indices are "good".
                         Ạ  All; yield 0 if one or more integers are falsy (0), 1
                            if all integers are truthy (non-zero).
\$\endgroup\$
6
\$\begingroup\$

Brachylog, 33 bytes

Fixed a bug thanks to @Synoli.

~c:1a
,"sincostanloglneeee"@6e@[?

Try it online!

Outputs true. if typeable or false. otherwise.

Explanation

We try deconcatenations of the input until we find one for which all strings that we concatenate are a prefix of one of ["sin", "cos", "tan", "log", "lne", "eee].

~c                          A list of strings which when concatenated results in the Input
  :1a                       All strings of this list satisfy the predicate below:

,"sincostanloglneeee"@5           The list ["sin", "cos", "tan", "log", "lne", "eee"]
                       e          Take one element of that list
                        @[?       The input is a prefix of that element
\$\endgroup\$
  • \$\begingroup\$ Why the . after true? \$\endgroup\$ – Cows quack Dec 4 '16 at 18:22
  • 1
    \$\begingroup\$ @KritixiLithos In SWI-Prolog when a query is true it prints true. and false. otherwise. i just reimplemented this: if the output is ignored (as it is here) and there is no writing to STDOUT, then it will print true. or false. depending on whether the main predicate succeeds or fails. It has a dot in SWI-Prolog because true. and false. are actually valid programs which always succeeds/always fails. \$\endgroup\$ – Fatalize Dec 4 '16 at 18:26
  • \$\begingroup\$ How does this solution work without tan explicitly appearing in the list? \$\endgroup\$ – Synoli Dec 11 '16 at 23:49
  • 2
    \$\begingroup\$ @Synoli It doesn't. I fixed it at the cost of 3 bytes, thanks. \$\endgroup\$ – Fatalize Dec 12 '16 at 7:53
4
\$\begingroup\$

Perl 6,  60 50  44 bytes

first attempt (60)

put +?(get~~/^<{<sin cos tan ln log e>».&{|m:ex/^.+/}}>*$/)

translation of the Perl 5 answer (50)

put +?(get~~/^[s[in?]?|co?|t[an?]?|ln?|log?|e]*$/)

using -n switch (43+1)

put +?/^[s[in?]?|co?|t[an?]?|ln?|log?|e]*$/

The first ? converts the result to Boolean, and the first + converts that to a number (1 for True, 0 for False)

\$\endgroup\$
3
\$\begingroup\$

Mathematica, 101 bytes

If[StringMatchQ[#,("sin"|"si"|"s"|"cos"|"co"|"c"|"tan"|"ta"|"t"|"ln"|"l"|"log"|"lo"|"e")..],"T","F"]&

It seems that the hard parts of this challenge are coming up with the shortest regex and choosing the most concise language to match the regex. I don't have anything to contribute to the former, and Mathematica isn't good candidate for the latter since you have to use StringMatchQ and RegularExpression. What I can do is answer your P.S.: is "tasteless" the longest word that you can type?

In[1]:= f=StringMatchQ[#,("sin"|"si"|"s"|"cos"|"co"|"c"|"tan"|"ta"|"t"|"ln"|"l"|"log"|"lo"|"e")..]&;

In[2]:= Select[EntityList@"Word",f@#[[2,1]]&][[All,2,1]]//SortBy[StringLength]//DeleteDuplicates
Out[2]= {c,e,l,s,t,cc,cl,el,et,lo,si,sl,ta,te,ccc,col,cos,cot,eel,ell,eta,etc,lee,let,log,lot,sec,see,set,sic,sin,sit,tae,tan,tat,tec,tee,cell,clog,clot,coco,cole,colt,coss,cost,cote,else,less,loco,loge,loll,lose,loss,lota,sect,seel,sell,sess,seta,sett,sill,silo,silt,sine,sise,siss,site,sloe,slog,slot,stet,taco,tact,tael,talc,tale,tall,tect,tell,test,cello,close,cosec,costa,cotan,eccle,elect,elsin,ettle,loess,lotte,secle,setee,since,sleet,stale,stall,state,steel,stele,tasse,taste,tatee,teest,telco,testa,tetel,tsine,cellco,closet,coleta,collet,coltan,cosine,cosset,costal,ecesis,estate,lessee,scelet,select,sellee,sestet,settee,settle,siesta,silole,stacte,stance,stasis,tallet,tallot,taslet,tassel,tasset,tattle,tectal,teetan,tellee,testee,tsetse,celesta,cessile,cocotte,collect,costate,ecolect,ectasis,electee,sessile,sinless,sitelet,statant,tassell,tastant,testate,coestate,colessee,colocolo,cosiness,costless,electant,lossless,sceletal,siletane,statelet,tactless,tallness,telltale,telocoel,coelostat,sissiness,stateless,tasteless,tattletale}

So "tattletale" seems to be the longest by one character.

\$\endgroup\$
  • \$\begingroup\$ Why is this non-competing? Does the function f you define not comply with the rules of the challenge? \$\endgroup\$ – Dennis Dec 4 '16 at 17:23
  • \$\begingroup\$ No, it outputs True or False rather than a single character. \$\endgroup\$ – ngenisis Dec 4 '16 at 17:25
  • \$\begingroup\$ Posts tagged with decision-problem are about determining True/False, so I think this is competing. \$\endgroup\$ – FlipTack Dec 4 '16 at 17:29
  • \$\begingroup\$ Non-competing status is reserved for submissions that use a language or language feature that didn't exist or had a bug when the challenge was posted. \$\endgroup\$ – Dennis Dec 4 '16 at 17:29
  • \$\begingroup\$ Fair enough. I edited my answer to have an actual solution. \$\endgroup\$ – ngenisis Dec 4 '16 at 17:36
2
\$\begingroup\$

Wonder, 41 bytes

!.(mstr"^(s|t|co?|(l|ta|si)n?|log?|e)+$")

Usage:

(!.(mstr"^(s|t|co?|(l|ta|si)n?|log?|e)+$")) "tasteless"

Totally misunderstood the question before, but now it's all fixed. Outputs F for match and T for no match.

Noncompeting, 35 bytes

!.`^(s|t|co?|(l|ta|si)n?|log?|e)+$`

Usage:

(!.`^(s|t|co?|(l|ta|si)n?|log?|e)+$`) "tasteless"

This makes use of applicable regexes, which was implemented after this challenge.

\$\endgroup\$
  • 2
    \$\begingroup\$ From my understanding, you can only delete the last character in the calculator, which means n in not typable but sin and ln are. \$\endgroup\$ – Sunny Pun Dec 4 '16 at 16:23
  • \$\begingroup\$ This regex detects sa as true \$\endgroup\$ – Cows quack Dec 4 '16 at 16:27
  • 1
    \$\begingroup\$ This fails the test case got. \$\endgroup\$ – Dennis Dec 4 '16 at 16:30
  • \$\begingroup\$ I believe it's fixed. \$\endgroup\$ – Mama Fun Roll Dec 4 '16 at 16:57
  • \$\begingroup\$ The ? make the sub expression docile; see rexegg.com/regex-quantifiers.html#cheat_sheet. But even making it greedy with ?? or possessive with ?+ doesn´t work for some reason (at least in PHP). coelostats triggers the trap (at lo and ta). \$\endgroup\$ – Titus Dec 6 '16 at 12:19
2
\$\begingroup\$

Processing, 223 bytes

int d(String b){for(String p:"tan0log0sin0cos0ln0e".split("0"))if(p.startsWith(b))return 1;return 0;}

int l(String p){String b="";int t=1;for(char c:p.toCharArray()){b+=c;if(d(b)<1){b=c+"";t=d(b);}if(t<1)return t;}return t;}

Finally decided to do an answer without regex. To call the function, use l("tasteless");. Returns 0 for false and 1 for true.

Expanded code with explanation

int d(String b){
  for(String p:"tan0log0sin0cos0ln0e".split("0"))
    if(p.startsWith(b))
      return 1;
  return 0;
}
//main function
int l(String p){
  String b="";
  int t=1;
  for(char c:p.toCharArray()){
    b+=c;
    if(d(b)<1){
      b=c+"";
      t=d(b);
    }
    if(t<1)return t;
  }
  return t;
}

Basically, we iterate over the given string, building up b char by char. We check using d() if any of the tan,log,... start with b. If it does, then it is valid. Else, we check if the char at that position is valid and we reset b. Now if it is invalid, 0 will be returned, or else it will still be valid. At the end, if the program hasn't already returned something, then return 1.

\$\endgroup\$
  • \$\begingroup\$ Can't the d function return a bool? \$\endgroup\$ – Roman Gräf Dec 5 '16 at 13:55
  • \$\begingroup\$ @RomanGräf It is more bytes to use boolean than int. Also true and false require more bytes than 1 and 0 \$\endgroup\$ – Cows quack Dec 5 '16 at 14:03
2
\$\begingroup\$

Scala, 49 bytes

s=>s.matches("(s(in?)?|co?|t(an?)?|ln?|log?|e)+")

Returns true if the given string matches the regex, false otherwise.

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

Python 3, 154 bytes

r=1;i=input()
while r:
 r=0
 for s in'sin,cos,tan,log,ln,co,lo,si,ta,s,c,t,l,e'.split(','):
  if i.startswith(s):r=i=i.replace(s,'',1);break
print(i=='')

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ You might need to check indentation, I had to edit the code to make it work \$\endgroup\$ – george Dec 5 '16 at 10:02
  • \$\begingroup\$ @george, weird, I tried in IDLE and the online compiler, and both seem to work \$\endgroup\$ – Henke Dec 5 '16 at 17:38
2
\$\begingroup\$

Python 3, 149 130 bytes

i=input()
for a in 'tan,sin,cos,log,si,co,ta,lo,lo,ln,s,c,t,l,e'.split(','):
    if a in i:
        i=i.replace(a,"")
print(not i)

edit #1: shaved 19 bytes using @Henke solution

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

Python 2, 124 bytes

f=lambda w:any(f(w[len(s):])if w[:len(s)]==s else 0for s in'sin,cos,tan,log,ln,co,lo,si,ta,s,c,t,l,e'.split(','))if w else 1
\$\endgroup\$
0
\$\begingroup\$

PHP, 60 bytes

<?=preg_match("#^((si|ta|l)n?|co?|log?|s|e|t)+$#",$argv[1]);

regex stolen from ETHproductions:
takes input from command line argument; prints 1 for typable, 0 for not typeable.

older versions, 75 73 69 bytes

<?=!preg_replace("#co|log|ln|lo|sin|si|tan|ta|[celst]#","",$argv[1]);

replaces all possible words with empty string, returns the result, negates.

<?=!preg_split("#co|log|ln|lo|sin|si|tan|ta|[celst]#",$argv[1],-1,1);

splits input by regex matches. Flag 1 stands for PREG_SPLIT_NO_EMPTY and tells preg_split to only return non-empty results. If input is typable, preg_split will only have empty results, so it will return an empty array, which is falsy. ! negates the result.

Both versions take input from command line argument
and print 1 if result is empty (input is typable), else nothing.

Notes:
Packing the regex using ? does not work here; it renders the expressions ungreedy; probably due to backtracking. And the order of the alternatives is important: ta has to stand before t or the engine will stop matching when it finds t.

I found a quantifier cheat sheet, thought ?? or ?+ might help; but they did not work for me.

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

Java 8, 55 bytes

s->return s.matches("^((si|ta|l)n?|co?|log?|[ste])+$");

Disclamer: I used ETHproductions' regex because it was many bytes shorter than mine. Full credit on the Regex to him. What I did was add 24 bytes to make it a Java function.

Returns false if the word did not fit into the Regex, else true.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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