18
\$\begingroup\$

OG post

Task

In this challenge, you will be given an string emoticon, and your task will be to output its happiness.

How?

An emoticon will always have eyes and mouth. It can also include eyebrows and nose. Each part will influence the overall happiness rating, which is the sum of happiness ratings of all parts. Emoticons may be flipped, reversing the order of parts. Here is the different possible parts and their happiness rating:

Symbol    Flipped symbol    Happiness rating

Eyebrows:

<None>    <None>            0
<         >                -2
[         ]                -1
|         |                 0
]         [                 1
>         <                 2

Eyes:

:         :                 0
;         ;                 1

Noses:

^         ^                 0
-         -                 0

Mouth

<         >                -3
(         )                -2
[         ]                -1
|         |                 0
]         [                 1
)         (                 2
>         <                 3

Test cases:

In        Out

:)        2
<:(      -4
|:-|      0
>;^)      5
(;        3
>-:<     -1
(:|       2

Rules

  1. You must be able to handle flipped emoticons. If the input can be interpreted both ways (for example <:<) you can output either of the possible results
  2. Standard loopholes and I/O rules apply.
  3. This is code-golf, so shortest code wins.
\$\endgroup\$
11
  • 2
    \$\begingroup\$ >:< is not strictly palindromic, but rather symetrical. >:> would be palindromic. Note that if you meant symetrical, the result will be the same, considered as a flipped one or not. But for palindromic ones the result will be different (opposite) \$\endgroup\$
    – Kaddath
    Sep 30 '20 at 10:11
  • \$\begingroup\$ @Kaddath yes, thank you for correcting. \$\endgroup\$
    – Dion
    Sep 30 '20 at 10:14
  • 4
    \$\begingroup\$ Also, even though noses won't count towards the output, you might want to mention all possible nose-characters regardless (^- based on the test cases?), because it does influence the positions. I.e. >^:> will only have a single possible output of -1 (2 for eyebrow >, 0 for eyes :, -3 for mouth >), because we know the nose is between the mouth and eyes. Unlike >:> which doesn't have a nose, and therefore can have two possible outputs depending on which > we count as mouth/eyebrows respectively. \$\endgroup\$ Sep 30 '20 at 10:26
  • 1
    \$\begingroup\$ @JonathanAllan added \$\endgroup\$
    – Dion
    Sep 30 '20 at 11:50
  • 2
    \$\begingroup\$ Interesting! Never imagined one of my challenges would be popular enough to get its own spin-off :p \$\endgroup\$ Sep 30 '20 at 18:49
5
\$\begingroup\$

05AB1E, 60 59 bytes

„:;S¡D€gÆI„()SkàĀ-dUv">)]|"')NXQ×K©.ºDysÃk®g<-X·<*yĀ*}I';åO

Try it online or verify all test cases.

Explanation:

„:;S              # Push string ":;", and convert it to a list of characters: [":",";"]
    ¡             # Split the (implicit) input-string on these characters
     D            # Duplicate the pair
      €g          # Get the length of each part
        Æ         # Reduce by subtracting
I                 # Push the input again
 „()S             # Push string "()", and convert it to a list of characters: ["(",")"]
     k            # Get the 0-based index of these characters in the string
                  # (or -1 if it isn't present)
      à           # Pop and push the maximum
       Ā          # Check that this is NOT 0 (0 if 0; 1 if -1, 1, 2, or 3)
-                 # Subtract the two from one another
 d                # Check that this is non-negative (>=0)
  U               # And pop and store this result in variable `X`
                  # (X=1 for faces where the mouth is left; X=0 for faces where the
                  # mouth is right or where we couldn't determine mouth/eyebrows)
v                 # Loop over the parts `y` in the pair we duplicated after the split:
 ">)]|"           #  Push string ">)]|"
         N        #  Push the 0-based loop-index
          XQ      #  Check if it's equal to variable `X` (1 if N==X, 0 if N!=X)
       ')   ×    '#  Repeat ")" that many times (")" if N==X, "" if N!=X)
             K    #  Remove that from string ">)]|"
              ©   #  Store this string in variable `®` (without popping)
               .º #  Mirror it with overlap: ">)]|"→">)]|[(<" or ">]|"→">]|[<"
 D                #  Duplicate this mirrored string
  y               #  Push the current part
   s              #  Swap so the copy of the mirrored string is at the top
    Ã             #  Keep only those characters in the part (removes noses "^"/"-")
     k            #  Get the 0-based index of the character in the mirrored string
      ®g          #  Push string `®`, and pop and push its length
        <         #  Decrease it by 1
         -        #  And subtract this from the index
 X                #  Push variable `X`
  ·               #  Double it
   <              #  Decrease it by 1
    *             #  And multiply the top two values
                  #  (negates the current value if X==0, or leaves it as is if X==1)
 y                #  Push the current part again
  Ā               #  Check that it's NOT empty (0 if empty; 1 otherwise)
   *              #  And multiply that as well, so empty parts become 0
}I                # After the loop, push the input again
  ';å            '# Check if it contains a ";" (1 if truthy; 0 if falsey)
O                 # And sum all values on the stack
                  # (after which the result is output implicitly) 
\$\endgroup\$
3
\$\begingroup\$

JavaScript (ES6),  181  176 bytes

s=>((/^[()]|[-^][:;]|[:;]$/.test(s)?s=[...s].reverse(q=-1):q=1,[b,e,n,m]=s,n?m?0:e<':'|e>';'?[e,b,m]=s:m=n:[e,m,b]=s,"<[|]>".indexOf(b)-2)%3+q*(e>':')+"<([|])>".indexOf(m)-3)*q

Try it online!

Commented

s => (                      // s = smiley string
  (                         //
    /^[()]|[-^][:;]|[:;]$/  // the smiley is unambiguously flipped if:
                            //   - it starts with a parenthesis
                            //   - or there's a nose before the eyes
                            //   - or it ends with the eyes
    .test(s) ?              // if the smiley is flipped:
      s = [...s]            //   reverse s
          .reverse(q = -1)  //   and set q to -1
    :                       // else:
      q = 1,                //   set q to 1
    [b, e, n, m] = s,       // default order: eyebrows, eyes, nose, mouth
    n ?                     // if s is at least 3 character long:
      m ?                   //   if s is 4 character long:
        0                   //     we got it right, so do nothing
      :                     //   else (3 characters):
        e < ':' | e > ';' ? //     if there's a nose:
          [e, b, m] = s     //       new order: eyes, nose, mouth 
                            //       but we actually load the nose into the
                            //       eyebrows to invalidate them
        :                   //     else:
          m = n             //       the nose is actually the mouth
    :                       // else (2 characters):
      [e, m, b] = s,        //   new order: eyes, mouth
                            //   (and set eyebrows to undefined)
    "<[|]>".indexOf(b) - 2  // compute the score for the eyebrows
  ) % 3 +                   // turn -3 into 0
  q * (e > ':') +           // add the score for the eyes
  "<([|])>".indexOf(m) - 3  // add the score for the mouth
) * q                       // multiply the final result by q
\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 165 bytes

$
@
([()].+|..[:;].|.+[:;])@
@$1
T`()><`Ro`@.|.@
T`(<[]>)`Ro`@.+
[[<(]
#$&
T`()<>[];`33221
\d
$*1@
1
@1
+`#@1
#1#
+`#1[^1]*@1|@1[^1]*#1

[^#1]

^(#)?(1#*)*
$#1$*-$#2

Try it online! Link includes test cases. Explanation:

$
@

Append a chin to the face.

([()].+|..[:;].|.+[:;])@
@$1

If the face seems flipped then prepend the chin instead.

T`()><`Ro`@.|.@

Switch ()s and ><s in the mouth, so that ><s are scored consistently.

T`(<[]>)`Ro`@.+

Flip the characters in a flipped face.

[[<(]
#$&

Mark the unhappy characters.

T`()<>[];`33221

Get the happiness of each character.

\d
$*1@

Convert the happiness to unary.

1
@1

Initially mark the happiness as positive.

+`#@1
#1#

Propagate negative happiness.

+`#1[^1]*@1|@1[^1]*#1

Pair happiness and unhappiness and delete both.

[^#1]

Delete all other characters.

^(#)?(1#*)*
$#1$*-$#2

Calculate the total happiness.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ @Arnauld Thanks, I've added browless faces to my flipped face detector. \$\endgroup\$
    – Neil
    Sep 30 '20 at 14:39
1
\$\begingroup\$

Wolfram Language (Mathematica), 213 bytes

Association[Thread[{""<>#,""<>(Reverse@#/.(Rule@@@Characters@"<>><())([]]["~Partition~2))}&[StringTake[" <[|]>:; ^-<([|])>",List/@{##}+{0,6,8,11}]~StringDelete~" "]->If[#<2,4,#]+#2+#4-9]&@@@Tuples@Range@{6,2,3,7}]

Try it online! This is an expression which evaluates to an Association object. It takes a string as input and returns an integer as output. The logic is very simple: it generates and rates all possible emoticons, and then it returns the rating for the given emoticon.

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

Jelly, 56 bytes

O:6ṣ9Ẉ>/ȯḢƲ%5Ḣ
ṚÇ©¡“<[|]>“<([|])>”iⱮ€U2¦o3SḢḟ0_7N®¡+”;e$

Try it online! Or see the test-suite. Or see all the emoticons.

How?

This decides whether to reverse the string using the helper link (if the left of the eyes is longer than the right or if the string starts with a ( or ), all using ordinals div six). Then finds the unflipped values of the eyebrows and mouth by indexing into two lists of characters while special-casing a lack of eyebrows and then offsetting the sum. Negates this result if we reversed the string (effectively the same as flipping the characters). Finally adds one to the result if the eyes are winking.

ṚÇ©¡“<[|]>“<([|])>”iⱮ€U2¦o3SḢḟ0_7N®¡+”;e$ - Main Link: list of characters, E
   ¡                                      - repeat...
 Ç                                        - ...number of times: call helper link as f(E)
  ©                                       -    (and copy the result to the register) 
Ṛ                                         - ...action: reverse
    “<[|]>“<([|])>”                       - list of lists of characters = ["<[|]>","<([|])>"]
                     €                    - for each (list, p, in that list):
                    Ɱ                     -   map (across c in E) with:
                   i                      -     first index (of c) in (p)
                      U2¦                 - reverse the second of the resulting list
                         o3               - replace 0s (not found) with 3s
                                            (offsetting a lack of eyebrows)
                           S              - sum (e.g. [[2,4],[5,1]] -> [7,5])
                            Ḣ             - head -> the sum of the relevant indices
                                                    zero if empty
                             ḟ0           - filter discard zeros
                               _7         - subtract 7
                                   ¡      - repeat...
                                  ®       - ...number of times: recall from register
                                 N        - ...action: negate
                                        $ - last two links as a monad:
                                     ”;   -   ';' character
                                       e  -   exists in (E)?
                                    +     - add
                                          - implicit print (the result is a list containing a single integer, which is printed as that integer)

O:6ṣ9Ẉ>/ȯḢƲ%5Ḣ - Link 1, should_reverse?: list of characters, E
O              - ordinals
 :6            - integer divide by six
   ṣ9          - split at nines (':' or ';')
          Ʋ    - last four links as a monad - f(x):
     Ẉ         -   length of each
       /       -   reduce by:
      >        -     greater than?
         Ḣ     -   head (x)
        ȯ      -   logical OR (replace a 0 with the list of ordinals of the left part)
           %5  - modulo by five - '(' and ')' give 1, others give 0
             Ḣ - head
\$\endgroup\$
1
  • \$\begingroup\$ Thanks, I've used a working link to TIO now. \$\endgroup\$ Oct 1 '20 at 18:23

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.