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