Craps賭博遊戲


說明

一個簡單的賭博遊戲,遊戲規則如下:玩家擲兩個骰子,點數為1到6,如果第一次點數和為7或11,則玩家勝,如果點數和為2、3或12,則玩家輸,如果和 為其它點數,則記錄第一次的點數和,然後繼續擲骰,直至點數和等於第一次擲出的點數和,則玩家勝,如果在這之前擲出了點數和為7,則玩家輸。

解法

規則看來有些複雜,這是一個遊戲嗎?不!這是兩個遊戲,第一個遊戲規則是事先設定好輸贏點數,第二個遊戲規則是要指定贏的點數(由玩家擲出),分別對這兩 個遊戲的規則撰寫函式,就可避免看似複雜的switch、if等條件判斷(如 C 到 JavaScript 的實作所示)。

不過就流程來說,主要就是擲骰、使用規則判斷、顯示輸贏或繼續。規則判斷是一種策略,因此可使用回呼函式或物件傳入,遊戲流程就可當作可重用樣版了(如 Haskell 的實作所示)。

實作:C    Java    Python    Scala    Ruby    JavaScript    Haskell

  • C
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define LOST 0
#define WON 1
#define CONTINUE 2

int dice();
int initialRoll(int);
int reRoll(int, int);

int main(void) {
srand(time(0));

int firstPoint = dice();
printf("玩家點數:[%d]\n", firstPoint);

int status = initialRoll(firstPoint);
while(status == CONTINUE) {
int point = dice();
printf("玩家點數:%d\n", point);
status = reRoll(firstPoint, point);
}

puts(status == WON ? "玩家勝" : "玩家輸");

return 0;
}

int dice() {
return (rand() % 6) + (rand() % 6) + 2;
}

int initialRoll(int firstPoint) {
switch(firstPoint) {
case 7: case 11: return WON;
case 2: case 3: case 12: return LOST;
default: return CONTINUE;
}
}

int reRoll(int firstPoint, int point) {
return firstPoint == point ? WON : (7 == point ? LOST : CONTINUE);
}

  • Java
import static java.lang.Math.random;
import static java.lang.System.out;

enum Status { WON, LOST, CONTINUE }

public class Craps {
public static int dice() {
return (int)(random() * 6) + (int)(random() * 6) + 2;
}

public static Status initialRoll(int firstPoint) {
switch(firstPoint) {
case 7: case 11: return Status.WON;
case 2: case 3: case 12: return Status.LOST;
default: return Status.CONTINUE;
}
}

public static Status reRoll(int firstPoint, int point) {
return firstPoint == point ? Status.WON :
(7 == point ? Status.LOST : Status.CONTINUE);
}

public static void main(String[] args) {
int firstPoint = dice();
out.printf("玩家點數:[%d]%n", firstPoint);

Status status = initialRoll(firstPoint);

while(status == Status.CONTINUE) {
int point = dice();
out.printf("玩家點數:%d%n", point);
status = reRoll(firstPoint, point);
}

out.println(status == Status.WON ? "玩家勝" : "玩家輸");
}
}

  • Python
from random import randint

class Status:
LOST = 0
WON = 1
CONTINUE = 2

def initialRoll(firstPoint):
return Status.WON if firstPoint in [7, 11] else \
(Status.LOST if firstPoint in [2, 3, 12] else Status.CONTINUE)

def reRoll(firstPoint, point):
return Status.WON if firstPoint == point else \
(Status.LOST if 7 == point else Status.CONTINUE)

def dice():
return randint(1, 6) + randint(1, 6)

firstPoint = dice()
print("玩家點數:[%d]" % firstPoint)
status = initialRoll(firstPoint)

while status == Status.CONTINUE:
point = dice()
print("玩家點數:%d" % point)
status = reRoll(firstPoint, point)

print("玩家勝" if status == Status.WON else "玩家輸")

  • Scala
import scala.util.Random

