Presentation is loading. Please wait.

Presentation is loading. Please wait.

2007/12/12 ema.

Similar presentations


Presentation on theme: "2007/12/12 ema."— Presentation transcript:

1 2007/12/ ema

2 Agenda オブジェクト指向 ブロック(イテレータ) クラス irb 文法 変数 三目並べ : Tick-tac-toe

3 オブジェクト 指向って?

4 !!! WARNING !!!

5 !!! WARNING !!! プログラミングの経験を前提にしていますが 頭をまっさらにして聞いてください
「C++ / Java ではこうだよね?」 というのは邪魔になりかねません 後、一般的な入門書とは毛色を変えています 詳細は入門書を読み直してください

6 3つのオブジェクト指向 「メッセージング」 by アラン・ケイ 影響を受けている言語 : Smalltalk、Ruby など
影響を受けている言語 : C++ など 「手続きによる抽象化手法」 by ウィリアム・クック オブジェクト指向の概念の発明者は誰ですか?

7 登 場 人 物

8 すべてがオブジェクト 「メッセージング」の考え方 インスタンス メッセージ リテラル すべてがオブジェクト
オブジェクト同士はメッセージをやりとりする インスタンス メッセージ リテラル

9 インスタンスありきと神は語りき 計算してください

10 インスタンス / オブジェクト 計算してください コンピュータ上にある何か

11 メッセージ 計算してください オブジェクト同士のやりとり

12 実 例

13 1 . to_s : 数字の「1」を文字列に ソースコード オブジェクト空間 1 . to_s Rubyインタプリタ

14 リテラルという魔法 1 「1」の インスタンスを生成 1 . to_s

15 メッセージング(メソッド呼び出し) 1 to_s して下さい 1 . to_s

16 結果が返ってくる "1" を生成 1 "1" "1" だよ 1 . to_s

17 評価終了 : 1.to_s => "1" 1 "1" "1" 評価の結果 "1" でした

18 式と評価 式 オブジェクト 1 . to_s “1” 評価 先ほどの 一連の流れのこと Ruby のプログラムは 式 と 評価 の繰り返し
Evaluate : 値にする,推し測る,実行する オブジェクト 1 . to_s “1” 評価 先ほどの 一連の流れのこと

19 メソッド オブジェクトに対する操作 「Ruby 用語集」より 先ほどの例は「to_s」メソッドを呼び出していた
厳密には関数とは違うけど、似たようなもの

20 オブジェクト と メソッド呼び出し 1 to_s して下さい 1 . to_s

21 ブ ロ ッ ク (イテレータ)

22 = 例: 10 回繰り返し 10.times { |i| puts i } ブロック 10.times do |i| puts i end
ブロック内が実行される

23 例: each - ループする 1 each do |i| puts i end 2 3

24 配列 から 配列 を作る A 変換 B

25 map : 関数型言語のノリ [ 1, 2, 3 ].map do |i| i * 2 end 僕が map の意義を理解したのは割と最近
だから、無茶をしようとしているのかも? でも、map そのものは自然なはず [ 1, 2, 3 ].map do |i| i * 2 end

26 配列 : map / collect - 変換 1 2 map do |i| i * 2 end 2 4 3 6 各要素を二倍する

27 配列 : map / collect - 変換 [1, 2, 3] を元に新しい配列を作る 要素を二倍
[ 1, 2, 3 ].map { |i| i * 2 } [ 1, 2, 3 ] ×2 [ 2, 4, 6 ]

28 [1, 2, 3] . map { |i| I * 2 } ブロック (イテレータ) [1,2,3].map { |i| i*2 }

29 [1, 2, 3] の生成 - リテラルらるる [1, 2, 3] の インスタンスを生成 [1,2,3].map { |i| i*2 }

30 メッセージング 結果格納用の 配列を生成 { |i| i*2 } を使って map して下さい
1 2 { |i| i*2 } を使って map して下さい 3 [1,2,3].map { |i| i*2 }

31 ブロックの評価 : 「1」その 1 「i = 1」で 「i * 2」を 評価して下さい [1,2,3].map { |i| i*2 } 1

