石取りゲーム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