Справочник Жаркова по проектированию и программированию искусственного интеллекта. Том 6: Программирование на Visual Basic искусственного интеллекта. Продолжение 2

Text
0
Kritiken
Leseprobe
Als gelesen kennzeichnen
Wie Sie das Buch nach dem Kauf lesen
Schriftart:Kleiner AaGrößer Aa

20.3. Создание проекта

Создаём проект по обычной схеме: в VS в панели New Project в окне Project types выбираем тип проекта Visual Basic, Windows, в окне Templates выделяем шаблон Windows Forms Application, в окне Name записываем имя проекта Game и щёлкаем OK. Создаётся проект, появляется форма Form1 в режиме проектирования (рис. 20.7). Оставляем по умолчанию или проектируем форму, как подробно описано в параграфе “Методика проектирования формы”. За маркер увеличиваем размеры формы таким образом, чтобы в панели Properties (для Form1) в свойстве Size были значения, например, 519; 464. Белый цвет фона формы мы установим далее в программе (в строке Me.BackColor = Color.White).

Для задания режимов и управления игрой воспользуемся каким-либо элементом управления или компонентом. Как и выше, с панели инструментов Toolbox переносим на форму элемент управления MenuStrip и щёлкаем по нему (ниже формы в режиме проектирования). На форме Form1 появляются окна с надписью Type Here (Печатайте здесь), в которые записываем команды, слева: Game (Игра), New Game (Новая игра), Pause (Пауза), Restart (Перезапуск), Options (Результаты), Exit (Выход), рис. 20.9, справа: Help (Помощь), Contents (Содержание), Index (Указатель), Search (Поиск), About this game (Об этой игре), рис. 20.10.




Рис. 20.7. Форма Form1 в режиме проектирования. Рис. 20.8. SE и Properties.





Рис. 20.9. Команды меню Game. Рис. 20.10. Команды меню Help.

В панели Properties в свойстве Text в имени каждой команды меню MenuStrip перед соответствующей буквой записываем оператор &, после чего на форме эта буква станет подчёркнутой. Напомним, что в режиме выполнения, после нажатия клавиши Alt вместе с клавишей с подчёркнутой буквой (английского алфавита) в команде меню Game или Help, выполняется соответствующая команда.

С панели инструментов Toolbox размещаем на форме основной графический элемент управления PictureBox для поля игры. За маркеры увеличиваем размеры поля, чтобы в панели Properties в свойстве Size были значения 300; 375, а в свойстве BackColor вместо заданного по умолчанию серого цвета Control выбираем белый цвет Window.

Размещаем на форме панель Panel, за её маркеры увеличиваем размеры Size до значений 175; 96.

На этой панели Panel размещаем 5 элементов управления PictureBox с размерами Size (24; 67). В панели Properties в свойстве BackColor для всех этих элементов выбираем белый цвет Window, а в свойстве Name изменяем имена этих 5 элементов на следующие (справа налево):

ones – единицы,

tens – десятки,

hundreds – сотни,

thousands – тысячи,

tenthousands – десятки тысяч.

Ниже на форме размещаем элемент управления PictureBox с заданными по умолчанию размерами Size (100; 50). Чтобы на этом элементе разместить рисунок, в панели Properties щёлкаем свойство Image, в появившейся панели Select Resource выбираем переключатель Local resource и щёлкаем кнопку Imports (рис. 20.11). В панели Open находим (например, в папке с загруженными из Интернета файлами) графический файл new.bmp (рис. 20.12) и щёлкаем кнопку Open, после чего этот рисунок мы увидим в панели Select Resource, на которой щёлкаем OK. Окончательно, этот рисунок new.bmp разместится в панели Properties в свойстве Image и на форме на поле данного элемента PictureBox.

Аналогично ниже размещаем на форме ещё один элемент управления PictureBox с заданными по умолчанию размерами Size (100; 50), на который добавляем рисунок exit.bmp.