object Status extends Enumeration {
val LOST, WON, CONTINUE = Value
}

def dice = {
val r = new Random
(r.nextDouble * 6).toInt + (r.nextDouble * 6).toInt + 2
}

def initialRoll(firstPoint: Int) = firstPoint match {
case 7 | 11 => Status.WON
case 2 | 3 | 12 => Status.LOST
case _ => Status.CONTINUE
}

def reRoll(firstPoint: Int, point: Int) = {
if(firstPoint == point) Status.WON else
(if(7 == point) Status.LOST else Status.CONTINUE)
}

def doWhile(status: Status.Value) {
if(status == Status.CONTINUE) {
val point = dice
printf("玩家點數:%d%n", point)
doWhile(reRoll(firstPoint, point))
}
}

val firstPoint = dice
printf("玩家點數:[%d]%n", firstPoint)
var status = initialRoll(firstPoint)

while(status == Status.CONTINUE) {
val point = dice
printf("玩家點數:%d%n", point)
status = reRoll(firstPoint, point)
}

println(if(status == Status.WON) "玩家勝" else "玩家輸")

  • Ruby
# encoding: Big5

class Status
LOST = 0
WON = 1
CONTINUE = 2
end

def initialRoll(firstPoint)
case firstPoint
when 7, 11; Status::WON
when 2, 3, 12; Status::LOST
else; Status::CONTINUE
end
end

def reRoll(firstPoint, point)
firstPoint == point ? Status::WON :
(7 == point ? Status::LOST : Status::CONTINUE)
end

def dice
(rand * 6).to_i + (rand * 6).to_i + 2
end

firstPoint = dice
puts("玩家點數:[#{firstPoint}]")
status = initialRoll(firstPoint)

while status == Status::CONTINUE
point = dice
puts("玩家點數:#{point}")
status = reRoll(firstPoint, point)
end

puts(status == Status::WON ? "玩家勝" : "玩家輸")

  • JavaScript
var Status = {
LOST : 0,
WON : 1,
CONTINUE : 2
};

function dice() {
return parseInt(Math.random() * 6) + parseInt(Math.random() * 6) + 2;
}

function initialRoll(firstPoint) {
switch(firstPoint) {
case 7: case 11: return 0;
case 2: case 3: case 12: return 1;
default: return 2;
}
return 3;
}

function reRoll(firstPoint, point) {
return firstPoint === point ? Status.WON :
(7 === point ? Status.LOST : Status.CONTINUE);
}

var firstPoint = dice();
print("玩家點數:[" + firstPoint + "]");
var sts = initialRoll(firstPoint);

while(sts === Status.CONTINUE) {
var point = dice();
print("玩家點數:" + point);
sts = reRoll(firstPoint, point);
}

print(sts === Status.WON ? "玩家勝" : "玩家輸");

  • Haskell
import Data.List
import System.Random

data Status = Won | Lost | Continue deriving (Eq)

initialRoll firstPoint =
if firstPoint `elem` [7, 11] then Won
else if firstPoint `elem` [2, 3, 12] then Lost
else Continue

reRoll firstPoint point =
if firstPoint == point then Won
else if 7 == point then Lost
else Continue

diceLt gen = randomRs (1, 6) gen::[Int]

craps roll firstPoint diceLt1 diceLt2 = do
let point = (head diceLt1) + (head diceLt2)
status = roll point
putStrLn \$ "Point:" ++ show point
if status == Continue then
craps r2 firstPoint (tail diceLt1) (tail diceLt2)
else
putStrLn (if status == Won then "Won" else "Lost")
where r2 = \point -> reRoll firstPoint point

main = do
gen1 <- getStdGen
gen2 <- newStdGen
let diceLt1 = diceLt gen1
diceLt2 = diceLt gen2
craps r1 ((head diceLt1) + (head diceLt2)) diceLt1 diceLt2
where r1 = \firstPoint -> initialRoll firstPoint