[topic] 憂鬱な勇者

RPG他の要素を全て省略してレベルアップだけするプログラム。自動またはユーザからのアクションによって、RPG風の経験値の獲得とレベルアップメッセージを出力します。

元祖のソースコードは Ruby で書かれています。

http://d.hatena.ne.jp/hrkt0115311/20080527/1211891558

出力はほぼ原典どおりですが、それぞれの言語の特徴にあわせた処理の仕方で書いてみるとどうなるでしょうか(オブジェクト指向、再帰処理が書きやすい、など)。

これまでの言語別移植リストはこちらに掲載されています。

http://d.hatena.ne.jp/keyword/%cd%ab%dd%b5%a4%ca%cd%a6%bc%d4

Posted feedbacks - Nested

Flatten Hidden
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
module Main where

import Data.List
import qualified System.IO.UTF8 as U
import System.IO.Unsafe
import System.Random

shuffle :: StdGen -> [a] -> ([a],StdGen)
shuffle g xs = shuffle' [] g (length xs,xs)
  where shuffle' acc g (0,_)  = (acc,g)
        shuffle' acc g (n,xs) = case randomR (0,n-1) g of
          (i,g') -> case splitAt i xs of
                      (ys,z:zs) -> shuffle' (z:acc) g' (n-1,ys++zs)

facts = scanl (*) 1 [1..30]
monsters = ["焼きたてパン","強いシャチホコ","もんじゃ焼き一年生","怪人ホタテ男","ニセ勇者","逃げ足の早いアレ","睡魔","煩悩","愛らしい子犬の中の人","恋するスズメバチ","勇敢なクマンバチ","信じられない物","勇者の師匠","浮遊する鎧","怪盗ドボン","闇の招き猫","誘惑のカスタードクリーム","しょっぱすぎる籠手","カレー味の兜","光沢だけは一流の盾","若葉マークのモンスター","新緑の季節","梅雨時の車両のニオイ","暑すぎる夏","新宿らしき何か","やたら発達したドーナツ","育ちすぎたクマー","なごやかな雰囲気","凍り付いた気配","忍び寄る恐怖"]

skills = ["お豆腐の買い方","鉛筆の買い方","消しゴムの使い方","メモの取り方","攻撃に使えないこともない呪文","裏町の歩き方","森林浴","珈琲の味","しじみのみそ汁の作り方","回覧板の回し方","郵便物の投函方法","立ち話のコツ","猫の呼び方","犬の呼び方","カラスの呼び方","鳩専用豆鉄砲","秘密の趣味","速く走るコツ","剣の使い方","斧の使い方","まきわりで、まっきわりわり","聖なる祈り","孤独","涼しく過ごすコツ","お洒落のコツ","卵をふわっと焼く方法","ごはんの研ぎ方","油汚れの対応方法","大人の振るまい","Suicaの使い方"]

main = do { g <- getStdGen
          ; let (ms,g') = shuffle g monsters
          ; let (ss,_)  = shuffle g' skills
          ; U.putStrLn 
          $ unlines 
          $ intersperse sep 
          $ map showStep 
          $ zip [1..30] 
          $ zip3 facts ms ss
          }

showStep (l,(v,m,s))
  = unlines 
  $ ["*-----"
    ,m++"を倒した!"
    ,show (facts !! l) ++ "の経験値を得た."
    ,"勇者は"++(if l==30 then "また,"
                else show l ++"に")++"レベルが上った!"
    ,"勇者は"++(if l==30 then "ふと空しさ" 
                else s) ++"を覚えた."]

sep = unlines ["そして,"
              ,"かくかくかじかで,山あり谷ありの冒険が続いがが割愛."]

書きわすれましたが、日本語(utf8)を表示するにはutf8-stringというパッケージが提供するSystem.IO.UTF8モジュールが必要です。

言語の特徴にあわせてということで、Lisp といえばマクロなのでしょうが、使い道が浮かびませんでした。format と loop もまあ特徴といってもいいかなということで、この二つを軸に。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#-clisp (defun ! (n) (if (zerop n) 1 (* n (! (1- n)))))

(defconstant +monsters+
  #("焼きたてパン" "強いシャチホコ" "もんじゃ焼き一年生" "怪人ホタテ男"
    "ニセ勇者" "逃げ足の早いアレ" "睡魔" "煩悩" "愛らしい子犬の中の人"
    "恋するスズメバチ" "勇敢なクマンバチ" "信じられない物" "勇者の師匠"
    "浮遊する鎧" "怪盗ドボン" "闇の招き猫" "誘惑のカスタードクリーム"
    "しょっぱすぎる籠手" "カレー味の兜" "光沢だけは一流の盾"
    "若葉マークのモンスター" "新緑の季節" "梅雨時の車両のニオイ" "暑すぎる夏"
    "新宿らしき何か" "やたら発達したドーナツ" "育ちすぎたクマー"
    "なごやかな雰囲気" "凍り付いた気配" "忍び寄る恐怖"))

(defconstant +skills+
  #("お豆腐の買い方" "鉛筆の買い方" "消しゴムの使い方" "メモの取り方"
    "攻撃に使えないこともない呪文" "裏町の歩き方" "森林浴" "珈琲の味"
    "しじみのみそ汁の作り方" "回覧板の回し方" "郵便物の投函方法"
    "立ち話のコツ" "猫の呼び方" "犬の呼び方" "カラスの呼び方" "鳩専用豆鉄砲"
    "秘密の趣味" "速く走るコツ" "剣の使い方" "斧の使い方"
    "まきわりで、まっきわりわり" "聖なる祈り" "孤独" "涼しく過ごすコツ"
    "お洒落のコツ" "卵をふわっと焼く方法" "ごはんの研ぎ方"
    "油汚れの対応方法" "大人の振るまい" "Suicaの使い方"))