Рис. 20.11. В панели Select Resource щёлкаем Imports. Рис. 20.12. В панели Open находим файл.

Аналогично ниже размещаем на форме ещё один элемент управления PictureBox, увеличиваем его размеры Size до 128; 50 и добавляем на него рисунок option.bmp.

С панели инструментов Toolbox переносим на форму компонент типа списка рисунков ImageList, который, как компонент, размещается ниже формы. В панели Properties в свойстве Name изменяем его имя на numbers (цифры для подсчёта очков), а в свойстве ImageSize увеличиваем цифры до размеров 26; 67. Чтобы этот компонент заполнить цифрами для подсчёта очков, в панели Properties щёлкаем свойство Images, в появившейся панели Images Collection Editor щёлкаем кнопку Add (рис. 20.13). В приведённой выше панели Open находим (например, в папке с загруженными из Интернета файлами) графический файл 0.bmp и щёлкаем кнопку Open, после чего этот рисунок мы увидим в панели Images Collection Editor. Аналогично в список рисунков ImageList добавляем остальные цифры 1, 2, 3, …, 9.

Чтобы программа периодически через Interval времени дополняла поле игры новыми разноцветными кругами (взамен выбитых игроком кругов), с панели инструментов Toolbox переносим на форму (точнее, ниже формы) первый таймер Timer1. В панели Properties (для этого таймера) в свойстве Enabled оставляем заданное по умолчанию значение False, т.к. мы включим этот таймер в программе в нужном месте при помощи строки (Timer1.Enabled = True). А в свойстве Interval вместо заданных по умолчанию 100 миллисекунд задаём, например, значение 7000 миллисекунд (равное 7 секундам).

Чтобы в верхней части формы (на синей полоске для свойства Text) после начала игры шел отсчёт времени (Time), на форму переносим второй таймер Timer2. В панели Properties (для этого второго таймера) в свойстве Enabled изменяем заданное по умолчанию значение False на True (включаем таймер), в свойстве Interval вместо заданных по умолчанию 100 миллисекунд задаём значение 1000 (равное 1 секунде), чтобы шел посекундный отсчёт времени.

Если в игре применяются звуковые файлы, то их целесообразно разместить в одной папке с именем, например, Resources. Для добавления в проект этой папки, в панели Solution Explorer выполняем правый щелчок по имени проекта, в контекстном меню выбираем Add, New Folder, в поле появившегося значка папки записываем имя папки и нажимаем клавишу Enter.

Добавляем в эту папку первый звуковой файл Windows XP Balloon.wav по стандартной схеме: выполняем правый щелчок по имени этой папки, в контекстном меню выбираем Add, Existing Item, в панели Add Existing Item в окне “Files of type” выбираем “All Files”, в центральном окне находим (например, в папке с загруженными из Интернета файлами) и выделяем имя файла и щёлкаем кнопку Add (или дважды щёлкаем по имени файла). В панели Solution Explorer мы увидим этот файл.

Аналогично добавляем в проект второй файл win.wav.

Напомним, что добавлять в проект указанные выше файлы можно как по одному, так и все сразу (после их выделения или только одной мышью, или мышью с нажатой клавишей Shift – для выделения всех соседних файлов, или мышью с нажатой клавишей Ctrl – для выделения всех файлов в различных местах).



Рис. 20.13. В панели Images Collection Editor щёлкаем кнопки Add и OK.

Для ввода в проект новой формы (для таблицы с результатами игры) в меню Project выбираем Add Windows Form, в панели Add New Item оставляем заданные по умолчанию параметры и щёлкаем кнопку Add. В ответ VS выводит новую форму Form2 и добавляет в панель Solution Explorer новый пункт Form2.vb. Аналогично, как первую, проектируем вторую форму (рис. 20.14), за маркеры увеличиваем форму до размеров Size (436; 223) и вводим на форму элементы управления: сетку DataGridView с размерами Size (288; 104), кнопку Button с заголовком Reset (в свойстве Text) и флажок CheckBox, для которого в свойстве Name записываем имя isSoundOn, а в свойстве Checked выбираем значение True (устанавливаем флажок). Свойства этих элементов управления можно стандартно изменять, как описано ранее.



