16
\$\begingroup\$

For the purposes of this question, a deck of cards is formatted in this way:

[
 "AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "10S", "JS", "QS", "KS", 
 "AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "10D", "JD", "QD", "KD", 
 "AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "10H", "JH", "QH", "KH", 
 "AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "10C", "JC", "QC", "KC", 
 "J", "J"
]

Cards are always formatted as value, followed by suits. E.g. AS is the Ace of Spades. The two single J's are Jokers. We want to shuffle this deck of cards, but the shuffle must be SuperbTM.

A Superb ShuffleTM is one in which:

  • No two cards (except Jokers) of the same suit are adjacent.
  • No card (except Jokers) is adjacent to one of the same value.
  • No card (except Jokers) is adjacent to one of an adjacent value (one higher or one lower in this order, A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, A. Notice that Ace can not be adjacent to either a 2 or a King).
  • The Jokers can be in any position.
  • The definition of a Superb ShuffleTM does not require the cards to be in a different order each time they are shuffled. Which isn't very superb, but it is SuperbTM.

Because that's SuperbTM.

An example might be:

[
 "AS", "5D", "9H", "KC", "2D", "6H", "10C", "QS", "3H", "7C", "9S", 
 "KD", "4C", "6S", "10D", "AC", "3S", "7D", "JH", "J", "4D", "8H", 
 "QC", "AD", "5H", "9C", "JS", "2H", "6C", "8S", "QD", "3C", "5S", 
 "9D", "KH", "2S", "6D", "10H", "J", "3D", "7H", "JC", "KS", "4H", 
 "8C", "10S", "AH", "5C", "7S", "JD", "2C", "4S", "8D", "QH"
]

The challenge:

  • Write some code to execute a superb shuffle
  • Use any language.
  • The input can be either:
    • a deck of cards as described above in the same order, as an array or other list structure.
    • No input (the code generates a deck of cards in that order)
  • The output must be a full deck of cards in a Superb ShuffleTM as described above.
  • Attempt to perform your Superb ShuffleTM in the smallest number of bytes.
  • A link to an online interpreter such as Try It Online is preferred, but optional.

Happy shuffling!

caird coinheringaahing
50.9k11 gold badges133 silver badges364 bronze badges
asked Jun 18, 2018 at 11:06
\$\endgroup\$
17
  • 1
    \$\begingroup\$ Somewhat related \$\endgroup\$ Commented Jun 18, 2018 at 11:24
  • \$\begingroup\$ Can we substitute T instead of 10? \$\endgroup\$ Commented Jun 18, 2018 at 12:10
  • \$\begingroup\$ @JoKing You may not. Just like the generating a deck of cards question, the different string lengths are part of the complexity. \$\endgroup\$ Commented Jun 18, 2018 at 12:24
  • \$\begingroup\$ Are we allowed to print each card separately like the Charcoal answer does, or do we need to actually return an array/list? \$\endgroup\$ Commented Jun 18, 2018 at 12:42
  • 2
    \$\begingroup\$ Who owns the trademark on Superb Shuffle? Curious to see TM in an algorithm name. Never seen that before. \$\endgroup\$ Commented Jun 23, 2018 at 16:01

13 Answers 13

36
\$\begingroup\$

Ruby, (削除) 28 (削除ここまで) 26 bytes

->x{x.map{x[($.+=17)%54]}}

Try it online!

Today I decided to have a look at this problem again, and I could shave (削除) 3 (削除ここまで) 5 bytes from the previous solution (reported below).

Ruby, 31 bytes

->x{(0..53).map{|r|x[r*17%54]}}

Try it online!

Explanation:

I'm picking one card, then skipping over the next 16 and start from the first card when I reach the last card of the deck. 17 and 54 are mutually prime, so I'm sure to pick all cards.

The 17th position is guaranteed to be a different suit and the difference in value is at least 2: the 13th (or 15th) card has the same value and a different suit, so by skipping other 4 (or 2), the value is right.

