Download presentation
Presentation is loading. Please wait.
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/
Similar presentations
© 2024 slidesplayer.net Inc.
All rights reserved.