32 ブロックの評価 : 「1」その 2 2 1 2 結果を格納 3 2 でした [1,2,3].map { |i| i*2 }

33 ブロックの評価 : 「2」その 1 「i = 2」で 「i * 2」を 評価して下さい [1,2,3].map { |i| i*2 } 2

34 ブロックの評価 : 「2」その 2 2 4 1 2 結果を格納 3 4 でした [1,2,3].map { |i| i*2 }

35 ブロックの評価 : 「3」その 1 「i = 3」で 「i * 2」を 評価して下さい [1,2,3].map { |i| i*2 } 2
4 1 2 「i = 3」で 「i * 2」を 評価して下さい 3 [1,2,3].map { |i| i*2 }

36 ブロックの評価 : 「3」その 2 2 4 1 6 2 結果を格納 3 6 でした [1,2,3].map { |i| i*2 }

37 ブロックの評価 : 「3」その 2 2 4 1 6 2 3 [2, 4, 6] だよ [1,2,3].map { |i| i*2 }

38 評価終了 2 4 1 6 2 3 評価の結果 [2, 4, 6] でした [2, 4, 6]

39 ガ ベ ー ジ コレクション

40 ガベージコレクション (GC) "1" 1 役目を終えたね

41 ク ラ ス

42 1.to_s ふたたび 1 to_s 1 . to_s "1" だよ

43 実際には、Fixnum クラスが処理 to_s 1 Fixnum to_s 1 . to_s "1" だよ

44 実際には、Fixnum クラスが処理 to_s 1 2 Fixnum to_s 2 . to_s "2" だよ

45 インスタンス毎は非効率 インスタンス毎にメソッドを用意するのは非効率 共通の処理/特徴をまとめたのがクラス
String(文字列), Array(配列)など

46 継承 : クラスの属性を受け継ぐ sub class super class 基本的にはメッセージを super class に丸投げ
Class A Class B super class 基本的にはメッセージを super class に丸投げ

47 オーバーライド / 再定義 Class A Class B 特定メッセージのみ 反応を変える

48 i r b

49 Interactive RuBy irb コマンド Ruby の式を簡単に入力/実行するためのツール
Ubuntu などだと標準で入ってないので sudo aptitude install irb などとしてインストール

50 Interactive RuBy 文 評価結果 irb(main):001:0> a = "1" => "1"
irb(main):002:0> b = a irb(main):003:0> a += "b" => "1b" irb(main):004:0> b 評価結果

51 休 憩 質問無い?

52 Agenda オブジェクト指向 ブロック(イテレータ) クラス irb 文法 変数 三目並べ : Tick-tac-toe

53 文 法

54 特徴 すべてがオブジェクト ほぼすべての文が値を返す 改行が文の切り替わり。; は書かない慣習 メソッド呼び出しの ( ) は必須ではない
{ } と do end はほぼ等価

55 if - もし○○なら if month == 1 "睦月" elsif month == 2 "如月" # ... 中略 ... else
# エラー end

56 偽になるのは false と nil だけ if 0 puts "hoge" hoge が表示される end
残りは全て 真 になる(0 も!) if 0 puts "hoge" end hoge が表示される

57 nil って? C でいうところの null 未初期化値

58 case - when case month when 1 then "睦月" when 2 then "如月"
# ... 中略 ... when 12 then "師走" else # エラー end

59 unless - もし、○○じゃなかったら unless line.empty? # 空でなければ end

60 while / until - 繰り返し while line = gets puts line end

61 break / next while line = gets # # で始まる行はコメント next if line[0] =~ /^#/
# __END__ だけの行がきたら終わる break if line == '__END__' puts line end

62 修飾子 return if str.empty? retry unless retry_count >= 20
この2つはよく使う。後ろから条件を指定 ぶっちゃけ好みの問題

63 メソッド定義 def japanese_month_name( month ) # ... 中略 ... end メソッド名 引数

64 制御構造も値を返す def japanese_month_name( month ) case month when 1 then "睦月"
# ... 中略 ... when 12 then "師走" else # エラー end

