I am getting a segmentation fault at args->deck[i]++; in win_hand_prob_threading even though the variables I pass to the function being called in multiple threads are all allocated on the heap. The segmentation fault also only happens in one of the threads. I have tried using gdb, but it has not helped me much. My only hunch is that calling win_hand_prob somehow makes args->deck into invalid memory to access.

#include "jack.h"

void print_hand(char hand[22], int cards) {
    for (int i = 0; i < cards; i++) {
        printf("%d, ", (int)card_values[hand[i]]);
    }
    printf("n");
}

void dealer_drawing_win_prob(char deck[10], int phv, char dhand[22], int dcards, double* win, double* draw, double* lose) {
    int dhv = hand_value(dhand, dcards);

    if (phv == bust) {
        *win = 0.;
        *draw = 0.;
        *lose = 1.;
        return;
    }
    if (dhv == bust) {
        *win = 1.;
        *draw = 0.;
        *lose = 0.;
        return;
    }
    if (phv == twenty_one) {
        if (dhv == twenty_one) {
            *win = 0.;
            *draw = 1.;
            *lose = 0.;
        }
        else {
            *win = 1.;
            *draw = 0.;
            *lose = 0.;
        }
        return;
    }
    if (dhv == twenty_one) {
        *win = 0.;
        *draw = 0.;
        *lose = 1.;
        return;
    }

    if (dhv > 16) {
        if (dhv > phv) {
            *win = 0.;
            *draw = 0.;
            *lose = 1.;
        }
        else if (dhv < phv) {
            *win = 1.;
            *draw = 0.;
            *lose = 0.;
        }
        else {
            *win = 0.;
            *draw = 1.;
            *lose = 0.;
        }
        return;
    }

    double twin = 0., tdraw = 0., tlose = 0.;
    double t2win, t2draw, t2lose, draw_card_prob;

    int deck_count = count_deck(deck);

    for (int i = 0; i < 10; i++) {
        if (deck[i] == 0)
            continue;

        dhand[dcards] = i;

        draw_card_prob = (double)deck[i] / deck_count;

        if (hand_value(dhand, dcards + 1) == bust) {
            twin += draw_card_prob;
            continue;
        }

        deck[i]--;

        dealer_drawing_win_prob(deck, phv, dhand, dcards + 1, &t2win, &t2draw, &t2lose);

        deck[i]++;

        twin += draw_card_prob * t2win;
        tdraw += draw_card_prob * t2draw;
        tlose += draw_card_prob * t2lose;
    }

    *win = twin;
    *draw = tdraw;
    *lose = tlose;
}

void win_hand_prob(char deck[10], char phand[22], int pcards, char dhand[22], int dcards, double* win, double* draw, double* lose)
{
    int phv = hand_value(phand, pcards);
    int dhv = hand_value(dhand, dcards);

    if (phv == bust)
    {
        *win = 0.;
        *draw = 0.;
        *lose = 1.;
        return;
    }
    if (dhv == bust)
    {
        *win = 1.;
        *draw = 0.;
        *lose = 0.;
        return;
    }
    if (phv == twenty_one)
    {
        if (dhv == twenty_one)
        {
            *win = 0.;
            *draw = 1.;
            *lose = 0.;
        }
        else
        {
            *win = 1.;
            *draw = 0.;
            *lose = 0.;
        }
        return;
    }
    if (dhv == twenty_one)
    {
        *win = 0.;
        *draw = 0.;
        *lose = 1.;
        return;
    }

    double hit_win = 0., hit_draw = 0., hit_lose = 0., stay_win, stay_draw, stay_lose, draw_card_prob;
    double twin, tdraw, tlose;

    int deck_count = count_deck(deck);

    dealer_drawing_win_prob(deck, hand_value(phand, pcards), dhand, dcards, &stay_win,
            &stay_draw, &stay_lose);

    for (int i = 0; i < 10; i++)
    {
        if (deck[i] == 0)
            continue;

        phand[pcards] = i;

        draw_card_prob = (double) deck[i] / deck_count;

        if (hand_value(phand, pcards + 1) == bust)
        {
            hit_lose += draw_card_prob;
            continue;
        }

        deck[i]--;

        win_hand_prob(deck, phand, pcards + 1, dhand, dcards, &twin, &tdraw, &tlose);

        deck[i]++;

        hit_win += draw_card_prob * twin;
        hit_draw += draw_card_prob * tdraw;
        hit_lose += draw_card_prob * tlose;
    }

    if ((hit_win - hit_lose) > (stay_win - stay_lose))
    {
        *win = hit_win;
        *draw = hit_draw;
        *lose = hit_lose;
    }
    else
    {
        *win = stay_win;
        *draw = stay_draw;
        *lose = stay_lose;
    }
}

