MENU

【VB】ペントミノ2Dパズルを解く(5)ボードクラスを作る

いよいよボードクラスです。マス目の空いている場所に部品が置けるかどうかを判定したり、配置データをこのクラスで管理します。

・クラス宣言

クラスの名前は "Board" です。

Public Class Board

・プロパティ:Width, Height

ボードの幅と縦。初期化時に設定します。

ReadOnly Property Width As Integer      'X軸方向
ReadOnly Property Height As Integer     'Y軸方向

・プロパティ:Cells( , )

※ 外からは2次元のように見えますが実体は1次元です

ボードのマス目(値は Boolean)です。エクセルVBAのCellsとは縦横が逆です。サイズは動的に確保します。

   Private _Cells As Boolean()    'セル実体:1次元配列
   Property Cells(x As Integer, y As Integer) As Boolean
      Get
         Return _Cells(x + y * Width)
      End Get
      Set(value As Boolean)
         _Cells(x + y * Width) = value
      End Set
   End Property

・プロパティ:解判定関係

解の判定に使用するプロパティです。PlacedPieceCountが部品の種類(=12)に等しくなったときが正解です。PlacedFirstPieceは最初に置いた部品でプログレスバーの表示計算に使います。

Property PlacedPieceCount As Integer = 0
Property PlacedFirstPiece As Piece = Nothing

・初期化

引数にボードの横と縦のサイズを指定します。

Sub New(width As Integer, height As Integer)
   _Width = width
   _Height = height
   ReDim _Cells(width * height - 1)
   PlacedPieceCount = 0
   PlacedFirstPiece = Nothing
End Sub

・関数 onBoard

指定した座標がボード上にあるかどうかを判定します(ボード上にあれば True)。

Public Function onBoard(x As Integer, y As Integer) As Boolean
   If x >= 0 AndAlso x <= Width - 1 AndAlso
      y >= 0 AndAlso y <= Height - 1 Then
      Return True
   Else
      Return False
   End If
End Function

・関数:nextBlankCell

指定した座標から空(False)セルを検索して、空セルがあればその座標を返します。検索方向は下で、下端まで到達すると右上へ移ります。空セルがなければ Nothing を返します。

Public Function nextBlankCell(c As Coord) As Coord
   Dim x = c.X
   Dim y = c.Y
   Do Until Cells(x, y) = False
      Select Case True
         Case y < Height - 1
            y += 1
         Case x < Width - 1
            x += 1
            y = 0
         Case Else
            Return Nothing
      End Select
   Loop
   Return New Coord(x, y)
End Function

・関数:canPlace

ボードの指定した位置に部品が置けるかどうかを返します(部品を置くことができれば True)。部品の5個の座標に対応するセルがすべて空であれば True、1つでもセルが埋まっていれば False を返します。

Public Function canPlace(piece As Piece, c As Coord) As Boolean
   For Each p In piece.Coords
      Dim x = c.X + p.X
      Dim y = c.Y + p.Y
      If onBoard(x, y) = False OrElse Cells(x, y) = True Then
         Return False
      End If
   Next
   Return True
End Function

・メソッド:placePiece

ボードの指定した位置に部品を置きます

Public Sub placePiece(shelf As Shelf)
   With shelf.PlacedCoord
      For Each p In shelf.PlacedPiece.Coords
         Cells(.X + p.X, .Y + p.Y) = True
      Next
   End With
   PlacedPieceCount += 1          '解判定のためのカウンターを増加
   If PlacedPieceCount = 1 Then
      PlacedFirstPiece = shelf.PlacedPiece    'プログレスバー表示用
   End If
End Sub

・メソッド:removePiece

ボードの指定した位置の部品を取り除きます

Public Sub removePiece(shelf As Shelf)
   With shelf.PlacedCoord
      For Each p In shelf.PlacedPiece.Coords
         Cells(.X + p.X, .Y + p.Y) = False
      Next
   End With
   PlacedPieceCount -= 1
End Sub


以上が「ボードクラス」です。クラス全体のソースは以下のとおりです。

Public Class Board
   '**********************************************
   '*         Board  (ボードクラス:盤面) 
   '**********************************************
   ReadOnly Property Width As Integer      'X軸方向
   ReadOnly Property Height As Integer     'Y軸方向

   Private _Cells As Boolean()    'セル実体:1次元配列
   Property Cells(x As Integer, y As Integer) As Boolean
      Get
         Return _Cells(x + y * Width)
      End Get
      Set(value As Boolean)
         _Cells(x + y * Width) = value
      End Set
   End Property

   Property PlacedPieceCount As Integer = 0
   Property PlacedFirstPiece As Piece = Nothing

   '** 初期化
   Sub New(width As Integer, height As Integer)
      _Width = width
      _Height = height
      ReDim _Cells(width * height - 1)
      PlacedPieceCount = 0
      PlacedFirstPiece = Nothing
   End Sub

   '** onBoard
   Public Function onBoard(x As Integer, y As Integer) As Boolean
      If x >= 0 AndAlso x <= Width - 1 AndAlso
         y >= 0 AndAlso y <= Height - 1 Then
         Return True
      Else
         Return False
      End If
   End Function

   '** nextBlankCell(Y軸→X軸の順に検索)
   Public Function nextBlankCell(c As Coord) As Coord
      Dim x = c.X
      Dim y = c.Y
      Do Until Cells(x, y) = False
         Select Case True
            Case y < Height - 1
               y += 1
            Case x < Width - 1
               x += 1
               y = 0
            Case Else
               Return Nothing
         End Select
      Loop
      Return New Coord(x, y)
   End Function

   '** canPlace
   Public Function canPlace(piece As Piece, c As Coord) As Boolean
      For Each p In piece.Coords
         Dim x = c.X + p.X
         Dim y = c.Y + p.Y
         If onBoard(x, y) = False OrElse Cells(x, y) = True Then
            Return False
         End If
      Next
      Return True
   End Function

   '** placePiece
   Public Sub placePiece(shelf As Shelf)
      With shelf.PlacedCoord
         For Each p In shelf.PlacedPiece.Coords
            Cells(.X + p.X, .Y + p.Y) = True
         Next
      End With
      PlacedPieceCount += 1          '解判定のためのカウンターを増加
      If PlacedPieceCount = 1 Then
         PlacedFirstPiece = shelf.PlacedPiece    'プログレスバー表示用
      End If
   End Sub

   '** removePiece
   Public Sub removePiece(shelf As Shelf)
      With shelf.PlacedCoord
         For Each p In shelf.PlacedPiece.Coords
            Cells(.X + p.X, .Y + p.Y) = False
         Next
      End With
      PlacedPieceCount -= 1
   End Sub

End Class

以上でプログラムで使用する4つのクラス(Coord, Piece, Shelf, Board)が揃いました。次回は準備作業の最後として「DEFクラス」を作成します。このクラスはプログラムの表紙(鑑)です。プログラム諸元や共有で使用する定数や関数などをまとめて記述しておくクラスです。