Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Given a string, return that string's "luck".

A string's luck, as I completely just made up for the purpose of this challenge, is an integer, determined as so:

  • The base luck for a string is 1.
  • For each consecutive letter it shares with the word "lucky" (case insensitive), multiply the luck by 2. For instance, if your string was "lumberjack" or "smack" you'd multiply by 4. (More specifically, 2^number of consecutive characters shared.)
    • The shared letters have to be in the same consecutive order it appears in "lucky" but can start anywhere in the word for the same value ("luc" has the same 8* multiplier as "cky").
    • If the word has multiple occurrences where it shares consecutive characters with lucky, use the longest consecutive string of the characters.
  • For ANY letter it shares with the word "omen" subtract 2 from the luck.
    • It can match a character any amount of times, in any order. For instance the string "nnnnnomemenn" loses 24 luck (12 matching letters)

Example:

luck("lucky")
>>32

2^5 (5 consecutive letters) = 32

luck("firetruck")
>>6

2^3 - 2 (3 consecutive letters from uck, e shared with omen)

luck("memes")
>>-7

1 - 8 (base amount, 4 shared with "omen")

This is code golf, so the answer with the fewest bytes wins.

You can input and output any way you'd like - write a function, use standard input, etc.

For functions, assume whatever data type would make sense for that language. (For example, in JavaScript, you'd be passed a String and return a Number)

Edit: You can assume any input is lowercase.

share|improve this question
8  
Nice first challenge! – Alex A. 2 days ago
2  
Should the program accept uppercase input? – busukxuan 2 days ago
2  
@busukxuan Good question - no, it doesn't need to accept uppercase input. – charredgrass 2 days ago
    
@cat Not sure I quite understand what you're asking. But you can just assume all input will be lowercase and you don't need to catch any uppercase input. – charredgrass 2 days ago
1  
Can we assume an upper or lower bound on the luck of a given input? i.e. what's the smallest number of bits / data type I can get away with, or is it as big as my language can handle? that is, should it be int8_t str_luck(const char* str); or should it be uint64_t str_luck(const char* str);? – cat 2 days ago

15 Answers 15

up vote 6 down vote accepted

05AB1E, 36 32 28 26 bytes

Œv'¸éyåiyˆ}}¯é¤go¹'ƒÖ¦Ãg·-

Explanation

Œv         }                  # for each substring of input
  '¸éyåi  }                   # if substring is part of "lucky"
        yˆ                    # add it to global array
            ¯é¤               # get the longest such substring
               go             # raise 2 to its length
                 ¹'ƒÖ¦Ã       # remove all chars from input that isn't in "omen"
                       g·     # get length and multiply by 2
                         -    # subtract
                              # implicitly display

Try it online

Saved 2 bytes thanks to Adnan

share|improve this answer
    
Compression for 1 word can also be done with ', so for 26: Œv'¸éyåiyˆ}}¯é¤go¹'ƒÖ¦Ãg·- :). – Adnan 2 days ago
    
@Adnan: Weird. I was certain I had tried that. Apparently not. Thanks! – Emigna 2 days ago
    
why isn't this the top answer? – uoɥʇʎPʎzɐɹC yesterday

Pyth, 27 26 28 bytes

-^2le+k}#"lucky".:Q)yl@"omen

1 byte saved thanks to OP :-)

Explanation:

                                 Implicit Q as input
                .:Q              Find all substrings of input
     +k}#"lucky"                 Filter for substring of "lucky", prepend "" in case of []
    e                            Take last element, which is longest
   l                             Get its length
 ^2                              Raise two to that
                      @"omen"Q   Filter Q for characters in "omen"
                     l           Get length; counts how many characters in "omen" there are
                    y            Double that
-                                Find the difference

Test it here.

share|improve this answer
1  
I'm not an expert in Pyth but I believe you can change "omen" to just "omen and Pyth will understand – charredgrass 2 days ago
    
@charredgrass Oops, my mistake :-) – busukxuan 2 days ago
1  
Doesn't seem to work for string without chars form "lucky" in it. "memes" for example. – Emigna 2 days ago
1  
@Emigna Ah. the zero case again.... Thanks, fixed it! – busukxuan 2 days ago

Ruby, 91 87 bytes

String#count's finnicky usage strikes again! (When passed a String, it counts all occurrences of each letter in the function argument instead of all occurrences of the entire string.)

Try it online

->s{2**(z=0..5).max_by{|j|z.map{|i|s[b="lucky"[i,j]]?b.size: 0}.max}-2*s.count("omen")}

A version that takes in lines from STDIN and prints them: 89 bytes (86 +3 from the -n flag)

p 2**(z=0..5).max_by{|j|z.map{|i|$_[b="lucky"[i,j]]?b.size: 0}.max}-2*$_.count("omen")
share|improve this answer
1  
._. that String#count is weird. +1 for (ab)using it. Also is it shorter to use gets rather than a function? – Downgoat 2 days ago
1  
@Downgoat if I gets I also has to puts for output, so not in this case. – Kevin Lau - not Kenny 2 days ago

Ruby: 100 bytes