Рис. 20.14. Форма Form2 для таблицы с результатами игры.

20.4. Код программы


Открываем файл Form1.vb (например, по схеме: File, Open, File) и в классе Form1 нашего проекта записываем следующие переменные и методы.

Листинг 20.1. Переменные и методы.

Dim matrix As Grid

Dim score As Integer = 0

Dim mouseOffset As Point

Dim paused As Boolean = False

Dim isSoundOn As Boolean = True

Private Sub BlockClick(ByVal sender As Object, _

ByVal e As System.Windows.Forms.MouseEventArgs)

' Play the sound.

If isSoundOn Then

'Исправляем ошибку в оригинале:

My.Computer.Audio.Play( _

"..\..\Resources\Windows XP Balloon.wav", _

AudioPlayMode.WaitToComplete) 'Ждем окончания мелодии.

End If

' Update the matrix and compute the new score.

Dim count As Integer = matrix.Click(New Point(e.X, e.Y))

score += 10 * count

' Draw the new grid.

matrix.Draw(Me.PictureBox1.CreateGraphics(), _

Me.PictureBox1.BackColor)

' Write the score on the screen.

Dim images() As PictureBox = { _

Me.tenthousands, Me.thousands, _

Me.hundreds, Me.tens, Me.ones}

Dim scoreString As String = score.ToString().PadLeft(5)

Dim digits() As String = { _

scoreString.Chars(0), _

scoreString.Chars(1), _

scoreString.Chars(2), _

scoreString.Chars(3), _

scoreString.Chars(4)}

For index As Integer = 0 To 4

If digits(index) <> " " Then

images(index).Image = _

numbers.Images(CInt(digits(index)))

 

Else

images(index).Image = Nothing

End If

Next

End Sub

Private Sub StartNewGame()

' If a game is already running, check for a new high score.

If Not matrix Is Nothing Then

Me.Timer1.Enabled = False

HighScores.UpdateScores(score)

End If

Timer1.Enabled = False

matrix = New Grid(6)

score = 0

matrix.Draw(Me.PictureBox1.CreateGraphics(), _

Me.PictureBox1.BackColor)

Timer1.Enabled = True

AddHandler PictureBox1.MouseDown, AddressOf BlockClick

'Обнуляем счётчик секунд:

secondCounter = 0

End Sub

' To pause the game, turn off the timer.

Private Sub Pause()

Timer1.Enabled = False

Me.PauseToolStripMenuItem.Visible = False

Me.RestartToolStripMenuItem.Visible = True

RemoveHandler PictureBox1.MouseDown, AddressOf BlockClick

paused = True

End Sub

Private Sub ShowOptions()

'Dim optionsForm As New Options

Dim optionsForm As New Form2

optionsForm.SoundOn = isSoundOn

optionsForm.ShowDialog()

isSoundOn = optionsForm.SoundOn

optionsForm.Dispose()

End Sub

Private Sub Restart()

Timer1.Enabled = True

Me.PauseToolStripMenuItem.Visible = True

Me.RestartToolStripMenuItem.Visible = False

AddHandler PictureBox1.MouseDown, AddressOf BlockClick

paused = False

End Sub

Private Sub EndGame()

' Get top scores so far.

Me.Timer1.Enabled = False

HighScores.UpdateScores(score)

Me.Close()

End Sub

В панели Properties (для Form1) на вкладке Events дважды щёлкаем по имени события Load (Загрузка). Появившийся шаблон метода Form1_Load после записи нашего кода принимает следующий вид.

Листинг 20.2. Метод для загрузки объектов.