answered Jun 18, 2018 at 11:24
\$\endgroup\$
3
  • 6
    \$\begingroup\$ Well done on finding the process every other answer uses ;) \$\endgroup\$ Commented Jun 18, 2018 at 12:12
  • 3
    \$\begingroup\$ Can you explain how you found the *17%54? Just trial and error or is there some obvious maths that I'm missing? \$\endgroup\$ Commented Jun 18, 2018 at 12:36
  • \$\begingroup\$ @Daniel 17 is the required minimum distance between two differently suited cards that are not adjacent numerically (accounting for the two jokers; e.g. 17 steps gets you from the Ace of Clubs to the 3 of Spades); 54 is the number of cards in the deck. \$\endgroup\$ Commented Jun 18, 2018 at 20:19
12
\$\begingroup\$

Python 3, 21 bytes

lambda x:(x*17)[::17]

Try it online!

Explanation:

The same idea as my Ruby answer, but even shorter in Python: I use 17 decks, and pick every 17th card.

answered Jun 18, 2018 at 13:38
\$\endgroup\$
5
\$\begingroup\$

Japt, (削除) 6 (削除ここまで) (削除) 5 (削除ここまで) 4 bytes

Splits the input array into sub-arrays of every 16th element and flattens.

óG c

Try it

answered Jun 18, 2018 at 11:54
\$\endgroup\$
2
  • \$\begingroup\$ Do you need to flatten it? \$\endgroup\$ Commented Jun 18, 2018 at 20:06
  • \$\begingroup\$ @Oliver, I'm hoping not; waiting for AJ to confirm. \$\endgroup\$ Commented Jun 18, 2018 at 20:35
4
\$\begingroup\$

Java 10, (削除) 72 (削除ここまで) 65 bytes

d->{var r=d.clone();for(int i=54;i-->0;r[i*7%54]=d[i]);return r;}

Similar as @GB's Ruby answer, but by using i*7%54 on the result-array, instead of i*17%54 on the input-array to save a byte.

Try it online.

Explanation:

d->{ // Method with String-array as both parameter and return-type
 var r=d.clone();// Result-String, starting as a copy of the input
 for(int i=54;i-->0;
 // Loop `i` in the range (54, 0]
 r[ // Set an item in the result-array at index:
 i*7%54 // Index `i` multiplied by 7, and then take modulo-54
 ]=d[i]); // To the `i`'th item in the input-Deck
 return r;} // Return the result-Array
answered Jun 18, 2018 at 11:48
\$\endgroup\$
3
  • \$\begingroup\$ Unfortunately, the result contains numerous cards which are adjacent to cards of the same suit. It starts with AS, 6S, JS, 3D, 8D, KD,. \$\endgroup\$ Commented Jun 18, 2018 at 11:50
  • \$\begingroup\$ @AJFaraday TIO was still with 11 instead of 7. Could you check it again. Perhaps I missed something else, but I think it should be correct now (I hope). \$\endgroup\$ Commented Jun 18, 2018 at 11:53
  • \$\begingroup\$ That's got it now. Nice work! \$\endgroup\$ Commented Jun 18, 2018 at 11:56
4
\$\begingroup\$

JavaScript, 35 bytes

x=>x.map((a,i)=>i%2?a:x[(i+20)%54])

Try it online!

Taking an array of deck as input, and replacing each odd value with another card that is "20 cards" away on the deck.

answered Jun 18, 2018 at 14:05
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Aha, when I said "everyone" in my post was incorrect; this is how I went too! \$\endgroup\$ Commented Jun 18, 2018 at 17:43
3
\$\begingroup\$

JavaScript, 27

Another one based off of the ruby answer

d=>d.map((_,i)=>d[i*17%54])

Edited in an obvious shortening

answered Jun 18, 2018 at 15:35
\$\endgroup\$
3
\$\begingroup\$

Perl 6, (削除) 21 20 (削除ここまで) 18 bytes

Thanks to Brad Gilbert b2gills for -2 bytes

{.[$++*17%$_]xx$_}

Try it online!

