0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ブラックジャックもどきゲーム、BlackJick

Last updated at Posted at 2023-12-29

カードゲームのブラックジャックをコンピュータとプレイするプログラム(もどき)を作ったけれども、カジノでやるようなブラックジャックは知らないし、指摘を受けて、また作り直そうとしてwebを検索してみたら、ディーラーとのやり取りが意外と複雑だったので、開発を中止し、元のプログラムはせっかく作ったし、これはこれで遊べるので、'BlackJick'として残しておきます。Jickとは、僕が以前飼ってた黒猫で、隣の幼稚園の壁の上に置いてコンビニに出かけたら、いなくなりました。このプログラムをJickに捧げます。

Cで書かれています。

ソースをコピペして、cc blackjick.c -o blackjickとしてコンパイルし、./blackjickとして実行させてください。

このプログラムは古典的確率論で推測する初歩的人工知能版です。

遊び方

最初にコンピュータ、プレイヤー双方ともに2枚のカードが配られます。相手のカードは見えません。手札の合計が21を超えないように山からカードを引いていきます。コンピュータは確率計算に基づきカードを引いていきます。
ジョーカーは1枚入っていて、0から10までの任意の値を取ることができます。A(エース)は常に1です。ブラックジャックのように11になったりしません。Jack,Queen,Kingは共に10として計算します。手札の合計が大きいほうが勝ちですが、21を超えたらアウトです。コンピュータ、プレイヤーが同じ点数の場合、ジョーカーを持ってたほうが勝ちです。
1.でカードを引き、2.でコンピュータと勝負です。

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

typedef struct {
    int mark; // 0:no card 1:heart 2:dia 3:club 4:spade 5:joker
    int number; // 1 ~ 13 0:joker
} card;

#define TRUMP (53)
#define DRAWMAX (12)    		// maximum number of cards per player

card cards[TRUMP];
int cardidx=0;
card comp_cards[DRAWMAX];
card player_cards[DRAWMAX];

card id2card(int c)
{
    card cd;
    cd.mark=(c==0)?5:(c-1)/13+1;
    cd.number=(c==0)?0:(c-1)%13+1;
    return cd;
}

void shuffle()
{
    int r[TRUMP]= {0},ss[TRUMP],c;
    srand((unsigned)time(NULL));
    for(int k=0; k<TRUMP; k++) {
        while(r[c=rand()%TRUMP]);
        r[ss[k]=c]=1;
    }
    for(int i=0; i<TRUMP; i++)
        cards[i]=id2card(ss[i]);
}

void draw_card(card cd[])
{
    int i=0;
    while(cd[i].mark) i++;
    if (cardidx<TRUMP && i<DRAWMAX)
        cd[i]=cards[cardidx++];
}

void init_players()
{
    for(int i=0; i<DRAWMAX; i++)
        comp_cards[i].mark=player_cards[i].mark=0;
    draw_card(comp_cards);
    draw_card(comp_cards);
    draw_card(player_cards);
    draw_card(player_cards);
}

int number_of_cards(card cd[])
{
    int idx=0;
    while(cd[idx].mark) idx++;
    return idx;
}

int isjoker(card cd[])
{
    int idx=0;
    while(cd[idx].mark)
        if (cd[idx++].mark==5)
            return 1;
    return 0;
}

void printcard(card cd)
{
    static char *marks[]= {"","♥","♦","♣","♠","Joker"};
    static char *numbers[]= {"","A","2","3","4","5","6","7","8","9","10",
                             "J","Q","K" };
    printf("[%s%s] ",marks[cd.mark],numbers[cd.number]);
}

int count_cards(card cd[])
{
    int n,i=0,v=0;
    while(cd[i].mark) {
        n=cd[i++].number;
        v+=n<=10?n:10;
    }
    return v;
}

int eval_cards(card cd[])
{
    int v=count_cards(cd),jv=isjoker(cd)?(v<=21?(21-v>=11?10:21-v):0):0;
    return v+jv;
}

void print_players_line(card cd[])
{
    int t,i=0;
    while(cd[i].mark)
        printcard(cd[i++]);
    printf(" total=%3d ",t=eval_cards(cd));
    if (t==21)
        printf("*BlackJick*");
    printf("\n");
}

void print_comp()
{
    int idx=0;
    while(comp_cards[idx++].mark)
        printf("[###] ");
    printf("%d cards.\n",idx-1);
}

int game()
{
    // game
    int status,cv=eval_cards(comp_cards),pv=eval_cards(player_cards);
    if (cv==21 && pv==21|| cv==pv)
        if (isjoker(comp_cards))
            status=2;
        else if (isjoker(player_cards))
            status=1;
        else
            status=0;
    else if (cv>=22 && pv>=22)
        status=0;
    else if (cv>=22 && pv<=21)
        status=1;
    else if (cv<=21 && pv>=22)
        status=2;
    else if (cv<pv)
        status=1;
    else
        status=2;
    return status;
}

double expected_value_of_next_card(card self[])
{
    int noc=TRUMP-number_of_cards(self),n=count_cards(self);
    int j=isjoker(self)?0:(n>=21?0:(n<11?10:21-n));
    return ((double)340+j-n)/noc;
}

int todrawp(card self[])
{
    return eval_cards(self)>=21?0:(count_cards(self)+expected_value_of_next_card(self))<=21.00?1:0;
}

int computer_turn()
{
    if (todrawp(comp_cards)) {
        printf("Computer drew a card.\n");
        draw_card(comp_cards);
        return 1;
    }
    return 0;
}

