カードゲームのブラックジャックをコンピュータとプレイするプログラム(もどき)を作ったけれども、カジノでやるようなブラックジャックは知らないし、指摘を受けて、また作り直そうとして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.でコンピュータと勝負です。
#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版
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())