65 メソッド呼び出し a = japanese_month_name( 1 ) b = japanese_month_name 2
( ) は、あっても無くても良い 付けるかどうかは気分次第 読みやすいと感じる方で

66 Array

67 配列って? オブジェクトを複数格納できるもの 何でもいれれる、混在できる a[0] a[1] a[2] a[n-1] 1 "foo"
/bar/ n-2 n-1 n a[-n] a[-3] a[-2] a[-1]

68 サイズ n の配列への添字アクセス a.length / a.size a[0] a[1] a[2] a[n-1] 1 2 3 n-2
a[-n] a[-3] a[-2] a[-1] a.first a.last a.length / a.size

69 配列式 [ 1, 2, 3 ] # 1, 2, 3 の配列を作る [ [ 1, 2 ], [ 3, 4 ] ] # ネストも可能
[ 1, 2, 3 ] # 1, 2, 3 の配列を作る [ [ 1, 2 ], [ 3, 4 ] ] # ネストも可能 %w(one two three) # ["one","two","three"]

70 Hash

71 ハッシュって? オブジェクトを複数格納できるもの 配列の添え字は数字だけ。 ハッシュの添字はオブジェクトなら何でも "foo"
h["name"] 20 h["age"] "male" h["sex"]

72 ハッシュ式 { "name" => "foo", "age" => 20, "sex" => "male" }

73 配列とハッシュの組み合わせ わざわざクラスや構造体を用意せずに 配列とハッシュの組み合わせだけで データ構造を実現することが多い

74 String

75 文字列 "hoge" 'hoge' #{式} で文字列中に値を埋め込める ex. "hoge #{1}" # => "hoge1"
文字列中に値を埋め込むことは出来ない

76 %記法による文字列 %q|"hoge"| # => "hoge" %Q["hoge#{i}"] # => "hoge1"
" や ' などを文字列に入れたいときに重宝 %q|"hoge"| # => "hoge" %Q["hoge#{i}"] # => "hoge1"

77 リテラル

78 その他のリテラル - 魔法の呪文 Symbol : :hoge Fixnum : 1 や -1 や 0xff や ?a
Float : 1.0 や 1.2e-3 Bignum : 100_000_000_000_000_000 Range : や Regexp : /hoge/

79 リテラルの評価 → オブジェクト 配列式 オブジェクト [1, 2, 3] [1, 2, 3] 評価 文字列リテラル オブジェクト
%Q|no: #{i}| "no 1" 評価

80 変 数

81 変数の種類と、名前の規則 ローカル変数 : 小文字 or _ で始まる 定数 : 大文字 で始まる
定数 : 大文字 で始まる 擬似変数 : self, nil, true, false, ... インスタンス変数 で始まる クラス変数 : で始まる グローバル変数 : $ で始まる

82 変数のイメージ : 矢印 [1, 2] a a = [1, 2] b = a a << 3

83 変数のイメージ [1, 2] a b a = [1, 2] b = a a << 3

84 変数のイメージ [1, 2, 3] a b a = [1, 2] b = a a << 3

85 数値や文字列はコピーされる 1 a a = 1 b = a a += 1

86 数値や文字列はコピーされる 1 a 1 b a = 1 b = a a += 1

87 数値や文字列はコピーされる 2 a 1 b a = 1 b = a a += 1

88 三目並べ作り Tick-Tac-Toe

89 実際のコードを読む 実際のコードを読む 出てくる文法的要素を随時解説 三目並べ(Tick-tac-toe)を作ってみた

90 設計 : 入力と出力を決める 入出力は、コマンドライン すなわち、標準入出力を使う

91 実行時のイメージ o のターンです x> 1 y> 3 y x:1 2 3 +-+-+-+ 1 |o|o|x|
2 |x|x| | 3 |o| | |

92 登場人物を洗い出す - クラス候補 ○マス ×マス プレーヤ プレーヤ 空白マス ゲームルール 盤面

93 今回は盤面以外全部クラスにします Maru Batu Player Player Free TickTacToe

94 以下,部分部分をみていきます ソースコードは全部で 160 行ほど 以下,部分部分にわけて読んでいきます