void play()
{
    int d=0;
    do {
        double e;
        printf("---------------------------------------------------\n");
        printf("Pile : %d cards\n",TRUMP-cardidx);
        printf("Computer's cards : ");
        print_comp();
        printf("Player's cards : ");
        print_players_line(player_cards);
        e=expected_value_of_next_card(player_cards);
        printf("Expected value of next 1 card is %1.8lf.\n",e);
        printf("Have to draw ? %s.\n",todrawp(player_cards)?"Yes":"No");
        printf("1. Draw a card.\n2. Game.\n: ");
        scanf("%d",&d);
        if (d==1)
            draw_card(player_cards);
        computer_turn();
    } while(d!=2);
    while(computer_turn());
}

void result(int g) {
    printf("====================Result====================\n");
    printf("Computer : ");
    print_players_line(comp_cards);
    printf("Player : ");
    print_players_line(player_cards);
    printf("%s.\n",(g==0)?"Draw game":(g==1)?"Player win":"Computer win");
}

int main()
{
    printf("**********BlackJick ver 1.0**********\n");
    shuffle();
    init_players();
    play();
    result(game());
}

python版
blackjick.py
import random

class Card:
    def __init__(self, mark, number):
        self.mark = mark  # 0:no card 1:heart 2:dia 3:club 4:spade 5:joker
        self.number = number  # 1 ~ 13 0:joker

trump = 53
drawmax = 12
cards = []
cardidx = 0
comp_cards = [Card(0, 0) for _ in range(drawmax)]
player_cards = [Card(0, 0) for _ in range(drawmax)]

def id2card(c):
    mark = 5 if c == 0 else (c - 1) // 13 + 1
    number = 0 if c == 0 else (c - 1) % 13 + 1
    return Card(mark, number)

def shuffle():
    global cards, cardidx
    r = [0] * trump
    ss = []
    random.seed()
    for _ in range(trump):
        c = random.randint(0, trump-1)
        while r[c]:
            c = random.randint(0, trump-1)
        r[c] = 1
        ss.append(c)
    cards = [id2card(ss[i]) for i in range(trump)]

def draw_card(cd):
    global cardidx
    i = 0
    while cd[i].mark:
        i += 1
    if cardidx < trump and i < drawmax:
        cd[i] = cards[cardidx]
        cardidx += 1

def init_players():
    global comp_cards, player_cards
    for i in range(drawmax):
        comp_cards[i].mark = player_cards[i].mark = 0
    draw_card(comp_cards)
    draw_card(comp_cards)
    draw_card(player_cards)
    draw_card(player_cards)

def number_of_cards(cd):
    idx = 0
    while cd[idx].mark:
        idx += 1
    return idx

def isjoker(cd):
    idx = 0
    while cd[idx].mark:
        if cd[idx].mark == 5:
            return 1
        idx += 1
    return 0

def printcard(cd):
    marks = ["", "", "", "", "", "Joker"]
    numbers = ["", "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
    print("[{}{}] ".format(marks[cd.mark], numbers[cd.number]), end='')

def count_cards(cd):
    i = 0
    total_value = 0
    while cd[i].mark:
        n = cd[i].number
        total_value += n if n <= 10 else 10
        i += 1
    return total_value

def eval_cards(cd):
    total_value = count_cards(cd)
    joker_value = 10 if isjoker(cd) and total_value <= 21 else 0
    return total_value + joker_value

def print_players_line(cd):
    i = 0
    while cd[i].mark:
        printcard(cd[i])
        i += 1
    print("total={:3d} ".format(eval_cards(cd)), end='')
    if eval_cards(cd) == 21:
        print("*BlackJick*")
    print()

def print_comp():
    idx = 0
    while comp_cards[idx].mark:
        print("[###] ", end='')
        idx += 1
    print("{} cards.".format(idx - 1))

def game():
    cv = eval_cards(comp_cards)
    pv = eval_cards(player_cards)
    if (cv == 21 and pv == 21) or cv == pv:
        if isjoker(comp_cards):
            return 2
        elif isjoker(player_cards):
            return 1
        else:
            return 0
    elif cv >= 22 and pv >= 22:
        return 0
    elif cv >= 22 and pv <= 21:
        return 1
    elif cv <= 21 and pv >= 22:
        return 2
    elif cv < pv:
        return 1
    else:
        return 2

def expected_value_of_next_card(self):
    noc = trump - number_of_cards(self)
    n = count_cards(self)
    j = 0 if isjoker(self) else 0 if n >= 21 else 10 if n < 11 else 21 - n
    return (340 + j - n) / noc

def todrawp(self):
    return 0 if eval_cards(self) >= 21 else 1 if count_cards(self) + expected_value_of_next_card(self) <= 21.0 else 0

def computer_turn():
    global comp_cards
    if todrawp(comp_cards):
        print("Computer drew a card.")
        draw_card(comp_cards)
        return 1
    return 0

def play():
    d = 0
    while d != 2:
        print("---------------------------------------------------")
        print(f"Pile : {trump - cardidx} cards")
        print("Computer's cards : ", end='')
        print_comp()
        print("Player's cards : ", end='')
        print_players_line(player_cards)
        e = expected_value_of_next_card(player_cards)
        print(f"Expected value of next 1 card is {e:.8f}.")
        print("Have to draw ? {}.".format("Yes" if todrawp(player_cards) else "No"))
        d = int(input("1. Draw a card.\n2. Game.\n: "))
        if d == 1:
            draw_card(player_cards)
        computer_turn()
    while computer_turn():
        pass

def result(g):
    print("====================Result====================")
    print("Computer : ", end='')
    print_players_line(comp_cards)
    print("Player : ", end='')
    print_players_line(player_cards)
    print(["Draw game", "Player win", "Computer win"][g])

if __name__ == "__main__":
    print("**********BlackJick ver 1.0**********")
    shuffle()
    init_players()
    play()
    result(game())
0
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?