Yet another port of G B's answer. (削除) Note that, while the global variable $! is not reset between functions, the value doesn't matter, since any order of the output is valid. (削除ここまで) However, $ is reset.

Explanation:

{ } #Anonymous code block
 xx$_ #Repeat size of inputted array (54) times
 .[ ] #Get from the inputted array, the value at index
 $++*17%$_ #The incremented variable, multiplied by 17, modded by size of the array
answered Jun 18, 2018 at 12:23
\$\endgroup\$
1
  • 1
    \$\begingroup\$ This works just as well with an unnamed state var $ as it does with $! or $/. Also if you used $_ instead of @_ you could start it with .[...] instead of @_[...] saving another byte. \$\endgroup\$ Commented Jun 18, 2018 at 14:20
2
\$\begingroup\$

05AB1E, (削除) 9 (削除ここまで) (削除) 7 (削除ここまで) 5 bytes

ā17*è

Port of @GB's Ruby answer, so make sure to upvote him!

-2 bytes by printing each card with a new-line delimiter instead of wrapping it to a result-list
-2 bytes thanks to @Mr.Xcoder

Try it online.

Explanation:

ā # 1-indexed length range [1 ... length_of_input_list (54)]
 17* # `k`: Multiply each index by 17
 è # And then replace each item with the 0-indexed `k`'th card of the input-list
 # (with automatic wrap-around)
answered Jun 18, 2018 at 12:11
\$\endgroup\$
1
  • 1
    \$\begingroup\$ ā17*è should save 2 more bytes \$\endgroup\$ Commented Jun 18, 2018 at 12:56
2
\$\begingroup\$

T-SQL, 31 bytes

SELECT c FROM t ORDER BY i*7%54

If you don't care about an extra column in the output I can get it down to 29 bytes:

SELECT*FROM t ORDER BY i*7%54

So you can verify my output is "Superb", here is the deck it produces:

 J, 5H, 8S, KH, 3D, 8C, JD, AS, 6H, 9S, AC, 4D, 9C, QD, 
2S, 7H, 10S, 2C, 5D, 10C, KD, 3S, 8H, JS, 3C, 6D, JC, 
AH, 4S, 9H, QS, 4C, 7D, QC, 2H, 5S, 10H, KS, 5C, 8D, 
KC, 3H, 6S, JH, AD, 6C, 9D, J, 4H, 7S, QH, 2D, 7C, 10D

(Generated using the new SQL 2017 addition, STRING_AGG):

SELECT STRING_AGG(c,', ')WITHIN GROUP(ORDER BY i*7%54)FROM t 

The hard part for me was not the select code, it was populating the input table (which is allowed for SQL per our IO rules).

Because SQL is inherently unordered (it only guarantees a certain order if you include an explicit ORDER BY clause), I had to include that original order as a field i in the input table t. This also means I can use it to sort, using the same "relatively prime" factor/mod process everyone else is using. I found that i*7%54 worked just as well as i*17%54.

Here are the commands to set up and populate the input table t, based on my solution to this related question:

CREATE TABLE t (i INT IDENTITY(1,1), c VARCHAR(5))
--Insert 52 suited cards
INSERT t(c)
SELECT v.value+s.a as c
FROM STRING_SPLIT('A-2-3-4-5-6-7-8-9-10-J-Q-K','-')v,
 (VALUES('S',1),('D',2),('H',3),('C',4))s(a,b)
ORDER BY s.b
--Insert Jokers
INSERT t(c) SELECT 'J'
INSERT t(c) SELECT 'J'
answered Jun 18, 2018 at 16:29
\$\endgroup\$
2
  • \$\begingroup\$ Would the i not be considered additional input here? \$\endgroup\$ Commented Jun 18, 2018 at 19:59
  • \$\begingroup\$ @Shaggy The question says I can get the input deck in the original (listed) order. The only way to guarantee this in SQL is to have the order be an explicit part of the input, because SQL tables have no "default order". So, I view it as a necessary component of the input. But don't worry, SQL is rarely competitive anyway :) \$\endgroup\$ Commented Jun 18, 2018 at 20:35