Private Sub Form1_Load(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

PointTranslator.Graphics = Me.PictureBox1.CreateGraphics()

Me.PictureBox1.Width = Block.BlockSize * 12

Me.PictureBox1.Height = Block.BlockSize * 15

HighScores.SetUpHighScores()

' Setup the background color and the starting score.

Me.BackColor = Color.White

Me.ones.Image = Me.numbers.Images(0)

Me.tens.Image = Me.numbers.Images(0)

Me.hundreds.Image = Me.numbers.Images(0)

Me.Menu = Nothing

End Sub

Дважды щёлкаем по команде New Game для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.3. Метод-обработчик выбора команды.

Private Sub NewGameToolStripMenuItem_Click( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles NewGameToolStripMenuItem.Click

StartNewGame()

End Sub

Дважды щёлкаем по команде Pause для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.4. Метод-обработчик выбора команды.

Private Sub PauseToolStripMenuItem_Click( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles PauseToolStripMenuItem.Click

Me.Pause()

End Sub

Дважды щёлкаем по команде Restart для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.5. Метод-обработчик выбора команды.

Private Sub RestartToolStripMenuItem_Click( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles RestartToolStripMenuItem.Click

Restart()

End Sub

Дважды щёлкаем по команде Options для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.6. Метод-обработчик выбора команды.

Private Sub OptionsToolStripMenuItem_Click( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles OptionsToolStripMenuItem.Click

Dim optionsForm As New Form2

optionsForm.ShowDialog()

End Sub

Дважды щёлкаем по команде Exit для элемента управления MenuStrip. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.7. Метод-обработчик выбора команды.

Private Sub ExitToolStripMenuItem_Click( _

ByVal sender As System.Object, ByVal e As System.EventArgs) _

Handles ExitToolStripMenuItem.Click

Me.EndGame()

End Sub

Дважды щёлкаем по элементу управления PictureBox с рисунком new.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.8. Метод-обработчик щелчка по элементу.

Private Sub newGame_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles newGame.Click

StartNewGame()

End Sub

Дважды щёлкаем по элементу управления PictureBox с рисунком exit.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.9. Метод-обработчик щелчка по элементу.

Private Sub exitGame_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles exitGame.Click

EndGame()

End Sub

Дважды щёлкаем по элементу управления PictureBox с рисунком options.bmp (или в панели Properties для этого элемента на вкладке Events дважды щёлкаем по имени события Click). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.10. Метод-обработчик щелчка по элементу.

Private Sub options_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles options.Click

ShowOptions()

End Sub

Для управления игрой мышью, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события MouseDown. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.11. Метод-обработчик нажатия кнопки мыши.

Private Sub Form1_MouseDown(ByVal sender As System.Object, _

ByVal e As System.Windows.Forms.MouseEventArgs) _

Handles MyBase.MouseDown

mouseOffset = New Point(-e.X, -e.Y)

End Sub

Для управления игрой мышью, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события MouseMove. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.12. Метод-обработчик перемещения мыши.

Private Sub Form1_MouseMove(ByVal sender As System.Object, _

ByVal e As System.Windows.Forms.MouseEventArgs) _

Handles MyBase.MouseMove

If e.Button = Windows.Forms.MouseButtons.Left Then

Dim mousePos As Point = Control.MousePosition

mousePos.Offset(mouseOffset.X, mouseOffset.Y)

Location = mousePos

End If

End Sub

Для управления игрой клавишами клавиатуры, в панели Properties (для формы Form1) на вкладке Events дважды щёлкаем по имени события KeyPress. Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.13. Метод-обработчик нажатия клавиши.

Private Sub Form1_KeyPress(ByVal sender As System.Object, _

ByVal e As System.Windows.Forms.KeyPressEventArgs) _

Handles MyBase.KeyPress

Select Case e.KeyChar

Case "p"c, "P"c

If paused Then

Restart()

Else

Pause()

End If

Case "m"c, "M"c

If Me.FormBorderStyle = _

Windows.Forms.FormBorderStyle.Fixed3D Then

Me.FormBorderStyle = _

Windows.Forms.FormBorderStyle.None

Me.Menu = Nothing

Else

Me.FormBorderStyle = _

Windows.Forms.FormBorderStyle.Fixed3D

'Me.Menu = Me.MainMenu1

End If

Case Else

' Do nothing.

End Select

End Sub

Чтобы программа периодически через Interval времени дополняла поле игры новыми разноцветными кругами (взамен выбитых игроком кругов), ниже формы дважды щёлкаем по значку для первого таймера Timer1 (или в панели Properties для этого компонента на вкладке Events дважды щёлкаем по имени события Tick). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.14. Метод, вызываемый через Interval времени.

Private Sub Timer1_Tick(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Timer1.Tick

' Add another row to the grid and update the screen.

matrix.AddRow()

matrix.Draw(Me.PictureBox1.CreateGraphics(), _

Me.PictureBox1.BackColor)

End Sub

Чтобы в верхней части формы (на синей полоске для свойства Text) после начала игры шел отсчёт времени (Time), ниже формы дважды щёлкаем по значку для второго таймера Timer2 (или в панели Properties для этого компонента на вкладке Events дважды щёлкаем по имени события Tick). Появляется шаблон метода, который после записи нашего кода принимает следующий вид.

Листинг 20.15. Метод, вызываемый через Interval времени.

'Счётчик секунд, который обнуляем в начале каждой игры

'в методе StartNewGame:

Dim secondCounter As Integer

'Время окончания игры:

Dim EndGameTime As Integer = 60

Private Sub Timer2_Tick(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles Timer2.Tick

secondCounter = secondCounter + 1

Me.Text = "Time : " & secondCounter.ToString()

'Мелодия окончания игры:

If secondCounter = EndGameTime Then

My.Computer.Audio.Play( _

"..\..\Resources\win.wav", _

AudioPlayMode.Background)

End If

End Sub

Схема записи и вывода справочной информации, например, с правилами игры после выбора команды Contents (для элемента управления MenuStrip) и после выбора других команд уже приводилась в наших предыдущих работах.

Мы закончили написание программы в главный класс Form1 (для формы Form1 с пользовательским интерфейсом игры).

Теперь в наш проект добавляем новые файлы (для программирования соответствующих игровых действий). Добавить в проект файл можно по двум вариантам.

По первому варианту, добавляем в проект нужный файл по обычной схеме: в панели Solution Explorer выполняем правый щелчок по имени проекта, в контекстном меню выбираем Add, Existing Item, в панели Add Existing Item в окне “Files of type” выбираем “All Files”, в центральном окне находим (например, в папке компьютера файл, скопированный из Интернета), выделяем имя этого файла и щёлкаем кнопку Add (или дважды щёлкаем по имени этого файла).

По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя Block.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.

Листинг 20.16. Новый файл.

Imports System.Drawing.Drawing2D

''' <summary>

''' This class represents one of the balls in the game grid.

''' </summary>

''' <remarks></remarks>

Public Class Block

Public Const BlockSize As Integer = 25

Private colorValue As Color

Private deletionValue As Boolean = False

Private Shared rand As New Random

Public Property Color() As Color

Get

Return colorValue

End Get

Set(ByVal Value As Color)

colorValue = Value

End Set

End Property

Public Property MarkedForDeletion() As Boolean

Get

Return deletionValue

End Get

Set(ByVal Value As Boolean)

deletionValue = Value

End Set

End Property

Public Sub New(ByVal newColor As Color)

colorValue = newColor

End Sub

Public Sub New(ByVal colors() As Color)

Dim ncolors As Integer = colors.Length

Dim pickedColor As Integer

pickedColor = rand.Next(0, ncolors)

colorValue = colors(pickedColor)

End Sub

Public Sub Draw(ByVal graphics As Graphics, ByVal point As Point)

Dim brush As System.Drawing.Drawing2D.LinearGradientBrush = _

CreateTheBrush(point)

DrawTheCircle(graphics, brush, point)

End Sub

Private Sub DrawTheCircle(ByVal graphics As Graphics, _

ByVal brush As LinearGradientBrush, ByVal location As Point)

Dim topleft As Point = location

 

Dim bottomright As Point = New Point(location.X + _

BlockSize, location.Y + BlockSize)

Dim transTopLeft As Point = PointTranslator.TranslateToBL( _

topleft)

Dim transBottomRight As Point = _

PointTranslator.TranslateToBL(bottomright)

Dim transwidth As Integer = transBottomRight.X – transTopLeft.X

Dim transheight As Integer = _

transBottomRight.Y – transTopLeft.Y

graphics.FillEllipse(brush, New Rectangle(transTopLeft, _

New Size(transwidth, transheight)))

End Sub

Private Function CreateTheBrush(ByVal location As Point) As _

LinearGradientBrush

Dim transLocation As Point = _

PointTranslator.TranslateToBL(location)

Dim brushpt1 As Point = transLocation

Dim brushpt2 As New Point(transLocation.X + Block.BlockSize _

+ 4, transLocation.Y – BlockSize – 4)

Dim brush As New LinearGradientBrush(brushpt1, _

brushpt2, Me.Color, System.Drawing.Color.White)

Return brush

End Function

End Class

По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя Grid.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.

Листинг 20.17. Новый файл.

''' <summary>

''' This class represents the grid of blocks. It handles most of

''' the game play.

''' </summary>

''' <remarks></remarks>

Public Class Grid

' The grids is 12 columns and 15 rows of Block objects.

Dim matrix(11, 14) As Block

''' <summary>

''' Creates a few rows of blocks to start the game.

''' Game starts with Red, Blue, and Green blocks.

''' </summary>

''' <param name="nrows">Number of rows of blocks to create

''' to start the game.</param>

''' <remarks></remarks>

Public Sub New(ByVal nrows As Integer)

If nrows > matrix.GetLength(0) Then

Throw New Exception("Must start with " & _

matrix.GetLength(0) & " or fewer rows.")

End If

Dim row As Integer

Dim column As Integer

For row = 0 To nrows – 1

For column = 0 To matrix.GetLength(1) – 1

matrix(row, column) = New Block( _

New Color() {Color.Red, Color.Blue, Color.Green})

Next

Next

For row = nrows To matrix.GetLength(0) – 1

For column = 0 To matrix.GetLength(1) – 1

matrix(row, column) = Nothing

Next

Next

End Sub

''' <summary>

''' A new row may be added at any time. New rows have Gray

''' blocks in addition

''' to Red, Blue, and Green. This makes the game more difficult.

''' </summary>

''' <remarks></remarks>

Public Sub AddRow()

Dim column As Integer

' Add a new block to each column.

For column = 0 To matrix.GetLength(1) – 1

Dim newBlock As New Block(New Color() _

{Color.Red, Color.Blue, Color.Green, Color.Gray})

' Add the new block at the botttom of the column,


' and push the rest of the

' blocks up one column.

For row As Integer = matrix.GetLength(0) – 1 To 1 Step -1

matrix(row, column) = matrix(row – 1, column)

Next

matrix(0, column) = newBlock

Next

End Sub

''' <summary>

''' Draw the grid of blocks

''' </summary>

''' <param name="graphics"></param>

''' <param name="backColor"></param>

''' <remarks></remarks>

Public Sub Draw(ByVal graphics As Graphics, _

ByVal backColor As Color)

graphics.Clear(backColor)

Dim row As Integer

Dim column As Integer

Dim theBlock As Block

For row = 0 To matrix.GetLength(0) – 1

For column = 0 To matrix.GetLength(1) – 1

theBlock = matrix(row, column)

If Not theBlock Is Nothing Then

Dim pointA As New Point( _

column * Block.BlockSize, _

row * Block.BlockSize)

matrix(row, column).Draw(graphics, pointA)

End If

Next

Next

End Sub

''' <summary>

''' This method responds to a click event in the UI.

''' </summary>

''' <param name="point"></param>

''' <returns>The number of blocks removed from the grid.</returns>

''' <remarks></remarks>

Public Function Click(ByVal point As Point) As Integer

' Figure out row and column.

Dim total As Integer

Dim transPt As Point = PointTranslator.TranslateToTL(point)

Dim selectedRow As Integer = transPt.Y \ Block.BlockSize

Dim selectedColumn As Integer = transPt.X \ Block.BlockSize

Dim selectedBlock As Block = matrix(selectedRow, _

selectedColumn)

If Not selectedBlock Is Nothing Then

selectedBlock.MarkedForDeletion = True

' Determine if any of the neighboring blocks are

' the same color.

FindSameColorNeighbors(selectedRow, selectedColumn)

' Determine how many blocks would be eliminated.

total = Me.CalculateScore()

If total > 1 Then

Me.CollapseBlocks()

Else

Me.ClearMarkedForDeletion()

End If

End If

Return total

End Function

Private Sub ClearMarkedForDeletion()

Dim row As Integer

Dim column As Integer

For column = matrix.GetLength(1) – 1 To 0 Step -1

' If column is completely empty, then move everthing

' down one.

For row = 0 To matrix.GetLength(0) – 1

If Not matrix(row, column) Is Nothing Then

matrix(row, column).MarkedForDeletion = False

End If

Next

Next

End Sub

''' <summary>

''' Find out how many blocks will be eliminated.

''' </summary>

''' <returns></returns>

''' <remarks></remarks>

Private Function CalculateScore() As Integer

Dim row As Integer

Dim column As Integer

Dim total As Integer = 0

For column = matrix.GetLength(1) – 1 To 0 Step -1

' If column is completely empty, then move everthing

' down one.

For row = 0 To matrix.GetLength(0) – 1

If Not matrix(row, column) Is Nothing Then

If matrix(row, column).MarkedForDeletion Then

total += 1

End If

End If

Next

Next

Return total

End Function

''' <summary>

''' After the blocks are removed from the columns, there may be

''' columns that are empty. Move columns from right to left to

''' fill in the empty columns.

''' </summary>

''' <remarks></remarks>

Public Sub CollapseColumns()

Dim row As Integer

Dim column As Integer

For column = matrix.GetLength(1) – 1 To 0 Step -1

' If column is completely empty, then all the columns

' over one.

Dim noBlocks As Boolean = True

For row = 0 To matrix.GetLength(0) – 1

If Not matrix(row, column) Is Nothing Then

noBlocks = False

End If

Next

If noBlocks Then

Dim newcol As Integer

For newcol = column To matrix.GetLength(1) – 2

For row = 0 To matrix.GetLength(0) – 1

matrix(row, newcol) = matrix(row, newcol + 1)

Next

Next

newcol = matrix.GetLength(1) – 1

For row = 0 To matrix.GetLength(0) – 1

matrix(row, newcol) = Nothing

Next

End If

Next


End Sub

''' <summary>

''' Remove all the blocks from the grid.

''' </summary>

''' <remarks></remarks>

Public Sub CollapseBlocks()

Dim theBlock As Block

Dim column As Integer

Dim row As Integer

Dim aRow As Integer

' First remove the blocks from each column.

For column = 0 To matrix.GetLength(1) – 1

For row = matrix.GetLength(0) – 1 To 0 Step -1

theBlock = matrix(row, column)

If (Not theBlock Is Nothing) Then

If theBlock.MarkedForDeletion Then

For aRow = row To matrix.GetLength(0) – 2

matrix(aRow, column) = _

matrix(aRow + 1, column)

Next

matrix(matrix.GetLength(0) – 1, _

column) = Nothing

End If

End If

Next

Next

' Reset the MarkedForDeletion flags.

For row = 0 To matrix.GetLength(0) – 1

For column = 0 To matrix.GetLength(1) – 1

theBlock = matrix(row, column)

If Not theBlock Is Nothing Then

theBlock.MarkedForDeletion = False

End If

Next

Next

' Remove any columns that are now empty.

CollapseColumns()

End Sub

''' <summary>

''' Provides access into the grid.

''' </summary>

''' <param name="row"></param>

''' <param name="column"></param>

''' <value></value>

''' <remarks></remarks>

Default Public Property Item(ByVal row As Integer, _

ByVal column As Integer) As Block

Get

Return matrix(row, column)

End Get

Set(ByVal Value As Block)

matrix(row, column) = Value

End Set

End Property

Private blocksToExamine As ArrayList

''' <summary>

''' Set MarkedForDeletion to True for each neighboring block

''' of the same color.

''' </summary>

''' <param name="row"></param>

''' <param name="column"></param>

''' <remarks></remarks>

Private Sub FindSameColorNeighbors(ByVal row As Integer, _

ByVal column As Integer)

Dim color As Color = matrix(row, column).Color

blocksToExamine = New ArrayList

blocksToExamine.Add(New Point(row, column))

matrix(row, column).MarkedForDeletion = True

' Each time you find a neighbor, mark it for deletion, and

' add it to the list of blocks to look for neighbors.

' After you

' examine it, remove it from the list. Keep doing this

' until there are no more blocks to look at.

While blocksToExamine.Count > 0

FindNeighbors()

End While

End Sub

''' <summary>

''' Look to the blocks on each side.

''' </summary>

''' <remarks></remarks>

Private Sub FindNeighbors()

' Take the first block out of the arraylist and examine it.

Dim location As Point = CType(blocksToExamine(0), Point)

Dim currentBlock As Block = matrix(location.X, location.Y)

Dim row As Integer = location.X

Dim column As Integer = location.Y

blocksToExamine.RemoveAt(0)

Dim nextRow As Integer

Dim nextCol As Integer

Dim selected As Block

' look up

If row < matrix.GetLength(0) – 1 Then

nextRow = row + 1

selected = matrix(nextRow, column)

ExamineNeighbor(selected, nextRow, column, _

currentBlock.Color)

End If

' look down

If row > 0 Then

nextRow = row – 1

selected = matrix(nextRow, column)

ExamineNeighbor(selected, nextRow, column, _

currentBlock.Color)

End If

' look left

If column > 0 Then

nextCol = column – 1

selected = matrix(row, nextCol)

ExamineNeighbor(selected, row, nextCol, _

currentBlock.Color)

End If

' look right

If column < matrix.GetLength(1) – 1 Then

nextCol = column + 1

selected = matrix(row, nextCol)

ExamineNeighbor(selected, row, nextCol, _

currentBlock.Color)

End If

End Sub

''' <summary>

''' If the neighbor is the same color, add it to the blocks

''' to examine.

''' </summary>

''' <param name="selected"></param>

''' <param name="row"></param>

''' <param name="column"></param>

''' <param name="color"></param>

''' <remarks></remarks>

Private Sub ExamineNeighbor(ByVal selected As Block, _

ByVal row As Integer, ByVal column As Integer, _

ByVal color As Color)

If Not selected Is Nothing Then

If selected.Color.Equals(color) Then

If Not selected.MarkedForDeletion Then

selected.MarkedForDeletion = True

blocksToExamine.Add(New Point(row, column))

End If

End If

End If

End Sub

End Class

По второму варианту, в панели Solution Explorer выполняем правый щелчок по имени проекта и в контекстном меню выбираем Add, New Item, в панели Add New Item выделяем шаблон Code File, в окне Name записываем имя HighScore.vb и щёлкаем кнопку Add. В проект (и в панель Solution Explorer) добавляется этот файл, открывается пустое окно редактирования кода, в которое записываем код со следующего листинга.

Weitere Bücher von diesem Autor