->s{2**(m=0;4.times{|j|1.upto(5){|i|m=[i,m].max if s.match"lucky"[j,i]}};m)-s.scan(/[omen]/).size*2}
share|improve this answer
    
Try /[omen]/ as the regex to golf it down - it will match any character and is better in practical use than chaining |s for single characters. – charredgrass 2 days ago
    
Thanks! Ya that's a good idea. – addison 2 days ago

JavaScript (ES7), 123 112 107 bytes

s=>2**[5,4,3,2,1,0].find((i,_,a)=>a.some(j=>s.includes("luckyL".substr(j,i))))-2*~-s.split(/[omen]/).length

Edit: Saved 11 bytes thanks to @Titus by assuming that the letter L does not appear in the input. Saved 5 bytes thanks to @Oriol. ES6 version for 125 114 109 bytes:

f=
s=>(1<<[5,4,3,2,1,0].find((i,_,a)=>a.some(j=>s.includes("luckyL".substr(j,i)))))-2*~-s.split(/[omen]/).length
;
<input oninput=o.textContent=f(this.value)><pre id=o></pre>

share|improve this answer
    
Why do you use replace([^]) instead of match([])? Do you waste 3 bytes or is there a reason? – Titus 2 days ago
    
@Titus How many bytes does it cost to deal with a null match result? – Neil 2 days ago
1  
Four for a string, and a pair of () in this case; eating up all six that you would save with match(/[omen]/). Pity. – Titus 2 days ago
1  
@Titus Not sure if that's what you meant but by adding an L to the end of the substr (which will never appear in the original string) I don't have to worry about extraneous matches and I can actually use the same array [5,4,3,2,1,0] both times, saving a whopping 13 bytes! – Neil yesterday
1  
-2*s.split(/[omen]/).length+2 is shorter. – Oriol yesterday

Javascript - 206 Bytes

r=>{var a="lucky";r:for(var e=5;e>0;e--)for(var n=0;6>n+e;n++){var o=a.substring(n,e+n);if(r.includes(o))break r}for(var t=0,e=0;e<r.length;e++)('omen'.indexOf(r[e])+1)&&t++;return Math.pow(2,o.length)-2*t}
share|improve this answer
1  
You could change this condition: s[k]=='o'||s[k]=='m'||s[k]=='e'||s[k]=='n' to look like this: "oman".split("").includes(s[k]) – addison 2 days ago
1  
Welcome to PPCG! You can golf this down by removing whitespace to conserve bytes. Also, instead of (s[k]=='o'||s[k]=='m'||s[k]=='e'||s[k]=='n') you could use ('omen'.indexOf(s[k])+1) (assuming this is JavaScript) – charredgrass 2 days ago
    
Thanks for the tips! Got it down to 237, although it looks like the Ruby crowd's got me beat. – Christopher Burgdorff 2 days ago
    
Another small thing: you can shorthand function luck(r) down to r=> to just make it an anonymous function, that's all that is necessary for this challenge. Also I made an edit to the challenge so you don't have to worry about case so you can remove the r=r.toLowerCase(); – charredgrass 2 days ago
    
