石取りゲーム2

目次

Unknown programmer's programming note.

1. プログラムの概要

ishi2 - 石取りゲーム2をプレイする

ルール

  • 山から交互に石を取る
  • 取ることのできる石の数は、直前に取った相手の石の数の2倍を越えてはいけない
  • 最後の石を取った方が勝ち
  • 最初だけは好きな数だけ取ることができるが、全部を取ってはいけない
  • パスはできない

2. C

/*
 * 出典元「C言語による最新アルゴリズム事典」奥村晴彦著 - P7
 * インデントは変更してあります。
 * 他にも、メッセージや変数名や処理を変更している場合があります。
 */

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    int max;
    int n;
    int x;
    int fibo[21];
    int r;
    int my_turn;

    /* init fibonacci */
    fibo[1] = fibo[2] = 1;
    for (i = 3; i <= 20; i++)
    {
        fibo[i] = fibo[i - 1] + fibo[i - 2];
    }

    printf("How many stones? [2..10000] ");
    scanf("%d", &n);

    if (n < 2 || n > 10000)
    {
        return EXIT_FAILURE;
    }

    max = n - 1;

    for (my_turn = 1; n != 0; my_turn ^= 1)
    {
        printf("You can take up to %d stones.\n", max);
        if (my_turn)
        {
            x = n;
            for (i = 20; x != fibo[i]; i--) /* 20: high index of fibo */
            {
                if (x > fibo[i])
                {
                    x -= fibo[i];
                }
            }
            if (x > max)
            {
                x = 1;
            }
            printf("I take %d %s.\n", x, (x == 1 ? "stone" : "stones"));
        }
        else
        {
            do
            {
                printf("How many stones do you take? ");
                r = scanf("%d", &x);
                scanf("%*[^\n]");
            } while (r != 1 || x < 1 || x > max);
        }

        n -= x;
        max = 2 * x;
        if (max > n)
        {
            max = n;
        }

        if (n == 1)
        {
            printf("There remains one stone.\n");
        }
        else
        {
            printf("There remain %d stones.\n", n);
        }
    }

    if (my_turn)
    {
        printf("You win!\n");
    }
    else
    {
        printf("I win!\n");
    }
}

3. Emacs Lisp

(defun ishi ()
  (let* ((n (read-number "How many stones? [2..10000] "))
         (m (1- n))
         (my-turn t)
         output-buffer)

    (when (or (< n 1) (> n 10000))
      (error "Invalid game settings"))

    (setq output-buffer (get-buffer-create "*ishi*"))
    (switch-to-buffer-other-window output-buffer)
    (goto-char (point-max))
    (if (step-game n m my-turn (fibonacci 20))
        (insert (format "I win!\n"))
      (insert (format "You win!\n")))
    ))

(defun step-game (n m my-turn fibo)
  (let ((x 0)
        n-next
        m-next)
    (when (<= n 0)
      (error "invalid game"))

    (insert (format "You can take up to %s.\n" (stone-plural m)))

    (cond (my-turn
           (setq x n)
           (let ((fval (car fibo))
                 (f fibo))
             (while (not (= x fval))
               (when (> x fval)
                 (setq x (- x fval)))
               ;; next fibonacci number
               (setq f (cdr f))
               (setq fval (car f))))
           (when (> x m)
             (setq x 1))

           (insert (format "I take %s.\n" (stone-plural x))))
          (t
           (while (progn
                    (setq x (read-number "How many stones do you take? "))
                    (or (<= x 0) (< x 1) (> x m))
                    ))))

    (setq n-next (- n x))
    (setq m-next (if (> (* 2 x) n-next)
                     n-next
                   (* 2 x)))

    (insert (format "There remains %s.\n" (stone-plural n-next)))

    (if (= n-next 0)
        my-turn
      (step-game n-next m-next (not my-turn) fibo))))

