HiveBrain v1.2.0
Get Started
← Back to all entries
patterncMinor

Human (imperfect) array (card) shuffle written in C

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
humanwrittenimperfectarraycardshuffle

Problem

I've got this humanoid_shuffle I wrote in Python. I've been wanting to learn C so as an exercise I ported it to C. As this is my first venture into C and even the ideas of memory management and the like, what are some ways to make this better from a code quality and efficiency perspective?

A couple of quick thoughts from a C beginner:

  • Interesting how it's harder to justify creating multiple new copies of the array to juggle between.



  • Seems like you have to be much more clever and less practical with C (obviously the Python version is much easier to follow).



Thoughts?

Python

```
@staticmethod
def humanoid_shuffle(items, num_shuffles=6):
# how many times items can be pulled from the same list consecutively
MAX_STREAK = 10

# divide list roughly in half
num_items = len(items)
end_range = int(num_items / 2 + random.randint(0, int(.1 * num_items)))
first_half = items[:end_range] # list up to 0 - end_range
second_half = items[end_range:] # list after end_range - len(items)

split_lists = (first_half, second_half)
mixed = []
streak = current_item_index = 0
# while both lists still contain items
while first_half and second_half:
# calc the percentage of remaining total items
remaining = (1 - float(len(mixed)) / num_items)
# if we happen to generate a random value less than the remaining percentage
# which will be continually be decreasing (along with the probability)
# or
# if MAX_STREAK is exceeded
if random.random() MAX_STREAK:
# switch which list is being used to pull items from
current_list_index = 1 ^ current_list_index
# reset streak counter
streak = 0

# pop the selected list onto the new (shuffled) list
mixed.append(split_lists[current_list_index].pop())
# increment streak of how many consecutive times a list has remained selected
streak += 1

# add any remaining i

Solution

Before I do a C review I just want to do a literal translation of your python so you can compare it. Personally I think you can make your C look identical to your python (a small amount of extra work required for memory management and the array like container but otherwise the same).

#include 
#include 
#include 
#include 

typedef struct Cards
{
    int*    cards;
    int     size;
} Cards;

Cards shuffle_n(Cards deck, int num_shuffles)
{
    /* how many times items can be pulled from the same list consecutively */
    int const MAX_Streak = 10;

    /* divide list roughly in half */
    int num_items   = deck.size;
    int end_range   = num_items / 2 + rand() % (int)(.1 * num_items);

    Cards   split_lists[2]      = { {deck.cards, end_range},                          /* # list up to 0 - end_range */
                                    {deck.cards + end_range, deck.size - end_range}   /* list after end_range - len(items) */
                                  };
    int     current_list_index  = rand() % 2;

    int*    mixedData           = (int*)malloc(sizeof(int) * deck.size);
    Cards   mixed               = {mixedData, 0 };
    int     streak              = 0;

    /* # while both lists still contain items */
    while((split_lists[0].size != 0) && (split_lists[1].size != 0))
    {
        /* calc the percentage of remaining total items */
        int remaining = (1 - ((float)mixed.size) / num_items);
        /* if we happen to generate a random value less than the remaining percentage
         * which will be continually be decreasing (along with the probability)
         * or 
         * if MAX_Streak is exceeded 
         */
        if ((rand()  MAX_Streak))
        {
            /* switch which list is being used to pull items from */
            current_list_index = !current_list_index;
            /* reset streak counter */
            streak = 0;
        }

        /* pop the selected list onto the new (shuffled) list */
        mixed.cards[mixed.size++] = split_lists[current_list_index].cards[--split_lists[current_list_index].size];
        /* increment streak of how many consecutive times a list has remained selected */
        streak += 1;
    }

    /* add any remaining items */
    memcpy(&mixed.cards[mixed.size], &split_lists[0].cards, split_lists[0].size * sizeof(int)); mixed.size += split_lists[0].size;
    memcpy(&mixed.cards[mixed.size], &split_lists[1].cards, split_lists[1].size * sizeof(int)); mixed.size += split_lists[1].size;

    num_shuffles -= 1;
    /* if we still have shuffles to do */
    if (num_shuffles > 0)
    {   /* rinse and repeat */
        Cards result = shuffle_n(mixed, num_shuffles);
        free(mixedData);

        mixed   = result;
    }

    /* # finally return fully shuffled list */
    return mixed;
}
Cards shuffle(Cards deck) {return shuffle_n(deck, 6);}

int main()
{
    srand(time(NULL));
    int i;
    int array[52] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };

    Cards   deck = {array, sizeof(array)/sizeof(array[0])};

    printf("\nShuffling...\n\n");
    Cards   shuffled = shuffle( deck );

    for(i = 0; i < shuffled.size; i++)
    {
      printf("%d\n", shuffled.cards[i]);
    }
    free(shuffled.cards);
}

Code Snippets

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

typedef struct Cards
{
    int*    cards;
    int     size;
} Cards;

Cards shuffle_n(Cards deck, int num_shuffles)
{
    /* how many times items can be pulled from the same list consecutively */
    int const MAX_Streak = 10;

    /* divide list roughly in half */
    int num_items   = deck.size;
    int end_range   = num_items / 2 + rand() % (int)(.1 * num_items);

    Cards   split_lists[2]      = { {deck.cards, end_range},                          /* # list up to 0 - end_range */
                                    {deck.cards + end_range, deck.size - end_range}   /* list after end_range - len(items) */
                                  };
    int     current_list_index  = rand() % 2;

    int*    mixedData           = (int*)malloc(sizeof(int) * deck.size);
    Cards   mixed               = {mixedData, 0 };
    int     streak              = 0;

    /* # while both lists still contain items */
    while((split_lists[0].size != 0) && (split_lists[1].size != 0))
    {
        /* calc the percentage of remaining total items */
        int remaining = (1 - ((float)mixed.size) / num_items);
        /* if we happen to generate a random value less than the remaining percentage
         * which will be continually be decreasing (along with the probability)
         * or 
         * if MAX_Streak is exceeded 
         */
        if ((rand() < remaining) || (streak > MAX_Streak))
        {
            /* switch which list is being used to pull items from */
            current_list_index = !current_list_index;
            /* reset streak counter */
            streak = 0;
        }

        /* pop the selected list onto the new (shuffled) list */
        mixed.cards[mixed.size++] = split_lists[current_list_index].cards[--split_lists[current_list_index].size];
        /* increment streak of how many consecutive times a list has remained selected */
        streak += 1;
    }

    /* add any remaining items */
    memcpy(&mixed.cards[mixed.size], &split_lists[0].cards, split_lists[0].size * sizeof(int)); mixed.size += split_lists[0].size;
    memcpy(&mixed.cards[mixed.size], &split_lists[1].cards, split_lists[1].size * sizeof(int)); mixed.size += split_lists[1].size;

    num_shuffles -= 1;
    /* if we still have shuffles to do */
    if (num_shuffles > 0)
    {   /* rinse and repeat */
        Cards result = shuffle_n(mixed, num_shuffles);
        free(mixedData);

        mixed   = result;
    }

    /* # finally return fully shuffled list */
    return mixed;
}
Cards shuffle(Cards deck) {return shuffle_n(deck, 6);}


int main()
{
    srand(time(NULL));
    int i;
    int array[52] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 };

    Cards   deck = {array, sizeof(array)/sizeof(array[0])};

    printf("\nShuffling...\n\n");

Context

StackExchange Code Review Q#8182, answer score: 5

Revisions (0)

No revisions yet.