void* win_hand_prob_threading(void* argss) {
    struct arg_struct* args = (struct arg_struct*) argss;

    int phv = hand_value(args->phand, args->pcards);
    int dhv = hand_value(args->dhand, args->dcards);

    if (phv == bust) {
        *args->win = 0.;
        *args->draw = 0.;
        *args->lose = 1.;
        return NULL;
    }
    if (dhv == bust) {
        *args->win = 1.;
        *args->draw = 0.;
        *args->lose = 0.;
        return NULL;
    }
    if (phv == twenty_one) {
        if (dhv == twenty_one) {
            *args->win = 0.;
            *args->draw = 1.;
            *args->lose = 0.;
        }
        else {
            *args->win = 1.;
            *args->draw = 0.;
            *args->lose = 0.;
        }
        return NULL;
    }
    if (dhv == twenty_one) {
        *args->win = 0.;
        *args->draw = 0.;
        *args->lose = 1.;
        return NULL;
    }

    double hit_win = 0., hit_draw = 0., hit_lose = 0., stay_win, stay_draw, stay_lose, draw_card_prob;
    double twin, tdraw, tlose;

    int deck_count = count_deck(args->deck);

    dealer_drawing_win_prob(args->deck, hand_value(args->phand, args->pcards), args->dhand, args->dcards, &stay_win, &stay_draw, &stay_lose);

    for (int i = 0; i < 10; i++) {
        if (args->deck[i] == 0)
            continue;

        args->phand[args->pcards] = i;

        draw_card_prob = (double)args->deck[i] / deck_count;

        if (hand_value(args->phand, args->pcards + 1) == bust) {
            hit_lose += draw_card_prob;
            continue;
        }

        args->deck[i]--;

        win_hand_prob(args->deck, args->phand, args->pcards + 1, args->dhand, args->dcards, &twin, &tdraw, &tlose);

        args->deck[i]++;

        hit_win += draw_card_prob * twin;
        hit_draw += draw_card_prob * tdraw;
        hit_lose += draw_card_prob * tlose;
    }

    if ((hit_win - hit_lose) > (stay_win - stay_lose)) {
        *args->win = hit_win;
        *args->draw = hit_draw;
        *args->lose = hit_lose;
    }
    else {
        *args->win = stay_win;
        *args->draw = stay_draw;
        *args->lose = stay_lose;
    }
    return NULL;
}


double win_prob(char deck[10], double* win, double* draw, double* lose) {
    double pwin = 0., pdraw = 0., plose = 0.;
    double twin, tdraw, tlose, hand_prob;

    char phand[22];
    char dhand[22];

    int deck_count = count_deck(deck);

    for (int i = 0; i < 10; i++) {
        if (deck[i] == 0)
            continue;

        phand[0] = i;
        deck[i]--;

        for (int j = 0; j < 10; j++) {
            if (deck[j] == 0)
                continue;

            dhand[0] = j;
            deck[j]--;

            for (int k = 0; k < 10; k++) {
                if (deck[k] == 0)
                    continue;

                phand[1] = k;
                deck[k]--;

                pthread_t tids[10];

                double probs[30];
                double hand_probs[10];
                char* decks[10];
                char* pass_deck;
                char* phands[10];
                char* pass_phand;
                char* dhands[10];
                char* pass_dhand;

                struct arg_struct* pass_args;
                struct arg_struct* passed_args[10];

                for (int l = 0; l < 10; l++) {
                    printf("(%d, %d, %d, %d)n", i, j, k, l);
                    if (deck[l] == 0)
                    {
                        decks[l] = NULL;
                        phands[l] = NULL;
                        dhands[l] = NULL;
                        continue;
                    }
                    dhand[1] = l;
                    deck[l]--;

                    pass_deck = (char*) malloc(10 * sizeof(char));
                    decks[l] = pass_deck;
                    memcpy(pass_deck, deck, 10 * sizeof(char));

                    pass_phand = (char*) malloc(22 * sizeof(char));
                    phands[l] = pass_phand;
                    memcpy(pass_phand, phand, 22 * sizeof(char));

                    pass_dhand = (char*) malloc(22 * sizeof(char));
                    dhands[l] = pass_dhand;
                    memcpy(pass_dhand, dhand, 22 * sizeof(char));

                    pass_args = (struct arg_struct*) malloc(sizeof(struct arg_struct));
                    pass_args->deck = pass_deck;
                    pass_args->phand = pass_phand;
                    pass_args->pcards = 2;
                    pass_args->dhand = pass_dhand;
                    pass_args->dcards = 2;
                    pass_args->win = &(probs[l * 3]);
                    pass_args->draw = &(probs[l * 3 + 1]);
                    pass_args->lose = &(probs[l * 3 + 2]);
                    // (struct arg_struct){pass_deck, phand, 2, dhand, 2, &(probs[l * 3]), &(probs[l * 3 + 1]), &(probs[l * 3 + 2])};
                    passed_args[l] = pass_args;

                    hand_probs[l] = (double)(deck[i] + 1) * (deck[j] + 1) * (deck[k] + 1) * (deck[l] + 1) / ((deck_count) * (deck_count - 1) * (deck_count - 2) * (deck_count - 3));

                    // pwin += hand_prob * twin;
                    // pdraw += hand_prob * tdraw;
                    // plose += hand_prob * tlose;

                    deck[l]++;
                }

                for (int i = 0; i < 10; i++){
                    if (deck[i] == 0)
                        continue;
                    pthread_join(tids[i], NULL);
                }
                for (int i = 0; i < 10; i++){
                    if (deck[i] == 0)
                        continue;
                    pwin += hand_probs[i] * probs[i * 3];
                    pdraw += hand_probs[i] * probs[i * 3 + 1];
                    plose += hand_probs[i] * probs[i * 3 + 2];
                    free(decks[i]);
                    free(passed_args[i]);
                    free(phands[i]);
                    free(dhands[i]);
                }
                deck[k]++;
            }
            deck[j]++;
        }
        deck[i]++;
    }
    *win = pwin;
    *draw = pdraw;
    *lose = plose;
}


