最新 追記

sugi memo

  1. jboyfwkmogslqf (06-01)
  2. drswkutw (06-01)
  3. pjnsoycoywou (06-01)
2004|01|02|03|04|05|06|07|08|09|11|
2005|02|

2004-04-09

zsh 補完関数の書き方

<URL:http://www.ayu.ics.keio.ac.jp/~mukai/translate/write_zsh_functions.html>

zsh の独自補完の書き方は、日本語の情報がほとんどないのが現状なのでうれしい。

本日のツッコミ(全99件) [ツッコミを入れる]

Before...

_ jdlhed [[url=http://blog.360.yahoo.com/blog-12SVlrc5dKodOFwAkH67Ru..]

_ ccrbrnfkcbcqno [[url=http://blog.360.yahoo.com/blog-W8EBmvM5bqQN8_5ZvGa3c3..]

_ pjnsoycoywou [[url=http://blog.360.yahoo.com/blog-hDqen3M6erLjJgBOLGJWJi..]

_ drswkutw [[url=http://blog.360.yahoo.com/blog-10OWMx40d68qCcudLbVwJR..]

_ jboyfwkmogslqf [[url=http://blog.360.yahoo.com/blog-ZlHtA9Eyc6O3rsMW_MQ4wu..]


2004-04-15

プロのコード、アマのコード

<URL:http://arton.no-ip.info/diary/20040415.html#p03> で見かけたので、 Test::Unit の練習も兼ねて Ruby で書いてみました。

以下、過程を全部書いてるので長いです。

テストファーストということで、まずはテストから書く。

# jankentest.rb
require 'test/unit'
require 'janken'

class TC_Janken < Test::Unit::TestCase
  def test_win
    p = Player.new
    p.win
    assert_equal("プレイヤーの勝敗数:1勝0敗0引き分け", p.results)
  end
end

結果。

% ruby jankentest.rb
Loaded suite jankentest
Started
E
Finished in 0.001 seconds.

  1) Error:
test_win(TC_Janken):
NameError: uninitialized constant TC_Janken::Player
    jankentest.rb:6:in `test_win'

1 tests, 0 assertions, 0 failures, 1 errors

Player が全く実装されてないんだから当たり前。

# janken.rb
class Player
  def win
  end

  def results
    "プレイヤーの勝敗数:1勝0敗0引き分け"
  end
end

結果をいきなり埋め込んでるけどとりあえずこれで通る。

class Player
  def initialize
    @n_win = 0
  end

  def win
    @n_win += 1
  end

  def results
    "プレイヤーの勝敗数:#{@n_win}勝0敗0引き分け"
  end
end

ちゃんとカウントするようにする。

# TC_Janken
def test_lose
  p = Player.new
  p.lose
  assert_equal("プレイヤーの勝敗数:0勝1敗0引き分け", p.results)
end

負けも同様のテスト。

class Player
  def initialize
    @n_win = 0
    @n_lose = 0
  end

  def win
    @n_win += 1
  end

  def lose
    @n_lose += 1
  end

  def results
    "プレイヤーの勝敗数:#{@n_win}勝#{@n_lose}敗0引き分け"
  end
end

同様に実装。

def test_draw
  p = Player.new
  p.draw
  assert_equal("プレイヤーの勝敗数:0勝0敗1引き分け", p.results)
end

引き分けのテスト。(実装略)

ここで、次に Player#hand で手を出させたいところだが、 このテストってどう書けばいいのだろうか……

よく分からないので、とりあえず

def test_hand
  p = Player.new
  p.hand
end

とだけ書いて、実装されていることのテストだけしておく。

def hand
  puts '手を選んでください(0:グー、1:チョキ、2:パー)'
  s = gets
  s.to_i
  # todo: エラー処理
end

実装はこう。

次に試合の部分。

def test_game
  p0 = Player.new
  p1 = Player.new
  p0.hand = 0
  p1.hand = 0
  g = Game.new
  g.play(p0, p1)
  assert_equal("プレイヤーの勝敗数:0勝0敗1引き分け", p0.results)
  assert_equal("プレイヤーの勝敗数:0勝0敗1引き分け", p1.results)
end

どの手を出すかを分かっていないとテストが書けないので、 Player#hand= も作る。

# class Player
def hand
  if @hand
    h = @hand
    @hand = nil
    return h
  end

  puts '手を選んでください(0:グー、1:チョキ、2:パー)'
  s = gets
  s.to_i
  # todo: エラー処理
end

def hand=(h)
  @hand = h
end

Game の実装。

class Game
  def play(*players)
  end
end

試合判定の部分がまだ。

class Game
  JudgeTable = [
    [0, 1, -1],
    [-1, 0, 1],
    [1, -1, 0],
  ]

  def play(*players)
    # assert players.size == 2
    p0 = players[0]
    p1 = players[1]
    r = JudgeTable[p0.hand][p1.hand]
    case r
    when 0
      p0.draw; p1.draw
    when 1
      p0.win; p1.lose
    when -1
      p0.lose; p1.win
    end
  end
end

YAGNI 的に(?)、2人ゲームの場合のみを実装する。

これで、一応テストは全部通ったが、引き分けの場合しかテストがまだないので 勝ちと負けのテストも書く。

def test_game_win
  p0 = Player.new
  p1 = Player.new
  p0.hand = 0
  p1.hand = 1
  g = Game.new
  g.play(p0, p1)
  assert_equal("プレイヤーの勝敗数:1勝0敗0引き分け", p0.results)
  assert_equal("プレイヤーの勝敗数:0勝1敗0引き分け", p1.results)
end

これも OK。

さて、じゃんけんのたびに「プレイヤーの勝ちです」などのように結果を表示しないといけない。

def test_game_draw
  p0 = Player.new('プレイヤー0')
  p1 = Player.new('プレイヤー1')
  p0.hand = 0
  p1.hand = 0
  g = Game.new
  result = g.play(p0, p1)
  assert_equal('  プレイヤー0:グー  プレイヤー1:グー …… あいこです', result)
  assert_equal("プレイヤー0の勝敗数:0勝0敗1引き分け", p0.results)
  assert_equal("プレイヤー1の勝敗数:0勝0敗1引き分け", p1.results)
end

def test_game_win
  p0 = Player.new('プレイヤー0')
  p1 = Player.new('プレイヤー1')
  p0.hand = 0
  p1.hand = 1
  g = Game.new
  result = g.play(p0, p1)
  assert_equal('  プレイヤー0:グー  プレイヤー1:チョキ …… プレイヤー0の勝ちです', result)
  assert_equal("プレイヤー0の勝敗数:1勝0敗0引き分け", p0.results)
  assert_equal("プレイヤー1の勝敗数:0勝1敗0引き分け", p1.results)
end

Player のコンストラクタの引数の数が合わない。

# class Player
def initialize(name = 'プレイヤー')
  @name = name
  @n_win = 0
  @n_lose = 0
  @n_draw = 0
  @hand = nil
end

result の中にも名前を入れる。

# class Player
def results
  "#{@name}の勝敗数:#{@n_win}勝#{@n_lose}敗#{@n_draw}引き分け"
end

この段階で、Game#play の戻り値がおかしいことがテストで分かるので修正。

def play(*players)
  # assert players.size == 2
  p0 = players[0]
  p1 = players[1]
  p0_hand = p0.hand
  p1_hand = p1.hand
  r = JudgeTable[p0_hand][p1_hand]
  case r
  when 0
    p0.draw; p1.draw
    "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… あいこです"
  when 1
    p0.win; p1.lose
    "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… #{p0.name}の勝ちです"
  when -1
    p0.lose; p1.win
    "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… #{p1.name}の勝ちです"
  end
end

まだ通らない。p0_hand はただの数値なので、グーとかいう文字にならない。 ここは、グー・チョキ・パーをクラスにしてしまうのがいいだろう。

テストをこう書き換えて

def test_game_draw
  p0 = Player.new('プレイヤー0')
  p1 = Player.new('プレイヤー1')
  p0.hand = Hand::Guu
  p1.hand = Hand::Guu
  g = Game.new
  result = g.play(p0, p1)
  assert_equal('  プレイヤー0:グー  プレイヤー1:グー …… あいこです', result)
  assert_equal("プレイヤー0の勝敗数:0勝0敗1引き分け", p0.results)
  assert_equal("プレイヤー1の勝敗数:0勝0敗1引き分け", p1.results)
end

手のクラスを作って

module Hand
  class TGuu
    def to_i; 0 end
    def to_s; 'グー' end
  end

  class TChoki
    def to_i; 1 end
    def to_s; 'チョキ' end
  end

  class TPaa
    def to_i; 2 end
    def to_s; 'パー' end
  end

  Guu = TGuu.new
  Choki = TChoki.new
  Paa = TPaa.new
end

Game#play を書き換える

r = JudgeTable[p0_hand.to_i][p1_hand.to_i]

これで、テストが全部通る。

ここで、JudgeTable は Hand モジュールの中に移した方がいいように見えるので移動。 テストが通ることを確認。

次は、コンピュータプレイヤーを作る。

これまでの Player を GenericPlayer に名前を変え、 Player は GenericPlayer から継承させる。 hand と hand= の実装を GenericPlayer から Player に移動させ、 テストが通ることを確認。

と、ここで ComPlayer#hand を実装するわけだが、 その前に Player#hand が手のオブジェクトではなく数値を返していたので修正する。

Hand::create(n) を作り、0、1、2 に応じたオブジェクトを返す。

# module Hand
def create(n)
  case n
  when 0
    Guu
  when 1
    Choki
  when 2
    Paa
  end
end
module_function :create

ComPlayer の実装。

class ComPlayer < GenericPlayer
  def initialize(name = 'コンピュータ')
    super
  end

  def hand
    Hand::create(rand(3))
  end
end

最後に、5回プレイする部分を記述。

if $0 == __FILE__
  p = Player.new
  com = ComPlayer.new
  g = Game.new
  5.times do |i|
    puts g.play(p, com)
  end
  puts p.results
end

これで終了。

最終結果

class GenericPlayer
  attr_reader :name

  def initialize(name = 'プレイヤー')
    @name = name
    @n_win = 0
    @n_lose = 0
    @n_draw = 0
  end

  def win
    @n_win += 1
  end

  def lose
    @n_lose += 1
  end

  def draw
    @n_draw += 1
  end

  def results
    "#{@name}の勝敗数:#{@n_win}勝#{@n_lose}敗#{@n_draw}引き分け"
  end
end

class Player < GenericPlayer
  def initialize(name = 'プレイヤー')
    super
    @hand = nil
  end

  def hand
    if @hand
      h = @hand
      @hand = nil
      return h
    end

    puts '手を選んでください(0:グー、1:チョキ、2:パー)'
    s = gets
    Hand::create(s.to_i)
    # todo: エラー処理
  end

  def hand=(h)
    @hand = h
  end

end

class ComPlayer < GenericPlayer
  def initialize(name = 'コンピュータ')
    super
  end

  def hand
    Hand::create(rand(3))
  end
end


module Hand
  JudgeTable = [
    [0, 1, -1],
    [-1, 0, 1],
    [1, -1, 0],
  ]

  class TGuu
    def to_i; 0 end
    def to_s; 'グー' end
  end

  class TChoki
    def to_i; 1 end
    def to_s; 'チョキ' end
  end

  class TPaa
    def to_i; 2 end
    def to_s; 'パー' end
  end

  Guu = TGuu.new
  Choki = TChoki.new
  Paa = TPaa.new

  def create(n)
    case n
    when 0
      Guu
    when 1
      Choki
    when 2
      Paa
    end
  end
  module_function :create
end

class Game
  def play(*players)
    # assert players.size == 2
    p0 = players[0]
    p1 = players[1]
    p0_hand = p0.hand
    p1_hand = p1.hand
    r = Hand::JudgeTable[p0_hand.to_i][p1_hand.to_i]
    case r
    when 0
      p0.draw; p1.draw
      "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… あいこです"
    when 1
      p0.win; p1.lose
      "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… #{p0.name}の勝ちです"
    when -1
      p0.lose; p1.win
      "  #{p0.name}:#{p0_hand}  #{p1.name}:#{p1_hand} …… #{p1.name}の勝ちです"
    end
  end
end


if $0 == __FILE__
  p = Player.new
  com = ComPlayer.new
  g = Game.new
  5.times do |i|
    puts g.play(p, com)
  end
  puts p.results
end

うーん、何かまだまだ粗が目立ちますね……

感想

一番気になるのは、0、1、2 とグー・チョキ・パーの対応が、 JudgeTable、(TGuu|TChoki|TPaa)#to_i、Hand::create() の 3箇所にちらばっているところ。

じゃんけんは手が3種類だからこれでもまだいいけど、 もっと複雑なルールのゲームだとこれではまずいだろう。

何かいい方法あるかな……

色見本

どこで知ったか忘れてしまったのですが、 ある色を入れるとそれに合う色を提示してくれるページ。

<URL:http://www.colormatch.dk/>

ソースもすごい。

本日のツッコミ(全99件) [ツッコミを入れる]

Before...

_ ma383zda [c269t mp3 player tips2008 - http://Mp3Player2008.zoomshare..]

_ inkjet printer tips2008 [c1t internet web hosting tips2008 - http://InternetWebHost..]

_ goodyear tire tips2008 [c498t franklin mint tips2008 - http://FranklinMint2008.zoo..]

_ foreclosure property tips2008 [c42t refinancing loan tips2008 - http://RefinancingLoan200..]

_ ma934zda [c862t colorado refinance tips2008 - http://ColoradoRefinan..]


2004-04-16

本日のツッコミ(全82件) [ツッコミを入れる]

Before...

_ Clayton-M-Cox [Some education links. Please delete this message if it was..]

_ Nicholas Conceicao [Your are Great. And so is your site! Awesome content. Good..]

_ Eva Sutherland [I am so thankful for finding your website! http://chat.tra..]

_ Christopher Siniscalo [Great work! http://qblog.askmrq.com/?u=nbuycarisoprodol7 <..]

_ Kai Boot [Very good site! Thanks! :-) http://zcheapphentermine8.onli..]


2004-04-22

今日のオプション

% du -sh ~/Mail

du の -h は --human-readable。

<URL:http://i.loveruby.net/d/20040421.html#p03>より。

ちなみに8.9Mでした。

一番古いのが1999年9月。個人的なメールが500通ほど、事務的なメールが200通ほど。

メーリングリストのメールは、以前は全部手元に残していたんですが、 今は2週間ほどで自動的に捨てています。

[NovelEngine] ノベルゲームのスクリプティングについて

RandomNote に「わからない」 と書いたところ、 <URL:http://www.denpa.org/~go/denpa/200404/from21.html#21_2> にて詳しく説明をいただきました。ありがとうございます。

しばらく考えて、ようやく分かった気がします。

次のスクリプト

鈴菜:詩子も来るでしょ? [環境 待ち 1000][がっかり]と言うか来い。付き合え

は、

------>時刻 t
声: う_た_こ_も_く_る_で_しょ________|と_い_う_か_こ_い___つ_き_あ_え
文: 詩子も来るでしょ?___(1sec)______|と言うか来い。付き合え
________________________________待つ↑

のように実行される。(等幅フォントのつもりで)

これが、例えばメッセージ表示速度を遅くすると

------>時刻 t
声: う_た_こ_も_く_る_で_しょ________|と_い_う_か_こ_い___つ_き_あ_え
文: 詩__子__も__来__る__で__し__ょ__?______(1sec)___|と__言__う__か__来__い__。__付__き__合__え

となってしまいずれるから

鈴菜:詩子も来るでしょ? [声待ち 3000][がっかり]と言うか来い。付き合え

として

------>時刻 t ------------------- t=3↓
声: う_た_こ_も_く_る_で_しょ________|と_い_う_か_こ_い___つ_き_あ_え
文: 詩子も来るでしょ?__(t=3まで)____|と言うか来い。付き合え
________________________________待つ↑

これでとりあえず解決した。しかし……という問題提起でいいのでしょうか?

構造化データについて

実際に書かれるスクリプト形式がどうなるのかが示されていないので何とも言えませんが、 テキストを演出記述などから分離するのは、補助ツール等をうまく作らないと かえって分かりづらくなるおそれもあると思います。

例えば上の例では、

鈴菜:詩子も来るでしょ? [環境 待ち 1000][がっかり]と言うか来い。付き合え

という記述では、これを見るだけで途中で「がっかり」に変わることが分かりますが、 テキストを分離してしまうと、テキストを見るだけではそれが分からなくなってしまいます。

ただこれについては、

  • このことはそもそも問題なのか?
  • うまくスクリプト文法を作れば解決できるのではないか?
  • うまく補助ツールを作れば解決できるのではないか?

などの点に関してまだあまり考えていないため、判断は保留ということにしておきます。

本日のツッコミ(全1380件) [ツッコミを入れる]

Before...

_ Viagra [Your site is awesome <a href="http://students.concord.edu/..]

_ Viagra [You have a great site <a href="http://ibscore.dbs.umt.edu/..]

_ Viagra [You have a top notch site <a href="http://faculty.plattsbu..]

_ buy viagra online [ <a href="http://www.life2themax.net/links/jump.php?id=256..]

_ i was happy [I agree with RSA. This could work, but a simple bulletted ..]


2004-04-28

[NovelEngine] ノベルゲームのスクリプティングについて(2)

ちょっと思いだしたのは Ruby の文法の話で、 Ruby は

if foobar
  func
end

みたいな end 文法の言語なのですが、これを採用することになった理由の一つに end 文法を採用しても Emacs の ruby-mode を作れることが判明したからってのがあるそうです。

リンク先には書いてないのですが、もし ruby-mode が作れなかったら C 言語みたいに {} を使う 文法にしていたかもしれないというのも、確か Linux Magazine のまつもと氏の連載に書いてありました。

結局のところ全ては成果物を作りやすくするためにあるのですから、 やはり、スクリプタが演出を指定するために使うツールの側から考えた方がいいのかもしれません。

お返事

<URL:http://www.denpa.org/~go/denpa/200404/from21.html#27_1>

スクリプト文法的な問題もありません。
適切な(=論理的に目的とするデータ構造を再現する)文法はいくらでも提供できるでしょう。
ただ、その文法の熟知をスクリプタに求めるのは酷です。 

この部分を読んでちょっとひっかかったのですが、これは要するに 「文法を熟知していればスクリプトの直書きも可能ではあるが、 文法を熟知していなくても演出指定ができるようにするべきである」 という理解でいいのでしょうか?

まず大雑把なテキスト入力をテキストエディタで行ない、 実際の細かい演出はオーサリングツール上で行なうという感じでしょうか。

ごうさんのお話しで、「結局、スクリプタが組む文法としてはどういうものを考えているんだろう」というのが 分からずにもやもやとしていたのですが、オーサリングツールを使ってやるということになるということで 何となくもやもやが晴れました。

文法はどうだとかいうことしか気にしていない時点でテキストエディタ打ち込みを暗黙のうちに仮定してしまっていたわけで、 それはまずかったなと思います。

Fate とか、スクリプトすげーことになってるわけですが、死にながら作業してたんだろうか。あと Qualtett も。

Fate は、typemoon の清兵衛氏がフロー管理用のフローチャートツールを公開しているようですが、 演出部のスクリプティングがどうなっているかは知らないです。 (というか Fate まだやってなかったり。夏まではできそうにないなぁ……)

Qualtett は体験版しかやってないのですが、自動生成っぽい感じを受けなかったんですよね。 あれを手で入力していくのはさすがにつらすぎるんじゃないかという気もするんですが……

本日のツッコミ(全100件) [ツッコミを入れる]

Before...

_ Ikjmgd [<a href="http://codtramadoluk.squarespace.com/">tramadol o..]

_ Lmncxwe [<a href="http://shrinkurl.us/rxxanaxgener">xanax generic</..]

_ zvljxv [http://fm7.biz/tfb http://fm7.biz/tfc http://fm7.biz/tfd h..]

_ txymzw [http://fm7.biz/tfl http://fm7.biz/tfm http://fm7.biz/tfn h..]

_ Kouyusi [<a href="http://tomas.quickfreehost.com/buygenericviagra.h..]