95 クラスの書き方 class クラス名(大文字で始める) # メソッド定義 def hoge end クラス名は大文字で始める

96 duck typing – アヒル風ならアヒル
Batu maru? Free Maru メッセージに 答えてくれれば 何でも良い If it walks like a duck and quacks like a duck, it must be a duck. (アヒルのように歩き, アヒルのように鳴くものはアヒルに違いない) まつもと直伝 プログラミングのオキテ 第4回(3)

97 Maru, Batu, Free - マス目クラス 末尾に「?」が ついてるのは true / false を返す慣習 class Maru
def maru?; true ; end def batu?; false; end def free?; false; end def to_s ; "o" ; end end class Batu def maru?; false; end def batu?; true ; end def free?; false; end def to_s ; "x" ; end end class Free def maru?; false; end def batu?; false; end def free?; true ; end def to_s ; " " ; end end 末尾に「?」が ついてるのは true / false を返す慣習

98 フロー

99 main def main game = TickTacToe.new # 初期化 loop do
puts game.to_s # 盤面表示 game.main # 置いて、プレーヤ交代 break if game.end? # 終了? end game.display_result # 結果表示 # ... 中略 ... main # main 呼び出し

100 TickTacToe#main def main x, y = current_player.input # 入力
put( x, y ) # 置く change_player # プレーヤ交代 end

101 TickTacToe#initialize - 初期化
class TickTacToe def initialize @players = [ Player.new('x'), Player.new('o') ] @current_player_index = 0 @field = Array.new( 3 ) do Array.new( 3 ) { Free.new } end @result = NOT_END

102 TickTacToe#initialize
オブジェクトが初期化されるときに呼ばれる 例えば「 TickTacToe.new 」を呼ぶと, 「 TickTacToe オブジェクト 」 が生成されて, 「 TickTacToe#initialize 」 が実行される TickTacToe.new TickTacToe#initialize

103 インスタンス変数 TickTacToe TickTacToe @ から始まる変数 インスタンスごとに変数を持つ players field
result TickTacToe field players result

104 TickTacToe#initialize - 初期化
class TickTacToe def initialize @players = [ Player.new('x'), Player.new('o') ] @current_player_index = 0 @field = Array.new( 3 ) do Array.new( 3 ) { Free.new } end @result = NOT_END

105 @field の中身 3 x 3 の配列 配列の中に配列 Free Free Free @field[0] Free Free Free

106 なぜ次のコードでは駄目か? Free.new は 1 回しか評価されず 同じオブジェクトを 参照してしまう Free
@field = Array.new( 3 ) do Array.new( 3, Free.new ) end Free.new は 1 回しか評価されず 同じオブジェクトを 参照してしまう Free

107 TickTacToe - フィールド管理 return なくても 値が返る 名前は _ で区切る慣習 def cell( x, y )
@field[y][x] end def set_cell( x, y, obj ) @field[y][x] = obj return なくても 値が返る 名前は _ で区切る慣習

108 TickTacToe#put def put( x, y ) if @current_player_index == 0
set_cell( x, y, Batu.new ) else set_cell( x, y, Maru.new ) end

109 TickTacToe - プレーヤ管理 def current_player
] end def change_player == 0 @current_player_index = 1 else @current_player_index = 0

110 TickTacToe#end? その1 - 終了?
BATU_WIN = 0; MARU_WIN = 1 DRAW = 2; NOT_END = 3 def end? # 三目並ぶ可能性のある座標組合せの一覧を作る candidates = [ ] candidates << [ [0,0], [1,1], [2,2] ] # 斜め candidates << [ [2,0], [1,1], [0,2] ] # 斜め 3.times do |i| candidates << [ [i,0], [i,1], [i,2] ] # 縦 candidates << [ [0,i], [1,i], [2,i] ] # 横 end

111 配列 : push - 末尾に追加 a.push n a << n push 配列の大きさは 勝手に拡張される 1 2 3
n 配列の大きさは 勝手に拡張される