int main() {
    char deck[10];
    fill_deck(deck, 6);

    deck[card_indices[2]] = 0;
    deck[card_indices[3]] = 0;
    deck[card_indices[4]] = 0;
    deck[card_indices[9]] = 0;

    /*
    char phand[22] = { card_indices[10], card_indices[10] };
    int pcards = 2;

    char dhand[22] = { card_indices[5], card_indices[6] };
    int dcards = 2;

    deck[phand[0]] -= 1;
    deck[phand[1]] -= 1;
    deck[dhand[0]] -= 1;
    deck[dhand[1]] -= 1;
    */

    double win, draw, lose;

    // dealer_drawing_win_prob(deck, hand_value(phand, pcards), dhand, dcards, &win, &draw, &lose);
    // win_hand_prob(deck, phand, pcards, dhand, dcards, &win, &draw, &lose);
    win_prob(deck, &win, &draw, &lose);

    // printf("Player hand: %d, %dn", (int)card_values[phand[0]], (int)card_values[phand[1]]);
    // printf("Dealer hand: %d, %dn", (int)card_values[dhand[0]], (int)card_values[dhand[1]]);
    printf("Player win: %0.5f, draw: %0.5f, lose: %0.5fn", win, draw, lose);

    printf("Press any key to exit: n");
    get_single_char();

    return 0;
}

int hand_value(char hand[22], int cards) {
    if (cards == 2) {
        if ((hand[0] == card_indices[11] && hand[1] == card_indices[10]) ||
            (hand[1] == card_indices[11] && hand[0] == card_indices[10]))
            return twenty_one;
    }

    int aces = 0;
    int value = 0;
    for (int i = 0; i < cards; i++) {
        if (hand[i] == card_indices[11]) {
            aces++;
            continue;
        }
        value += card_values[hand[i]];
    }

    int ret;
    if (aces > 0)
        ret = ((21 - value - aces) / 10) * 10 + aces + value;
    else
        ret = value;

    return (ret > 21) ? bust : ret;
}

void fill_deck(char deck[10], int num_decks) {
    for (int i = 0; i < 10; i++) {
        if (i == 8) {
            deck[i] = 16 * num_decks;
            continue;
        }
        deck[i] = 4 * num_decks;
    }
}

int count_deck(char deck[10]) {
    int ret = 0;

    for (int i = 0; i < 10; i++) {
        ret += deck[i];
    }

    return ret;
}

void clear_stream(void)
{
    int c;
    while ((c = getchar()) != 'n' && c != EOF) {
        continue;
    }
}

int get_single_char(void)
{
    int input;

    input = getchar();

    if (input != 'n') {
        clear_stream();
    }

    return input;
}

jack.h

//
// Created by antho on 10/31/2022.
//

#ifndef BAYESIAN_BLACKJACK_JACK_H
#define BAYESIAN_BLACKJACK_JACK_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>

#define twenty_one 23
#define bust 22

const char card_values[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; // rank value of card from number representation
const char card_indices[] = { 0, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // number representation of card from rank value

struct arg_struct {
    char* deck;
    char* phand;
    int pcards;
    char* dhand;
    int dcards;
    double* win;
    double* draw;
    double* lose;
};

void clear_stream();
int get_single_char();
void fill_deck(char deck[10], int num_decks);
int hand_value(char hand[22], int cards);
int count_deck(char deck[10]);

#endif //BAYESIAN_BLACKJACK_JACK_H

I tried allocating every variable I would need to use on the heap, but it still segfaults. The debugger does not give any hints either.

12

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *