04-1 31204
プログラミング
3605 井上 寛晶 3531 松井 佑樹 3635 宮地 翼 要旨 各自でフリーソフトを作成、インターネット上に公開することを目的とし、 Visual Basic2008、2010 を使い、二年生までは「ちんちろりん」という簡単なゲームを作ったが、今回はより難度が高い「オセ ロ」の作成に成功した。 本文 1. 目的 情報化が進んだ現代において、社会に出ていくためにはパソコンの一つや二つ、軽く扱えなけれ ばならない。さらに、資源の乏しい日本においては今後、情報技術の発展することが望ましいと考 える。私たちのグループでは、SE(システムエンジニア)等の職に就き、今後の日本のみならず情 報技術によって世界に貢献できる人材となるべく、プログラミング技術の習得を目的とした。 また、今回はIA(人工知能)が必要となる対戦型オセロゲームを作成することを目的とし、より 高度なプログラミング技術の取得を目的とした。 2. 使用した器具・装置など (1)使用言語 Visual Basic(2)開発ソフト Microsoft Visual Studio 2008 Microsoft Visual Studio 2010 使用マシン FMV K5290 Intel LB-D701S 3. 研究・実験の手順 一年生から積み上げてきたVisual Basic の知識を生かし、以下のソフトを開発 ・対戦型オセロゲーム 4. 結果 ◎プログラムの説明
Cell,txt のプログラム
Public Class cell04-2 Public Grid As ReverseGrid
Public Position As Point '論理位置 Public Rectangle As Rectangle '物理位置 ↑ Status; 黒、白、なしの状態 Grid;オセロの盤面 Position;盤面内の説明 Rectangle;描画を行う四角形の領域 '■コンストラクタ ''' <summary>論理位置を指定してセルを作成します。</summary> ''' <param name="Grid">セルが属するグリッドを指定します。</param> ''' <param name="Position">セルの論理位置を指定します。</param> Public Sub New(ByVal Grid As ReverseGrid, ByVal Position As Point) Me.Grid = Grid
Me.Position = Position Dim Rect As New Rectangle
'論理位置から物理位置を求めます。
Rect.X = Position.X * ReverseGrid.CellSize Rect.Y = Position.Y * ReverseGrid.CellSize Rect.Width = ReverseGrid.CellSize
Rect.Height = ReverseGrid.CellSize Me.Rectangle = Rect
End Sub
Dim FrontBrush As New SolidBrush(Color.Black) Dim BackBrush As New SolidBrush(Color.White) '■Draw
''' <summary>現在の状態を描画します。</summary>
''' <param name="g">描画対象の Graphics オブジェクトを指定します。</param> Public Sub Draw(ByVal g As Graphics)
Dim CellRect As Rectangle '描画領域 ↑
04-3 '▼描画領域の算定 'セルいっぱいに描画するとぎちぎちになるので範囲を-2 する。 CellRect = Me.Rectangle CellRect.Inflate(-2, -2) '▼描画状態の設定
Select Case Me.Status Case CellStatus.Black FrontBrush.Color = Color.Black '表を黒に設定 BackBrush.Color = Color.White '裏を白に設定 Case CellStatus.White FrontBrush.Color = Color.White '表を白に設定 BackBrush.Color = Color.Black '裏を黒に設定 End Select ↑黒の石は表を黒、裏を白に、 白の石は表を白、裏を黒に設定する '▼描画実行
If Me.Status <> CellStatus.Nothing Then '裏面描画 CellRect.Y += 2 '裏と表をちょっとずらして立体的に見せる g.FillEllipse(BackBrush, CellRect) '表面描画 CellRect.Y -= 2 g.FillEllipse(FrontBrush, CellRect) End If ↑石の状態が有色(石が置かれている)であれば、石の表、裏を描画する。この時、裏表を若干ずらし て立体的に見せる。 '▼アクティブな場合は枠を描画する If Me.Focused Then g.DrawRectangle(Pens.Orange, CellRect) End If ↑下記の赤色の変更を適応するコード
04-4 End Sub
Public Focused As Boolean '■Focus
''' <summary>セルをアクティブにします。</summary>
''' <remarks>アクティブなセルとは Focused プロパティが True のセルです。
''' このメソッドを呼び出すと同じ盤に属するその他のセルのFocused プロパティを False にします。 ''' アクティブであることにそれ以上の効果はありませんが、
''' 描画の際に Focused プロパティが True のセルに枠線を描画します。 ''' </remarks>
Public Sub Focus() Dim X As Integer Dim Y As Integer
'同じグリッドに属する自分以外のセルを非アクティブにする。 For X = 0 To ReverseGrid.XCount - 1
For Y = 0 To ReverseGrid.YCount - 1 Grid.Cells(X, Y).Focused = False Next Next '自分自身をアクティブにする。 Me.Focused = True End Sub ↑マスの上にマウスを置いたときに枠線を表示する(Form1 の MouseMove イベントと対応) *こちらではマウスが来たときに枠を描く準備を行う。⇒実際に描画しているのはPaint イベントの Draw イベント(上の青色の部分)
04-5
computer3 のプログラム
Public Class Computer3 Dim Grid As ReverseGrid Public Standard As CellStatus
ReverseGrid;オセロの盤面を表し、石を置く、ひっくり返すことや、それに関するイベント、セルの管 理、描画処理を行う。
Cellstatus;石のもと(白、黒、なし、の三つの状態を表す) Grid はオセロの盤面、Standard は黒、白、なしの三色と宣言
Public Sub New(ByVal Grid As ReverseGrid, ByVal Standard As CellStatus) Me.Grid = Grid
Me.Standard = Standard End Sub
Public Sub Put()
↑コンピュータに石を置かせる Dim X As Integer Dim Y As Integer
Dim PlayerColor As CellStatus '角に置けるなら角におく
If Grid.CanPut(Standard, 0, 0) Then Grid.Put(Standard, 0, 0)
Return End If
If Grid.CanPut(Standard, 0, ReverseGrid.YCount - 1) Then Grid.Put(Standard, 0, ReverseGrid.YCount - 1)
Return End If
If Grid.CanPut(Standard, ReverseGrid.XCount - 1, 0) Then Grid.Put(Standard, ReverseGrid.XCount - 1, 0)
Return End If
04-6
If Grid.CanPut(Standard, ReverseGrid.XCount - 1, ReverseGrid.YCount - 1) Then Grid.Put(Standard, ReverseGrid.XCount - 1, ReverseGrid.YCount - 1)
Return End If
↑右上、右下、左上、左下に置くことが可能な時はその置けるところに石を置かせる なお、角を図1のように定義している
図1
If Standard = CellStatus.Black Then PlayerColor = CellStatus.White Else PlayerColor = CellStatus.Black End If ↑コンピュータの使う色が黒ならプレイヤーの石の色は白、それ以外(白)なら、プレイヤーの石は黒。 '順番に見ていってはじめに置けるところを探す
Dim ImageGrid As ReverseGrid Dim Puts As New ArrayList
↑ImageGrid はオセロの盤面、Puts は新しいコレクションと宣言 For Y = 0 To ReverseGrid.YCount - 1
For X = 0 To ReverseGrid.XCount - 1
If Grid.CanPut(Standard, X, Y) Then
Puts.Add(New Point(X, Y))
04-7
'▼まず、コピーのグリッドに石を置いてみる ImageGrid = Grid.Copy
ImageGrid.Put(Standard, X, Y)
'この状態で相手に角を取られる可能性があるか検証する Select Case True
Case ImageGrid.CanPut(PlayerColor, 0, 0) '左上の角を取られてしまうので何もしない
Case ImageGrid.CanPut(PlayerColor, 0, ReverseGrid.YCount - 1) '左下の角を取られてしまうので何もしない
Case ImageGrid.CanPut(PlayerColor, ReverseGrid.XCount - 1, 0) '右上の角を取られてしまうので何もしない
Case ImageGrid.CanPut(PlayerColor, ReverseGrid.XCount - 1, ReverseGrid.YCount - 1) '右下の角を取られてしまうので何もしない Case Else '角を取られる心配がないのでこの位置に石を置く Grid.Put(Standard, X, Y) Return End Select End If Next Next '角を取られる位置にしか置けない場合、仕方ないので置く Dim Pos As Point = DirectCast(Puts(0), Point)
Grid.Put(Standard, Pos.X, Pos.Y)
End Sub
End Class
↑置く場所を考える場合、コピーの盤面をAI が考え、それぞれの角を取られる場合を考える。⇒それ
04-8
Constant のプログラム
'■CellStatus
''' <summary>セルの状態を表します。</summary> Public Enum CellStatus
[Nothing] 'なし Black '黒 White '白 End Enum '■ScanDirection ''' <summary>方向を表します。</summary> Public Enum ScanDirection
Left Right Up Down LeftUp LeftDown RightUp RightDown End Enum
form1 のプログラム
Public Class Form1Dim WithEvents Grid As New ReverseGrid
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Grid.Initialize() lblBlackCount.Text = Grid.Count(CellStatus.Black) lblWhiteCount.Text = Grid.Count(CellStatus.White) lblWhiteTurn.Visible = False ↑ゲーム開始時に現在のターンをラベルを使って表示
04-9 End Sub
Private Sub PictureBox1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles PictureBox1.Click
'マウスの座標を PictureBox1 のコントロール座標に変換する。
Dim Pos As Point = PictureBox1.PointToClient(Windows.Forms.Cursor.Position)
↑マウスで表される座標(PC 上の画面での座標)を盤面上のマスの座標に変換 Dim ThisCell As cell
ThisCell = Grid.CellFromPoint(Pos.X, Pos.Y)
If Grid.Put(Turn, ThisCell.Position.X, ThisCell.Position.Y) Then ChangeTurn() End If ↑石を置いたときにターンを交代させる。また、ReverseGrid の Canput で設定した置けるマスのみに 石を置けるようにする。 End Sub ''' <summary>マウスの移動に伴ってセルにアクティブを示す枠を描画する</summary> Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As
System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
Dim ThisCell As cell
'マウスがある位置のセルを取得
ThisCell = Grid.CellFromPoint(e.X, e.Y)
If Not IsNothing(ThisCell) Then
'セルが取得できた場合は、セルにアクティブを示す枠を描画 ThisCell.Focus() '現在の状態を描画(PictureBox1 の Paint イベントを発生させる) PictureBox1.Invalidate() '←実際の描画はすべてここで行う End If ↑Cell の Focus と対応(こっちでは、マウスがある位置等を取得)
04-10 End Sub
Dim Turn As CellStatus = CellStatus.Black '今どっちの順番か Dim PlayerColor As CellStatus = CellStatus.Black 'プレイヤーの色 '■ChangeTurn
''' <summary>ターン交代</summary> Public Sub ChangeTurn()
'現在の状態を描画(PictureBox1 の Paint イベントを発生させる) PictureBox1.Invalidate() ↑paint イベントを強制的に発生させる ▼勝敗判定 ①すべてのマスに石が置かれる ②マスはまだ空いているが石を置けない状況 ③すべての色が同じ色になる ① If Grid.Count(CellStatus.Nothing) = 0 Then 石の置けるマスが0になり '全セルへの配置が終了した場合は勝敗判定して終了
If Grid.Count(CellStatus.Black) > Grid.Count(CellStatus.White) Then←黒のほうが多 かったら
MsgBox("黒の勝ちです!")
ElseIf Grid.Count(CellStatus.Black) < Grid.Count(CellStatus.White) Then←白のほう が多かったら MsgBox("白の勝ちです!") Else MsgBox("引き分けです!!") End If ↑マスすべてに石が置かれ、どちらの石の数が多いか調べた後、それぞれのメッセージを表示 Return
ElseIf Grid.PuttableCount(CellStatus.Black) = 0 AndAlso Grid.PuttableCount(CellStatus.White) = 0 Then
② '空いているセルがあるのに黒も白も置けない場合
If Grid.Count(CellStatus.Black) > Grid.Count(CellStatus.White) Then MsgBox("黒の勝ちです!")
ElseIf Grid.Count(CellStatus.Black) < Grid.Count(CellStatus.White) Then MsgBox("白の勝ちです!")
Else
MsgBox("引き分けです!!") End If
04-11
↑石を置くことのできるマスがなくなり、どちらが多いかを調べた後、それぞれのメッセージを表示 ElseIf Grid.Count(CellStatus.Black) = 0 Then
③ 'すべての石が白になった場合(=黒の石が 0 個の場合) MsgBox("白の勝ちです!")
Return
ElseIf Grid.Count(CellStatus.White) = 0 Then
'すべての石が黒になった場合(=白の石が 0 個の場合) MsgBox("黒の勝ちです!") Return End If ↑石すべてが白または黒になったらそれぞれのメッセージを表示 '▼次のターンの決定
If Turn = CellStatus.Black Then Turn = CellStatus.White lblBlackTurn.Visible = False lblWhiteTurn.Visible = True Else Turn = CellStatus.Black lblBlackTurn.Visible = True lblWhiteTurn.Visible = False End If ↑石が黒のターンなら次は白に、白なら次は黒に⇒ターンの交代を処理 また、黒のターン、白のターンであることを示す線を表示させる '▼置ける場所があるか判定 If Grid.PuttableCount(Turn) = 0 Then '置く場所がなければパスして次のターン ChangeTurn() End If '▼人間かコンピュータかで処理を分岐 If Turn = PlayerColor Then
'人間の番ならば、PictureBox を使用可能にする。 PictureBox1.Enabled = True Else ↑プレイヤーの番は盤面の操作を可能にし、コンピュータの番のときは盤面の操作を不可能にする。 'コンピュータの番ならば、PictureBox を使用不可にする。 PictureBox1.Enabled = False
04-12 'ちょっと時間をおく Application.DoEvents() System.Threading.Thread.Sleep(500) ↑0.5秒の間を空ける 'コンピュータに石を置かせる。どのセルに置くかはコンピュータ(AI)が決定する。 Computer.Put() ChangeTurn() 'プレイヤーの番へ End If ↑コンピュータが石を置きターンを交代する End Sub
Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint Grid.Draw(e.Graphics)
End Sub
''' <summary>石を置いたときに発生するイベント</summary>
Private Sub Grid_PutNew(ByVal sender As Object, ByVal e As System.EventArgs) Handles Grid.PutNew
Call Grid_Reversed(sender, e) End Sub
''' <summary>石がひっくり返されたときに発生するイベント</summary>
Private Sub Grid_Reversed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Grid.Reversed
'現在の状態を描画(PictureBox1 の Paint イベントを発生させる) PictureBox1.Invalidate()
04-13 lblBlackCount.Text = Grid.Count(CellStatus.Black) lblWhiteCount.Text = Grid.Count(CellStatus.White) ↑黒石、白石の数をラベルに表示し、paint イベントを発生させ、描画を行う。 'ちょっと時間をおく Application.DoEvents() System.Threading.Thread.Sleep(500) ↑石をひっくり返す動作をする際に、毎回0.5 秒の間を空ける⇒瞬時に変わるとゲーム性が損なわれ る! End Sub '■Start ''' <summary>ゲームを開始します。</summary> ''' <param name="PlayerColor">人間の石の色を指定します。</param> ''' <remarks>黒が先手になります。</remarks>
Private Sub Start(ByVal PlayerColor As CellStatus) Grid.Initialize()
Me.PlayerColor = PlayerColor '人間の色 If PlayerColor = CellStatus.Black Then
Computer.Standard = CellStatus.White 'コンピュータの色は白 Else Computer.Standard = CellStatus.Black 'コンピュータの色は黒 End If ↑プレイヤー、コンピュータの色を設定。 '現在の黒と白の駒の数を表示する lblBlackCount.Text = Grid.Count(CellStatus.Black) lblWhiteCount.Text = Grid.Count(CellStatus.White) ↑ラベルに黒石、白石の数を表示 'ChangeTurn を呼び出して黒の番を開始する。そのために仮に今は白の番であることにする。 Turn = CellStatus.White ChangeTurn() End Sub
Private Sub btnStartBlack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartBlack.Click
04-14
Start(CellStatus.Black)
End Sub
Private Sub btnStartWhite_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStartWhite.Click
Start(CellStatus.White) End Sub ↑黒、白で始まるかを選択するボタンの処理 5. 結果に対する考察・わかったこと、感想 人工知能というと、難しいイメージがあったが一つ一つ見ていくと角に置けるかを確認するプログ ラム、右上から左下まで置けるところを探すプログラム、実際に仮の盤面に置くプログラム、相手 に角を取られないことを確認するプログラム、実際に置くプログラムと、単純なことの積み重ねだ ったので、理解できた。この経験を生かして今後もプログラムの道に精進したい。 6. 参考文献、引用文献 http://homepage1.nifty.com/rucio/main/main.htm