2
\$\begingroup\$

Jelly, (削除) 5 (削除ここまで) 4 bytes

s4ZẎ

Try it online!

Turns out the way (削除) everyone else (削除ここまで) everyone else except The random guy is doing it saves a byte :(
Credit to G B for their method.


The way I went...

ṙÐe20

Try it online!

How?

Fix every other card and intersperse it with a rotation of the deck left by 20 places (18 and 22 places also work; furthermore so does either direction of rotation as well as fixing either odd or even cards)

ṙÐe20 - Link: list of the card strings (lists of characters)
 20 - place a literal twenty on the right
 Ðe - apply to even indices:
ṙ - rotate left (by 20)

That is (using T for 10 and rj & bj for the Js):

input: AS 2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AD 2D 3D 4D 5D 6D 7D 8D 9D TD JD QD KD AH 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AC 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC rj bj
 ṙ20: 8D 9D TD JD QD KD AH 2H 3H 4H 5H 6H 7H 8H 9H TH JH QH KH AC 2C 3C 4C 5C 6C 7C 8C 9C TC JC QC KC rj bj AS 2S 3S 4S 5S 6S 7S 8S 9S TS JS QS KS AD 2D 3D 4D 5D 6D 7D
ṙÐe20: AS 9D 3S JD 5S KD 7S 2H 9S 4H JS 6H KS 8H 2D TH 4D QH 6D AC 8D 3C TD 5C QD 7C AH 9C 3H JC 5H KC 7H bj 9H 2S JH 4S KH 6S 2C 8S 4C TS 6C QS 8C AD TC 3D QC 5D rj 7D
answered Jun 18, 2018 at 17:17
\$\endgroup\$
0
2
\$\begingroup\$

PowerShell 3.0, (削除) 30 (削除ここまで) 26 Bytes

$args[(0..53|%{$_*17%54})]

-4 thanks to Mazzy
Old code at 30 bytes

param($d)0..53|%{$d[$_*17%54]}

Another port of G B's method.

answered Jun 18, 2018 at 22:47
\$\endgroup\$
5
  • \$\begingroup\$ 26 bytes $args[(0..53|%{$_*17%54})]. \$\endgroup\$ Commented Jul 9, 2018 at 17:52
  • \$\begingroup\$ @Mazzy I feel like that breaks input specs. Sure they're collected into $args but you're not actually passing one in. \$\endgroup\$ Commented Jul 9, 2018 at 21:43
  • \$\begingroup\$ quote: The input can be either:... in the same order, as *an array*. $args is an array. and you can to use a splatting. for example $a=@("AS", ..., "J"); &{} @a. Try it. :) \$\endgroup\$ Commented Jul 9, 2018 at 22:30
  • \$\begingroup\$ in additional, it seems to me that there is no need to count the characters &{ and }. You can to save param($d)0..53|%{$d[$_*17%54]} to a file. and call this file without &{...} \$\endgroup\$ Commented Jul 9, 2018 at 22:37
  • 1
    \$\begingroup\$ @mazzy Yeah, I've always been a bit unsure of which control parts to keep so just usually defaulted to making it a script block. I'll strip it in the future though. \$\endgroup\$ Commented Jul 9, 2018 at 22:44
1
\$\begingroup\$

Charcoal, 8 bytes

×ばつ17κ

Try it online! Link is to verbose version of code. Another port of @GB's Ruby answer. Explanation:

 θ Input array
E Map over elements
 κ Current index
 17 Literal 17
 ×ばつ Multiply
 θ Input array
 § Cyclically index
 Implicitly print each result on its own line
answered Jun 18, 2018 at 12:24
\$\endgroup\$
1
\$\begingroup\$

Red, 44 bytes

func[a][append/dup a a 16 prin extract a 17]

Try it online!

Another interpetation of G B's code. I append 16 copies of the deck to itself and then extract each 17th card.

answered Jun 19, 2018 at 7:52
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.