Instead of substring you can use slice i believe (test this though, as I'm not sure) – Downgoat 2 days ago

hashmap, 38 bytes (non-competing)

Non-competing, however, because hashmap can't do consecutive orders yet.

i&sl"[^lucky]"-L2#^:n"[^omen]"-L2*;n#-

Explanation:

i&sl"[^lucky]"-L2#^:n"[^omen]"-L2*;n#-
i&sl                                   Get input, duplicate, lowercase
    "[^lucky]"-                        Remove all characters that are not in "lucky"
               L2#^                    Use the POW! command
                   :n                  Add to variable n
                     "[^omen]"-        Remove all characters that are not in "omen"
                               L2*     Multiply the length by 2
                                  ;n#- Get variable n and subtract
share|improve this answer
    
By "consecutive orders", do you mean that you can't determine the longest substring with consecutive letters from "lucky" yet? – Kevin Lau - not Kenny 2 days ago
    
@KevinLau-notKenny No, it can't yet. – Midnightas 2 days ago

Python (139 Bytes)

import itertools as t
s=input()
print 2**max([j-i for i,j in t.combinations(range(6),2)if'lucky'[i:j]in s]+[0])-2*sum(_ in'omen'for _ in s)
share|improve this answer
    
You can save one byte by using from intertools import* – wnnmaw yesterday

Ruby, 57 bytes

b=gets.count'omen'
$.+=1while/[lucky]{#$.}/
p 2**$./2-2*b

gets sets $. to 1 as a side effect, then we increment it until the regular expression matching $. consecutive lucky characters no longer matches.

share|improve this answer

TSQL, 233 bytes

Golfed:

DECLARE @t varchar(99)='oluck'

,@z INT=0,@a INT=0,@ INT=1,@c INT=0WHILE @a<LEN(@t)SELECT
@a+=IIF(@=1,1,0),@z=IIF('LUCKY'LIKE'%'+x+'%'and @>@z,@,@z),@c+=IIF(x
IN('O','M','E','N'),2,0),@=IIF(@+@a-1=LEN(@t),1,@+1)FROM(SELECT
SUBSTRING(@t,@a,@)x)x PRINT POWER(2,@z)-@c

Ungolfed:

DECLARE @t varchar(99)='oluck'

,@z INT=0
,@a INT=0
,@  INT=1
,@c INT=0
WHILE @a<LEN(@t)
  SELECT
    @a+=IIF(@=1,1,0),
    @z=IIF('LUCKY'LIKE'%'+x+'%'and @>@z,@,@z),
    @c+=IIF(x IN('O','M','E','N'),2,0),
    @=IIF(@+@a-1=LEN(@t),1,@+1)
    FROM(SELECT SUBSTRING(@t,@a,@)x)x
PRINT POWER(2,@z)-@c

Try it online

share|improve this answer

Mathematica, 86 bytes

Code:

2^StringLength@LongestCommonSubsequence[#,"lucky"]-2StringCount[#,{"o","m","e","n"}]&

Explanation:

LongestCommonSubsequence returns the longest contiguous substring common to the input and "lucky". StringLength gives its length. StringCount counts the number of occurrences of the characters of "omen" in the input.

share|improve this answer

Haskell (134 132 Bytes)

import Data.List
c[]=[]
c s@(_:x)=inits s++c x
l=length
g q=2^(maximum$map(\z->l q-l(q\\z))$c"lucky")-2*(l$intersect q"omen")

Not a code golfer nor a Haskell programmer, so would love some tips on this one.

(Example: g "firetruck")

share|improve this answer
    
I am no Haskell Expert either, but managed to carve off a few byes by changing the algorithm slightly and using function aliases on reused functions. – Zylviij yesterday

Haskell, 99

Another approach... I just learned about function aliasing

import Data.List
s=subsequences
i=intersect
l=length
f n=2^(l$last$i(s"lucky")$s n)-2*l(i n$"omen")

Haskell is my new love :D

Usage

f"lucky"
32

f"firetruck"
6

f"memes"
-7
share|improve this answer

Python 3, 168 157 152 139 144 136 bytes

EDIT: Really obvious things I should have seen easier have been changed, and some slightly less obvious.

Edit 2: stoopid (˚n˚). The program threw errors. I fixed it up. not actually 153 :(

Thanks to Leaky Nun for saving 5 bytes, and to jmilloy for saving 13 8 bytes.

s=input()
p=q=k=len(s)
m=0
while-~p:
 while-~q:m=(m,q-p)[(s[p:q]in"lucky")*q-p>m];q-=1
 p-=1;q=k
print(2**m-2*sum(i in"omen"for i in s))

The program runs through all possibly possible substrings in input (possibly possible, because it computes impossible substrings as well, 8 to 7, for example), checks if the substring is in "lucky", then sets the exponent of 2 to the length of the substring should it be greater than the current value. Possibly could be improved by using only one while loop. Could possibly use some improvement; I'm still getting the hang of this.

share|improve this answer
    
while p+1 becomes while-~p – Leaky Nun 2 days ago
    
since b=s[p:q], len(b) must be q-p right? – Leaky Nun 2 days ago
    
I stole you input and print method but did the rest very different, thanks! I think if you just do print(2**m-2*sum(i in"omen" for i in s)) for your last three lines you'll do better, like 148? – jmilloy 2 days ago
    
Oh, and you can just move s[p:q] into the if clause while-~q:n=q-p;m=n if(s[p:q]in"lucky")*n>m else m;q-=1 for 143? – jmilloy 2 days ago

PHP program, 139 135 108 bytes

quantum leap fails for multiple substrings where the first occurence is shorter. :(

actually I could save another 7 bytes in PHP<5.4 with register_globals on

<?for($s=$argv[1];$i<5;$i++)for($j=6;--$j;)$r=max($r,strstr($s,substr('lucky*',$i,$j))?2**$j:1);echo$r-2*preg_match_all('/[omen]/',$s);

usage: php -d error_reporting=0 <filename> <string>

+5 for a function:

function f($s){for(;$i<5;$i++)for($j=6;--$j;)$r=max($r,strstr($s,substr('lucky*',$i,$j))?2**$j:1);return$r-2*preg_match_all('/[omen]/',$s);}

tests (on the function)

echo '<table border=1><tr><th>input</th><th>output</th><th>expected</th><th>ok?</th></tr>';
foreach([
    'lumberjack'=>0,        'smack'=>2,
    'nnnnnomemenn'=>-23,    'lucky'=>32,
    'omen'=>-7,             'firetruck'=>6,
    'memes'=>-7,            'determine the “luck” of a string'=>0,
    'amazing'=>-3,          'wicked'=>2,
    'chucky'=>16,           'uckyuke'=>14,
    'ugly'=>2,              'lucy'=>8,
    'lukelucky'=>30
] as $x=>$e){
    $y=f($x);
    echo"$h<tr><td>",$x,'</td><td>',$y,'</td><td>',$e,'</td><td>',$e==$y?'Y':'N',"</td></tr>";
}echo '</table>';
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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