(defun fibonacci (n &optional acc)
  (cond ((zerop n)
         nil)
        ((= n 1)
         '(1))
        ((= n 2)
         '(1 1))
        (t
         (let ((a (fibonacci (1- n) acc)))
           (cons (+ (car a) (cadr a)) a)))))

(defun stone-plural (x)
  (if (= x 1)
      "one stone"
    (format "%d stones" x)))

(ishi)

4. Bash

#!/bin/bash

function make_fibonacci_series {
    fibo=(0 1 1)
    for i in $(seq 3 $1)
    do
        fibo+=( $(( ${fibo[$(( $i - 1 ))]} + ${fibo[$(( $i - 2 ))]})) )
    done

    echo ${fibo[@]}
}

function stone_plural {
    if [ $1 -eq 1 ]
    then
        printf "one stone"
    else
        printf "%d stones" $1
    fi
}

fibo=($(make_fibonacci_series 20))

read -p "How many stones? [2..10000] " n

if [ $n -lt 2 -o $n -gt 10000 ]
then
    exit 1
fi

my_turn=1
max=$(( $n - 1 ))

while [ $n -ne 0 ]
do
    printf "You can take up to %s.\n" "$(stone_plural $max)"

    if [ $my_turn -eq 1 ]
    then
        x=$n
        i=$(( ${#fibo[@]} - 1 ))
        while test $x -ne ${fibo[$i]}
        do
            if test $x -gt ${fibo[$i]}
            then
                x=$(( $x - ${fibo[$i]}))
            fi
            (( i-- ))
        done
        if [ $x -gt $max ]
        then
            x=1
        fi
        printf "I take %s.\n" "$(stone_plural $x)"
    else
        while
            read -p "How many stones do you take? " x
            [ ! $? -o $x -lt 1 -o $x -gt $max ]
        do true; done
    fi

    n=$(( $n - $x ))
    max=$(( 2 * $x ))
    if [ $max -gt $n ]
    then
        max=$n
    fi

    printf "There remain %s.\n" "$(stone_plural $n)"

    my_turn=$(( $my_turn ^ 1 ))
done

if [ $my_turn -eq 1 ]
then
    echo "You win!"
else
    echo "I win!"
fi

5. Fish

#!/usr/bin/fish

function make_fibonacci_series
    set fibo 1 1
    for i in (seq 3 $argv[1])
        set fibo[$i] (math $fibo[$(math $i - 1)] + $fibo[(math $i - 2)])
    end

    for i in $fibo
        echo $i
    end
end

function stone_plural
    if test $argv[1] -eq 1
        printf "one stone"
    else
        printf "%d stones" $argv[1]
    end
end

set fibo (make_fibonacci_series 20)

read -P "How many stones? [2..10000] " n

if test $n -lt 2 -o  $n -gt 10000
    exit 1
end

set my_turn 1
set max (math $n - 1)

while test $n -ne 0
    printf "You can take up to %s.\n" (stone_plural $max)

    if test $my_turn -eq 1
        set x $n
        set -l i (count $fibo)
        while test $x -ne $fibo[$i]
            if test $x -gt $fibo[$i]
                set x (math $x - $fibo[$i])
            end
            set i (math $i - 1)
        end

        if test $x -gt $max
            set x 1
        end
        printf "I take %s.\n" (stone_plural $x)
    else
        set -l ok 0
        while test $ok -eq 0
            read -P "How many stones do you take? " x

            if test $x = 'q'
                exit 1
            end

            if test $status -eq 0 -a $x -ge 1 -a $x -le $max
                set ok 1
            end
        end
    end

    set n (math $n - $x)
    set max (math 2 x $x)
    if test $max -gt $n
        set max $n
    end

    printf "There remain %s.\n" (stone_plural $n)

    set my_turn (math bitxor $my_turn, 1)
end

if test $my_turn -eq 1
    echo "You win!"
else
    echo "I win!"
end

著者: watercat

Created: 2022-10-08 土 11:52

Emacs 28.2 (Org mode 9.5.5)

Validate