# Heart plus diamond is spade-and-club: table puzzle

I found this YouTube video with a table on it showing some card suits with ampersands. You might not understand what it is about, but I still want to make a challenge about it.

The input is two suits, being one of the following:

heart
diamond
club


You can do anything for any other input.

Then the output is their 'game sum':

1. If both suits are red (heart/diamond), then:
• Up to one heart promotes to a spade
• Up to one diamond demotes to a club
2. Output in order of priority (spade > heart > diamond > club).

Leading and trailing whitespace is allowed.

Example input:

spade
heart


Example output:

spade and heart


Use any language. This is code-golf, so shortest code in bytes wins.

• Is the output club and spade an acceptable alternative for spade and club, or does the order matter? Jan 9 at 22:04
• @Arnauld The order matters. "club and spade" is not an acceptable alternative for "spade and club". Jan 9 at 22:23
• Unless you provide some motivation, this looks like an arbitrary and somewhat boring task. If there is a rule or pattern that governs the input-output relationship, finding it out should not be a part of the challenge Jan 9 at 22:50
• The video this question is based does not even provide any justification for this pattern, only showing this table briefly from what looks like a book.
– Tbw
Jan 10 at 3:51
• The order pf precedence (sorting order) Spade Heart Diamond Club is from the game Bridge (and is coincidentally reverse alphabetical order.) Cards stay the same unless both are red, in which case the first available heart is promoted to spade and the last available diamond is demoted to club. I've watched the video and it gives no clue why this should be the case. Jan 10 at 10:20

# Retina 0.8.2, 58 bytes

O^
h.+¶[hd]
spade $& [td]¶d.+$& club
( .+)?¶(.+ )?
and


Try it online! Takes input on separate lines but link is to test suite that splits on  +  for convenience. Explanation:

O^


Sort in reverse order.

h.+¶[hd]
spade $&  Prefix spade if heart is followed by either heart or diamond. [td]¶d.+$& club


Suffix club if either heart or diamond are followed by diamond.

( .+)?¶(.+ )?
and


Keep only the first and last words and join them with and.

# 05AB1E, 33 bytes

„‰áš¸#©¢O<i®“spade†Ú“#.;}{R„ €ƒÀý


Input as a pair of strings.

Explanation:

„‰áš¸                 # Push dictionary string "heart diamond"
#                # Split it on spaces: ["heart","diamond"]
©               # Store this pair in variable ® (without popping)
¢              # Count how many times each occurs in the (implicit) input-pair
O             # Sum those counts together
<i           # If it's 2:
# (this is only truthy for the following four pairs: dd,dh,hd,hh)
®          #  Push ["heart","diamond"] again from variable ®
# #  Split it on spaces as well: ["spade","club"]
.;         #  Replace the first "heart" with "spade" and first "diamond"
#  with "club" in the (implicit) input-pair
}           # Close the if-statement
# (the implicit else uses the implicit input-pair)
{R         # Sort the pair in descending order (sort + reverse)
„ €ƒ     # Push dictionary string "  and"
À    # Rotate it once to the left to " and "
ý   # Join the pair with " and " as delimiter
# (after which the result is output implicitly)


See this 05AB1E tip of mine (section How to use the dictionary?) to understand why „‰áš¸ is "heart diamond"; “spade†Ú“ is "spade club"; and „ €ƒ is " and".

# JavaScript (ES6), 80 bytes

-6 thanks to @tsh

Inspired by Neil's method.

Expects ([a, b]).

c=>(/[dt],h/.test([b,a]=c.sort())?"spade":a)+" and "+(/d,[dh]/.test(c)?"club":b)


Try it online!

### Commented

c =>           // c[] = input array
(              //
/[dt],h/     // if a is "heart" and b is
.test(       // either "heart" or "diamond",
[b, a] =   // where a and b are sorted such
c.sort() // that a > b:
) ?          //
:            // else:
a          //   use a
) +            //
" and " +      // append " and "
(              //
/d,[dh]/     // if b is "diamond" and a is
.test(c) ?   // either "diamond" or "heart":
"club"     //   use "club" as the right output
:            // else:
b          //   use b
)              //

• 80 bytes if input as an array: c=>(/[dt],h/.test([b,a]=c.sort())?"spade":a)+" and "+(/d,[dh]/.test(c)?"club":b) or c=>(/[dt],h/.test(c.sort())?"spade":c[1])+" and "+(/d,[dh]/.test(c)?"club":c[0])
– tsh
Jan 11 at 3:51

# Jelly, 34 bytes

ṢṚµĖ41,3ḥⱮỊẸoḂƲȧ"ȯ"“ɓ¤PⱮ»Ḳ¤j“ and


A full program that takes a single list of two strings and prints the result to STDOUT.

Thanks to @JonathanAllan for suggesting a technique that ultimately saved a byte!

ṢṚµOḢ€ọ2¬Ẹo_J$ƲḂȧ"ȯ"“ɓ¤PⱮ»Ḳ¤j“ and  A full program that takes a single list of two strings and prints the result to STDOUT. Thanks to @JonathanAllan for pointing out a bug! This works because of the following pattern: ╔═══════════════════════════╦════╦═════╦═════╦═════╗ ║ First character ║ c ║ d ║ h ║ s ║ ╠═══════════════════════════╬════╬═════╬═════╬═════╣ ║ Codepoint ║ 99 ║ 100 ║ 104 ║ 115 ║ ╠═══════════════════════════╬════╬═════╬═════╬═════╣ ║ ọ2 ║ 0 ║ 2 ║ 3 ║ 0 ║ ╠═══════════════════════════╬════╬═════╬═════╬═════╣ ║ Subtract 1, or not, mod 2 ║ 1 ║ 1 ║ 0 ║ 1 ║ ╠═══════════════════════════╬════╬═════╬═════╬═════╣ ║ Subtract 2, or not, mod 2 ║ 1 ║ 0 ║ 1 ║ 1 ║ ╚═══════════════════════════╩════╩═════╩═════╩═════╝  ## Explanation Ṣ | Sort Ṛ | Reverse µ | Start a new monadic chain O | Convert to codepoints Ḣ€ | Head of each ọ2 | Number of times divisible by 2 Ʋ | Following as a monad: ¬Ẹ | - Any non-zero o_J$                       | - Or (the result of ọ2 from before minus the indices)
Ḃ                     | Mod 2
ȧ"                   | And zipped (with the reverse sorted input)
ȯ"“ɓ¤PⱮ»Ḳ¤         | Or zipped with "spade club" split at spaces
j“ and   | Join with " and " (the last ” is implicit)

• @JonathanAllan thanks. I’d made a mistake in the bit after the ọ2 that I’d somehow failed to spot. Unfortunately I don’t think the corrected version easily supports your nice hash. I’ve found a hash that does work with this (using Ė41,3ḥⱮỊẸoḂƲ) which is one byte shorter so going with that! Jan 11 at 20:24

$,=" and ";/[dt] [dh]/&&s/heart/spade/+s/diamond/club/;say reverse sort/\S+/g  Try it online! • Heart + Diamond is wrong; /[dt] [dh]/ fixes it. – Neil Jan 11 at 0:58 • @Neil Thanks! I missed that when I reviewed my output. Fixing it saved a few bytes, too. Jan 11 at 5:46 # Charcoal, 52 49 bytes Ｆ²⊞υＳ⪫Ｅ⌈⟦υ⮌υ⟧⎇›⁼§hdκ§ι⁰⊙sc№Συλ§⪪spadeclub⁵κι and  Try it online! Link is to verbose version of code. Explanation: Ｆ²⊞υＳ  Input the two strings. Ｅ⌈⟦υ⮌υ⟧⎇›⁼§hdκ§ι⁰⊙sc№Συλ§⪪spadeclub⁵κι and  Sort them in descending order, then unless one the two strings contains s or c, change the first string from heart to spade and the second from diamond to club, then join the results with and. # Uiua, 76 72 bytes $"_ and _"⍜(⊟∩□|⊏⍖.)(∘|(⊙⊙;|⊙;)≍,,∩(("club"|"spade")=@h⊢),)×∩(∊:"hd"⊢),,