Hi everybody,
I'm trying to write a program to simulate a solitaire game that my math teacher showed me so that I can eventually get an approximate probability of winning. Although I eventually plan to simulate the game many times, I'm only going through it once at this point with a predefined deck to make sure it works before I randomize things later. I ran through it with a debugger, and it is reaching the return statement that it needs to, after following all the right steps. However, when it reaches the return, it returns control back over to itself. Eventually, it runs over the stack, and I end up with a segfault. If someone could help me make sure the test function returns control to the game function, I would greatly appreciate the help.

The basic function of the game is:
1) Begin by flipping four cards face-up from the deck, one on top of the other.
2) Look at the top card and the card three below it. If they are of the same suit, remove the two cards in between the cards you were comparing. If they are the same value (number), remove all four of the top four cards. for example, if the top four cards are 2♥, 7♦, J♣, A♥, the seven and the jack would be removed. If the top four cards are 2♥, 7♦, J♣, 2♦, then all four cards would be removed.
3) If no move is possible, or there are fewer than four cards face-up, flip another card from the deck, and do the tests in step two again.
4) The game ends when no further moves are possible. If there are no cards left, the player wins.

While I believe that there is no error in the logic of the program, I am certainly not perfect. There may also be more efficient ways to achieve the same goals.

Here is my attempt so far. Once again, my problem seems to be in the recursive calling of the test function, and the inability to transfer control to the game function.

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

struct card{
      int value;
      int index;
};

int test (struct card *x, struct card *y, struct card const *first, struct card const *last);

int game( void);

int main()
{   
    int i; //counter
    int win = 0; // number of wins
    int lose = 0; //number of losses
    srand( 1); //this is only to test things until later use srand(time(0))
//  for (i = 0; i < 1000000; i++;)  //runs a bunch of iterations 
    win += game();
    printf("number of wins: %d\n", win);
    getchar();
    return 0;
}

int test (struct card *x, struct card *y, struct card const *first, struct card const *last)
{
    int j = 0; //counter
    int k = 0; //another counter
    struct card const *temp;
    if (((x -> value) - 1) % 13 == ((y -> value) - 1) % 13) //same number
    {
        temp = y;
        for ( y = x; y <= temp; y++)
            y -> value = 0;
        x = y;
        while (j < 4)
        {
            if (x == first)
            {
                if ((x -> value) == 0)
                {
                    while ((x -> value) == 0)
                    {
                        if (x == last)
                            return 1; // ************ WIN ************ RETURN 1
                        x++;
                    }
                    break;
                }
            }
            else
            {
                x--;
                if ((x -> value) != 0)
                   j++;
            }
        }
        y = x;
        while (k < 3)
        {
              if (y == last)
                 return 0; // Should exit on this return statement
              y++;
              if ((y -> value) != 0)
                 k++;
        }
        test (x, y, first, last); //Recursive function call
    }
    if (((x -> value) - 1) / 13 == ((y -> value) - 1) / 13) //same suit
    {
        j = 0;
        temp = y - 1;
        for (y = x + 1; y <= temp; y++)
            y -> value = 0;
        x = y;
        while (j < 3)
        {
              if (x == first)
              {
                if ((x -> value) == 0)
                {
                    while ((x -> value) == 0)
                    {
                        if (x == last)
                            return 1; // ************ WIN ************ RETURN 1
                        x++;
                    }
                }
                y = x;
                do
                {
                    if (y == last)
                       return 0; // ************ LOSE ************ RETURN 0
                    y++;
                     if ((y -> value) != 0)
                       k++;
                }while (k < 3);
                test (x, y, first, last); //Recursive function call
              }
              else
              {
                x--;
                if ((x -> value) != 0)
                   j++;
              }
        }
        test (x, y, first, last); //Recursive function call
    }
    do
    {
          x++;          
    }while ((x -> value) == 0);
    do
    {
          y++;
          if (y == last)
             return 0;
    }while ((y -> value) == 0);
    test (x, y, first, last);
}
int game (void)
{
    struct card deck[52];
    int i = 0;
    int win = 0; // Local copy, separate from copy in main function
    struct card *x;
    struct card *y;
    for (i = 0; i < 52; i++)
    {
        deck[i].value = i + 1;
        deck[i].index = rand();
    }
    x = &deck[0];
    y = &deck[3];
    win += test (x, y, &deck[0], &deck[51]); //1 for win, 0 for lose
    return win;
}

Recommended Answers

All 8 Replies

I think you have infinite loop with recursions, as you do not return the result of the recursive calls.

Ok. Does that mean that the problem will be fixed simply by making sure to return a value with each call?

You should simpify also your control structure, let's say call in line 69 returns value 1 or 0, what happens then.

You seem to do the iteration both with while and recursion, write down your algorithm and check the logic. Test with almost finished pack of cards (end game) by hand (both before writing the new version of the function and after writing it "being the computer").

My opinion is that you do not need recursion here, if it is not requirement. Alternatevely you must take out the while's. But considering you will be running massive amount of games for experimental check of probabilities, the more efficient while is better.