(defun level-up-message (level monster skill &optional melancholy-p)
  (format t "~&*-----
~Aを倒した!
~D の経験値を得た。
勇者は~:[ ~D に~;、また、~]レベルが上がった!
勇者は、~:[~A~;ふと空しさ~]を覚えた。~%"
          monster (! level)
          melancholy-p level
          melancholy-p skill))

(defun interval-message ()
  (format t "~3%そして、
かくかくしかじかで、山あり谷ありの冒険が続いたが割愛。~2%"))

(loop for x from 1
  as monster = (aref +monsters+ (random 30))
  and skill = (aref +skills+ (random 30))
  while (< x 30)
  do (level-up-message x monster skill)
     (interval-message)
  finally (level-up-message x monster nil t))

意味はないけど、Iterableにしてみました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import java.math.BigInteger;
import java.util.Iterator;
import java.util.Random;


public class Sample182 implements Iterable<String> {
    private static final int MAX_BUTTLES = 30;

    private static final String[] Monsters = {
        "焼きたてパン", "強いシャチホコ", "もんじゃ焼き一年生", "怪人ホタテ男",
        "ニセ勇者", "逃げ足の早いアレ", "睡魔", "煩悩", "愛らしい子犬の中の人",
        "恋するスズメバチ", "勇敢なクマンバチ", "信じられない物", "勇者の師匠",
        "浮遊する鎧", "怪盗ドボン", "闇の招き猫", "誘惑のカスタードクリーム",
        "しょっぱすぎる籠手", "カレー味の兜", "光沢だけは一流の盾",
        "若葉マークのモンスター", "新緑の季節", "梅雨時の車両のニオイ",
        "暑すぎる夏", "新宿らしき何か", "やたら発達したドーナツ", "育ちすぎたクマー",
        "なごやかな雰囲気", "凍り付いた気配", "忍び寄る恐怖",
    };
    private static final String[] Skills = {
        "お豆腐の買い方", "鉛筆の買い方", "消しゴムの使い方", "メモの取り方",
        "攻撃に使えないこともない呪文", "裏町の歩き方", "森林浴", "珈琲の味",
        "しじみのみそ汁の作り方", "回覧板の回し方", "郵便物の投函方法",
        "立ち話のコツ", "猫の呼び方", "犬の呼び方", "カラスの呼び方",
        "鳩専用豆鉄砲", "秘密の趣味", "速く走るコツ", "剣の使い方", "斧の使い方",
        "まきわりで、まっきわりわり", "聖なる祈り", "孤独", "涼しく過ごすコツ",
        "お洒落のコツ", "卵をふわっと焼く方法", "ごはんの研ぎ方", "油汚れの対応方法",
        "大人の振るまい", "Suicaの使い方",
    };

    private static final String MessageTemplate1 = "*-----%n" +
            "%sを倒した!%n" +
            "%sの経験値を得た。%n" +
            "勇者は%dにレベルが上がった!%n" +
            "勇者は、%sを覚えた。%n";
    private static final String MessageTemplate2 = "*-----%n" +
            "%sを倒した!%n" +
            "%sの経験値を得た。%n" +
            "勇者は、また、レベルが上がった!%n" +
            "勇者は、ふと空しさを覚えた。%n";
    private static final String MessageIntermission = "%n" +
            "そして、%n" +
            "かくかくしかじかで、山あり谷ありの冒険が続いたが割愛。%n";


    @Override
    public Iterator<String> iterator() {
        return new Iterator<String>() {
            private final Random random_ = new Random();

            private int buttle_ = 0;
            private BigInteger exp_ = BigInteger.ONE;
            private boolean isIntermission_ = false;

            @Override
            public boolean hasNext() {
                return buttle_ < MAX_BUTTLES;
            }

            @Override
            public String next() {
                if (isIntermission_) {
                    isIntermission_ = false;
                    return String.format(MessageIntermission);
                } else {
                    buttle_++;
                    String format = (buttle_ == MAX_BUTTLES)? MessageTemplate2: MessageTemplate1;
                    exp_ = exp_.multiply(BigInteger.valueOf(buttle_));
                    isIntermission_ = true;
                    return String.format(format,
                            Monsters[random_.nextInt(Monsters.length)],
                            exp_.toString(),
                            buttle_,
                            Skills[random_.nextInt(Skills.length)]);
                }
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }


    public static void main(String[] args) {
        for (String msg: new Sample182()) {
            System.out.println(msg);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}

面白かったですー。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/env ocaml
#load "nums.cma";;
#load "unix.cma";;
open Big_int;;

let monster =
  [|"焼きたてパン";"強いシャチホコ";"もんじゃ焼き一年生";
  "怪人ホタテ男";"ニセ勇者";"逃げ足の早いアレ";"睡魔";
  "煩悩";"愛らしい子犬の中の人";"恋するスズメバチ";
  "勇敢なクマンバチ";"信じられない物";"勇者の師匠";
  "浮遊する鎧";"怪盗ドボン";"闇の招き猫";
  "誘惑のカスタードクリーム";"しょっぱすぎる籠手";
  "カレー味の兜";"光沢だけは一流の盾";"若葉マークのモンスター";
  "新緑の季節";"梅雨時の車両のニオイ";"暑すぎる夏";
  "新宿らしき何か";"やたら発達したドーナツ";"育ちすぎたクマー";
  "なごやかな雰囲気";"凍り付いた気配";"忍び寄る恐怖"|]

let skill =
 [|"お豆腐の買い方";"鉛筆の買い方";"消しゴムの使い方";
  "メモの取り方";"攻撃に使えないこともない呪文";
  "裏町の歩き方";"森林浴";"珈琲の味";"しじみのみそ汁の作り方";
  "回覧板の回し方";"郵便物の投函方法";"立ち話のコツ";"猫の呼び方";
  "犬の呼び方";"カラスの呼び方";"鳩専用豆鉄砲";"秘密の趣味";
  "速く走るコツ";"剣の使い方";"斧の使い方";
  "まきわりで、まっきわりわり";"聖なる祈り";"孤独";
  "涼しく過ごすコツ";"お洒落のコツ";"卵をふわっと焼く方法";
  "ごはんの研ぎ方";"油汚れの対応方法";
  "大人の振るまい";"Suicaの使い方"|]

let len_monster = Array.length monster
let len_skill = Array.length skill

let exp = 
  let tmp = ref (unit_big_int)  in
  Array.init 30 (fun i -> 
    tmp := (mult_int_big_int (i+1) !tmp);
    string_of_big_int !tmp)

let form = format_of_string "\
    *-----\n\
    %sを倒した!\n\
    %sの経験値を得た。\n\
    勇者は%sレベルが上がった!\n\
    勇者は、%sを覚えた。\n\n%!" ;;


let hero exp sec = 
  let len = Array.length exp in

  for i = 0 to len-2 do
    Printf.printf form
      monster.(Random.int len_monster)
      exp.(i)
      (string_of_int (i+1) ^ "に")
      skill.(Random.int len_skill);
    
    Unix.sleep sec;
    print_endline "\nそして、\n\
      かくかくしかじかで、\
      山あり谷ありの冒険が続いたが割愛。\n";
    Unix.sleep sec;
  done;

  Printf.printf form 
    monster.(Random.int len_monster)
    exp.(len-1) "、また、" "ふと虚しさ";;

hero exp 1;;

階乗計算をどうするかがポイントですかね。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
//モンスターリスト
$monster = array("焼きたてパン","強いシャチホコ","もんじゃ焼き一年生","怪人ホタテ男","ニセ勇者","逃げ足の早いアレ","睡魔","煩悩","愛らしい子犬の中の人","恋するスズメバチ","勇敢なクマンバチ","信じられない物","勇者の師匠","浮遊する鎧","怪盗ドボン","闇の招き猫","誘惑のカスタードクリーム","しょっぱすぎる籠手","カレー味の兜","光沢だけは一流の盾","若葉マークのモンスター","新緑の季節","梅雨時の車両のニオイ","暑すぎる夏","新宿らしき何か","やたら発達したドーナツ","育ちすぎたクマー","なごやかな雰囲気","凍り付いた気配","忍び寄る恐怖");

//スキルリスト
$skill = array("お豆腐の買い方","鉛筆の買い方","消しゴムの使い方","メモの取り方","攻撃に使えないこともない呪文","裏町の歩き方","森林浴","珈琲の味","しじみのみそ汁の作り方","回覧板の回し方","郵便物の投函方法","立ち話のコツ","猫の呼び方","犬の呼び方","カラスの呼び方","鳩専用豆鉄砲","秘密の趣味","速く走るコツ","剣の使い方","斧の使い方","まきわりで、まっきわりわり","聖なる祈り","孤独","涼しく過ごすコツ","お洒落のコツ","卵をふわっと焼く方法","ごはんの研ぎ方","油汚れの対応方法","大人の振るまい","Suicaの使い方",);

for($i = 0; $i < 30; $i++){
    echo "*-----\n";
    shuffle($monster);
    echo array_pop($monster) . "を倒した!\n";
    echo fact($i + 1) . "の経験値を得た。\n";
    if(count($monster) == 0)
        break;
    echo "勇者は" . ($i + 1) . "にレベルが上がった!\n";
    shuffle($skill);
    echo "勇者は、" . array_pop($skill) . "を覚えた。\n\n\n";
    echo "そして、\nかくかくしかじかで、山あり谷ありの冒険が続いたが割愛。\n\n";
}
echo "勇者は、また、レベルが上がった!\n";
echo "勇者は、ふと空しさを覚えた。";

//階乗計算
function fact($x){
    return bcmul($x ,($x <= 1 ? 1 : fact(bcsub($x, 1))));
}
windows 用のコンソール版の場合です。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
monster =: <;._1 ' 焼きたてパン 強いシャチホコ もんじゃ焼き一年生 怪人ホタテ男 ニセ勇者 逃げ足の早いアレ 睡魔 煩悩 愛らしい子犬の中の人 恋するスズメバチ 勇敢なクマンバチ 信じられない物 勇者の師匠 浮遊する鎧 怪盗ドボン 闇の招き猫 誘惑のカスタードクリーム しょっぱすぎる籠手 カレー味の兜 光沢だけは一流の盾 若葉マークのモンスター 新緑の季節 梅雨時の車両のニオイ 暑すぎる夏 新宿らしき何か やたら発達したドーナツ 育ちすぎたクマー なごやかな雰囲気 凍り付いた気配 忍び寄る恐怖'

skill =: <;._1 ' お豆腐の買い方 鉛筆の買い方 消しゴムの使い方 メモの取り方 攻撃に使えないこともない呪文 裏町の歩き方 森林浴 珈琲の味 しじみのみそ汁の作り方 回覧板の回し方 郵便物の投函方法 立ち話のコツ 猫の呼び方 犬の呼び方 カラスの呼び方 鳩専用豆鉄砲 秘密の趣味 速く走るコツ 剣の使い方 斧の使い方 まきわりで、まっきわりわり 聖なる祈り 孤独 涼しく過ごすコツ お洒落のコツ 卵をふわっと焼く方法 ごはんの研ぎ方 油汚れの対応方法 大人の振るまい Suicaの使い方'

sleep =: 6!:3
9!:1 >.5{6!:0 ''  NB. random seed 
p =: 1!:2&2       NB. print

main =: 3 : 0
sel =. ?@# { ]
for_i. >:i.30 do.
  p '*-----'
  p (>sel monster),'を倒した!'
  p (":!x:i), 'の経験値を得た。'
  if. i<30 do.
    p '勇者は',(":i),'にレベルが上がった!'
    p '勇者は、',(>sel skill),'を覚えた。'
    p ''
    sleep 2
    p ''
    p 'そして、'
    p 'かくかくしかじかで、山あり谷ありの冒険が続いたが割愛。'
    p ''
  else.
    p '勇者は、また、レベルが上がった!'
    p '勇者は、ふと空しさを覚えた。'
  end.
end.
)
exit main ''

Index

Feed

Other

Link

Pathtraq

loading...