112 TickTacToe#end? その2 - 終了?
candidates.each do |candidate| if candidate.all? { |x,y| cell(x,y).batu? } @result = BATU_WIN; return true end if candidate.all? { |x,y| cell(x,y).maru? } @result = MARU_WIN; return true # 決着がついて無くて,全部埋まれば引き分け @result = DRAW && filled? != NOT_END

113 TickTacToe#end? その3 - filled?
candidates.each do |candidate| if candidate.all? { |x,y| cell(x,y).batu? } @result = BATU_WIN; return true end if candidate.all? { |x,y| cell(x,y).maru? } @result = MARU_WIN; return true # 決着がついて無くて,全部埋まれば引き分け @result = DRAW && filled? != NOT_END

114 TickTacToe#filled? - 埋まった?
def filled? @field.all? do |row| row.all? do |cell| ! cell.free? end class Maru def free?; false; end end class Batu def free?; false; end end class Free def free?; true ; end end

115 all? - 全部が true? Batu Maru Batu Batu Maru Maru Maru Batu Batu
@field.all? do |row| row.all? do |cell| ! cell.free? end Batu Maru Batu Batu Maru Maru Maru Batu Batu

116 all? - 全部が true? 順番に評価される true Batu true true Maru Batu true Batu Maru
@field.all? do |row| row.all? do |cell| ! cell.free? end Batu true true Maru Batu true Batu Maru Maru 順番に評価される Maru Batu Batu

117 all? - 全部が true? 1行ずつ true true true true true true Batu Maru Maru
@field.all? do |row| row.all? do |cell| ! cell.free? end true true true true true Batu Maru Maru 1行ずつ Maru Batu Batu

118 all? - 全部が true? true true true true true true true true true true
@field.all? do |row| row.all? do |cell| ! cell.free? end true true true true true true true true true Maru Batu Batu

119 all? - 全部が true? true @field.all? do |row| row.all? do |cell|
! cell.free? end

120 TickTacToe#end? その4 - all?
candidates.each do |candidate| if candidate.all? { |x,y| cell(x,y).batu? } @result = BATU_WIN; break end if candidate.all? { |x,y| cell(x,y).maru? } @result = MARU_WIN; break # 決着がついて無くて,全部埋まれば引き分け @result = DRAW && filled? != NOT_END 1列全部×? [ [0, 0], [1, 1], [2, 2] ] 1 2 1 2

121 TickTacToe#end? その4 - all?
candidates.each do |candidate| if candidate.all? { |x,y| cell(x,y).batu? } @result = BATU_WIN; return true end if candidate.all? { |x,y| cell(x,y).maru? } @result = MARU_WIN; return true # 決着がついて無くて,全部埋まれば引き分け @result = DRAW && filled? != NOT_END 1列全部×? [ [2, 0], [1, 1], [0, 2] ] 1 2 1 2

122 TickTacToe#display_result
def display_result puts self.to_s # 終局図を表示 puts when BATU_WIN then "x WIN!" when MARU_WIN then "o WIN!" when DRAW then "DRAW" end

123 TickTacToe – to_s : 文字列化
WAKU = " \n" def to_s str = "y x:0 1 2 \n" str += WAKU @field.each_with_index do |row, i| str += "#{i} |" + row.join("|") + "|\n" end return str

124 配列 : join - 連結して文字列化 1 2 join("|") "1|2|3" 3

125 文字列への式の埋め込み "#{i}: #{i*2}" "%d: %d" % [ i, i*2 ] 変数の埋め込み #{} で囲む
シングルクオート ' だと #{} の効果がない "#{i}: #{i*2}" "%d: %d" % [ i, i*2 ]

126 Player クラス アクセサ定義 一行読み込んで,数値化 class Player attr_accessor :name
def initialize( name ) @name = name end def input puts current_player.name + " のターン" print "x> "; x = gets.to_i print "y> "; y = gets.to_i return x, y アクセサ定義 一行読み込んで,数値化

127 attr_XXXX - syntactic sugar
attr_reader 読み取り専用アクセサ - attr_reader :hoge def end attr_write 書き込み専用アクセサ - attr_writer :hoge def = val; end attr_accessor 読み書きアクセサ attr_reader + attr_write

