patterncMinor
Human (imperfect) array (card) shuffle written in C
Viewed 0 times
humanwrittenimperfectarraycardshuffle
Problem
I've got this
A couple of quick thoughts from a C beginner:
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
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.