Recursion is not a requirement. My only question if I use something other than recursion is how to ensure that the function can continue testing. The use of the while loops is mainly to reposition the x and y pointers so that it is set up for the next function call. Is there a way that I could modify them so that I could avoid the recursion completely then? I went through the whole game with the deck I set up, and I end up at the return statement in line 64. I thought the function should return a zero to the game function to indicate a loss, but instead it seems to be returning the zero to itself.

I came up with an idea that might have some potential, but it isn't working the way I thought it would. As opposed to recursively calling the function, I had the function return a -1 where I previously had the recursive calls. Then I changed the game function so that whenever it received a -1, it called the test function again. I think this should solve my infinite loop problem. However, when the test function is called again, and the x and y pointers get passed as arguments, they return to their initial values instead of retaining the values from the previous iteration of the test function. Is there any reason why this is happening? The lines that define the initial values are not being run again, and it was my understanding that pointers didn't need to be returned. Here are my new game and test functions. I put in the line that prints x -> value and y -> value to test, but it really looks like I just created another infinite loop, and I don't know how I did it.

int test (struct card *x, struct card *y, struct card const *first, struct card const *last)
{
    int j = 0; //counter
    int k = 0; //another counter
    struct card const *temp;
    if (((x -> value) - 1) % 13 == ((y -> value) - 1) % 13) //same number
    {
        temp = y;
        printf("same number\n");
        for ( y = x; y <= temp; y++)
            y -> value = 0;
        x = y;
        while (j < 4)
        {
            if (x == first)
            {
                if ((x -> value) == 0)
                {
                    while ((x -> value) == 0)
                    {
                        if (x == last)
                            return 1; // ************ WIN ************ RETURN 1
                        x++;
                    }
                    break;
                }
            }
            else
            {
                x--;
                if ((x -> value) != 0)
                   j++;
            }
        }
        y = x;
        while (k < 3)
        {
              if (y == last)
                 return 0; // ************ LOSE ************ RETURN 0
              y++;
              if ((y -> value) != 0)
                 k++;
        }
        return -1; //Replaced Recursive function call
    }
    if (((x -> value) - 1) / 13 == ((y -> value) - 1) / 13) //same suit
    {
        j = 0;
        temp = y - 1;
        for (y = x + 1; y <= temp; y++)
            y -> value = 0;
        x = y;
        while (j < 3)
        {
              if (x == first)
              {
                if ((x -> value) == 0)
                {
                    while ((x -> value) == 0)
                    {
                        if (x == last)
                            return 1; // ************ WIN ************ RETURN 1
                        x++;
                    }
                }
                y = x;
                do
                {
                    if (y == last)
                       return 0; // ************ LOSE ************ RETURN 0
                    y++;
                     if ((y -> value) != 0)
                       k++;
                }while (k < 3);
                return -1; //Replaced Recursive function call
              }
              else
              {
                x--;
                if ((x -> value) != 0)
                   j++;
              }
        }
        return -1; //Replaced Recursive function call
    }
    do
    {
          x++;          
    }while ((x -> value) == 0);
    do
    {
          y++;
          if (y == last)
             return 0;
    }while ((y -> value) == 0);
    return -1; //Replaced Recursive function call
}
int game (void)
{
    struct card deck[52];
    int i = 0;
    int win = 0; // Local copy, separate from copy in main function
    int check = -1;
    struct card *x;
    struct card *y;
    for (i = 0; i < 52; i++)
    {
        deck[i].value = i + 1;
        deck[i].index = rand();
    }
    x = &deck[0];
    y = &deck[3];
    while (check = -1)
    {
          check = test (x, y, &deck[0], &deck[51]); //1 for win, 0 for lose
          printf("x -> value = %d\ny -> value = %d\n\n", x -> value, y -> value);
    }
    win += check;
    return win;
}

You might be interested that I posted in Python forum, pure chance of course ;), very similar solitaire game. It could give ideas how to structure your C program.

I looked at it, and I think it could help some. There are a few things I don't quite understand about it though. The most complicated part of what I have so far seems to be moving the pointers after some cards have been taken out. I think (correct me if I'm wrong) that instead of doing that the way I did, the Python program you have deleted the cards that were "played" in line 90 or 92, depending on which cards were played, and then simply moved the cards back a set number of times. As far as I know, there is no way to do this in C, without completely reallocating memory for the array, or possibly sorting the array so that the deleted cards would be all the way at the back. In either case, both are pretty inefficient if I'm eventually going to be running massive numbers of games. This leaves me with an undefined number of times that I must move the pointers back or forward. But is the structure you were talking about mostly moving the lines of code that move the pointers to a different function? I guess I could have the test function return 2 for same suit, 4 for same value, and 0 for a failed move like I think you did, but is there a particular advantage to that? The only problem that I can see with my code so far is that when the test function iterates, it receives the same parameters every time, and does not keep the changed values from the pointers that it got from the previous iteration.
Thanks for all the help by the way!

There is zillion alternatives. I would take something like this approach in my code

What if you had a array of boolean which had True for those cards that have been removed and you had random order sequence of card numbers 1..52 or 0..51 in another array . What could you say about card's suit and value with card number n, when you consider n/13 and n%13 (you could value A as 1 in this game without problem, even with your rules)?

Alternatively struct together int card_no and bool deleted and do one array[52] .

In each iteration (your main for or while loop) you only update win count and reshufle the card numbers and set deleted all False. Keeping counter for deleted could be usefull also.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.