128 Q. CPU を実装するには??

129 Q. Player と CPU の違いは? 入力するのが,人 か コンピュータ かだけ name などは共通なので 継承して再定義する

130 A. CPU クラスを作る 継承 class CPU < Player def input # CPU の思考ルーチンを組み込む
end 継承 class TickTacToe def initialize @players = [ Player.new('x'), CPU.new('o') ] # ... 後略 ... end

131 デバッグ

132 バグがある! 置かれている場所に置けてしまう 盤の内側かどうかをチェックしていない

133 例外処理 例外が throw されると メソッド呼び出しを逆にたどって rescue されたら逆戻りが終わる

134 TickTacToe#put def put( x, y ) unless cell( x, y ).free?
throw "そこには置けません" end == 0 set_cell( x, y, Batu.new ) else set_cell( x, y, Maru.new )

135 エラーの例 def main puts current_player.name + " のターン" def put( x, y )
rescue => e warn e.message retry end def put( x, y ) unless cell( x, y ).free? throw "そこには置けません" end

136 TickTacToe#main def main puts current_player.name + " のターン"
x, y = current_player.input # 入力 put( x, y ) # 置く change_player # プレーヤ交代 rescue => e # 置けなかった warn e.message retry # やり直す end

137 Q. 範囲外を指定したら? 実際にやってみて下さい

138 より情報を 得るには?

139 量と質をこなすことが大事 まずは入門書 文法を押さえる CodeGolf / どう書く.org 練習問題として書いてみる
他人のコードを読んでみる リファレンスマニュアルとの格闘

140 プログラミング Ruby これが定番っぽい? あんまり良書を知らない 書いて覚えた

141 Rubyist Magazine 出張版 正しいRubyコードの書き方講座
Web でも読めます Rubyist Magazine でググる ただ、平易ではない

142 まとめ

143 まとめ オブジェクト と メッセージング 式 と 評価 ブロック

144 ご静聴 ありがとう ございました

145 Enumerable

146 配列をチェックする/要素を探す A チェック B

147 配列 : max / min - 最大最小 1 3 2 max 3

148 配列 : find / detect find do |s| s =~ /py/ end py を含む 文字列を探す “ruby”
“python” “perl” “python” py を含む 文字列を探す

149 配列 : any? / all? - チェック all? do |s| s =~ /^p/ end 全部 p から 始まってるか?
“ruby” all? do |s| s =~ /^p/ end false “perl” “python” 全部 p から 始まってるか?

150 配列 : sort - 並び替え 3 1 2 sort 2 1 3

151 配列 : sort_by - 条件を指定する sort_by do |i| - i end0 条件を指定して ソートする 1 3 2 2 3

152 配列 : select / find_all - 抜粋
1 1 select do |i| i % 2 == 1 end 2 3 3 奇数を全て取り出す

153 Array

154 配列 : データの追加 a.push n a << n a.insert 1, 3 insert push unshift
2 insert n-2 n-1 push unshift 3 n a.unshift 1

155 配列 : unshift - 先頭に追加 1 2 3 n-2 n-1 n unshift a.unshift 1

156 配列 : insert - 任意の場所に追加 a.insert 2, 3 1 2 n-2 n-1 n insert 3

157 配列 : 範囲外に代入したら? a = [ 1, 2, 3 ] a[3] = 4 1 2 3

158 配列 : 範囲外に代入したら? a = [ 1, 2, 3 ] a[3] = 4 配列の大きさは 勝手に拡張 1 2 3 4

159 配列 : データの削除 pop a.pop 1 2 3 n-2 n-1 n shift a.shift

160 配列 : pop - 末尾から削除 pop a.pop 1 2 3 n-2 n-1 n

161 配列 : shift - 末尾から削除 1 2 3 n-2 n-1 n shift a.shift

162 配列 : delete - ものを指定して削除 1 2 "foo" n-2 n-1 n delete a.delete "foo"

163 ホワイの(感動的)Rubyガイド 僕にはソリが合いませんでした
e_to_ruby/


Download ppt "2007/12/12 ema."

Similar presentations


Ads by Google