Dvorneg / minesweeper_GameObject.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com . javarush . games . minesweeper ; |
public class GameObject |
public int x ; |
public int y ; |
public boolean isMine ; |
public int countMineNeighbors ; |
public boolean isOpen ; |
public boolean isFlag ; |
public GameObject ( int x , int y , boolean isMine ) |
this . x = x ; |
this . y = y ; |
this . isMine = isMine ; |
this . isFlag = false ; |
> |
> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
package com . javarush . games . minesweeper ; |
import com . javarush . engine . cell . Color ; |
import com . javarush . engine . cell . Game ; |
import java . util . ArrayList ; |
import java . util . List ; |
public class MinesweeperGame extends Game |
private static final int SIDE = 9 ; |
private GameObject [][] gameField = new GameObject [ SIDE ][ SIDE ]; |
private int countMinesOnField ; |
private static final String MINE = » \uD83D \uDCA3 » ; |
private static final String FLAG = » \uD83D \uDEA9 » ; |
private int countFlags ; |
private boolean isGameStopped ; |
private int countClosedTiles = SIDE * SIDE ; |
private int score ; |
@ Override |
public void initialize () |
setScreenSize ( SIDE , SIDE ); |
createGame (); |
> |
private void createGame () |
//isGameStopped=false; |
for ( int y = 0 ; y < SIDE ; y ++) |
for ( int x = 0 ; x < SIDE ; x ++) |
boolean isMine = getRandomNumber ( 10 ) < 1 ; |
if ( isMine ) |
countMinesOnField ++; |
> |
gameField [ y ][ x ] = new GameObject ( x , y , isMine ); |
setCellColor ( x , y , Color . ORANGE ); |
setCellValue ( x , y , «» ); |
> |
> |
countFlags = countMinesOnField ; |
countMineNeighbors (); |
> |
private List < GameObject >getNeighbors ( GameObject gameObject ) |
List < GameObject >result = new ArrayList <>(); |
for ( int y = gameObject . y — 1 ; y <= gameObject . y + 1 ; y ++) |
for ( int x = gameObject . x — 1 ; x <= gameObject . x + 1 ; x ++) |
if ( y < 0 || y >= SIDE ) |
continue ; |
> |
if ( x < 0 || x >= SIDE ) |
continue ; |
> |
if ( gameField [ y ][ x ] == gameObject ) |
continue ; |
> |
result . add ( gameField [ y ][ x ]); |
> |
> |
return result ; |
> |
@ Override |
public void onMouseLeftClick ( int x , int y ) |
//super.onMouseLeftClick(x, y); |
if ( isGameStopped == true ) |
restart (); |
else |
openTile ( x , y ); |
> |
private void openTile ( int x , int y ) |
GameObject gameObject = gameField [ y ][ x ]; |
if ( gameObject . isOpen == false && gameObject . isFlag == false && isGameStopped == false ) |
gameObject . isOpen = true ; |
countClosedTiles —; |
setCellColor ( x , y , Color . GREEN ); |
if (! gameObject . isMine ) |
score = score + 5 ; |
setScore ( score ); |
if ( countMinesOnField == countClosedTiles ) |
win (); |
> |
if ( gameObject . isMine ) |
setCellValueEx ( gameObject . x , gameObject . y , Color . RED , MINE ); |
//setCellColor(x,y,Color.RED); |
gameOver (); |
> else if ( gameObject . countMineNeighbors == 0 ) |
setCellValue ( gameObject . x , gameObject . y , «» ); |
List < GameObject >neighbors = getNeighbors ( gameObject ); |
for ( GameObject neighbor : neighbors ) |
if (! neighbor . isOpen ) |
openTile ( neighbor . x , neighbor . y ); |
> |
> |
> else |
setCellNumber ( x , y , gameObject . countMineNeighbors ); |
> |
> |
> |
//подсчет мин рядом. |
private void countMineNeighbors () |
for ( int y = 0 ; y < SIDE ; y ++) |
for ( int x = 0 ; x < SIDE ; x ++) |
if ( gameField [ y ][ x ]. isMine == false ) |
//List result = new ArrayList<>(); |
List < GameObject >result = getNeighbors ( gameField [ y ][ x ]); |
int countMine = 0 ; |
for ( int i = 0 ; i < result . size () ; i ++) |
if ( result . get ( i ). isMine == true ) |
countMine ++; |
> |
gameField [ y ][ x ]. countMineNeighbors = countMine ; |
> |
> |
> |
> |
@ Override |
public void onMouseRightClick ( int x , int y ) |
//super.onMouseRightClick(x, y); |
markTile ( x , y ); |
> |
private void markTile ( int x , int y ) |
if ( isGameStopped == true ) |
return ; |
if (! gameField [ y ][ x ]. isOpen ) |
if ( gameField [ y ][ x ]. isFlag == false ) |
if ( countFlags != 0 ) |
setCellValue ( x , y , FLAG ); |
setCellColor ( x , y , Color . YELLOW ); |
gameField [ y ][ x ]. isFlag = true ; |
countFlags —; |
> |
> else |
setCellValue ( x , y , «» ); |
gameField [ y ][ x ]. isFlag = false ; |
setCellColor ( x , y , Color . ORANGE ); |
countFlags ++; |
> |
// if(countFlags!=0&&gameField[y][x].isFlag==true) |
> |
> |
private void gameOver () |
isGameStopped = true ; |
showMessageDialog ( Color . DARKBLUE , «GAME OVER! (нажмите на поле для рестарта.)» , Color . GOLD , 20 ); |
> |
private void win () |
isGameStopped = true ; |
showMessageDialog ( Color . BLACK , «Это победа!» , Color . GOLD , 20 ); |
> |
private void restart () |
countClosedTiles = SIDE * SIDE ; |
score = 0 ; |
setScore ( score ); |
countMinesOnField = 0 ; |
isGameStopped = false ; |
createGame (); |
//setCellValue(int, int, String); |
> |
> |
/*- ограничить количество ходов; |
— сделать так, чтобы первый ход никогда не попадал на мину; |
— усложнить или упростить игру, изменив количество мин на поле; |
— добавить визуальные эффекты (анимацию).*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
taskKey=»com.javarush.games.minesweeper.part16″\n\nИгра сапер (16/16) |
Наши поздравления: игра написана! Предлагаем запустить ее и посмотреть, что получилось. |
Если есть время и вдохновение, можешь улучшить игру, добавив некоторые "фичи" от себя. Например: |
• ограничить количество ходов; |
• сделать так, чтобы первый ход никогда не попадал на мину; |
• усложнить или упростить игру, изменив количество мин на поле; |
• добавить визуальные эффекты (анимацию). |
Готовую игру ты можешь опубликовать на JavaRush. Но перед этим нужно отправить свое решение на проверку, |
чтобы была доступна кнопка публикации. Игра будет доступна в разделе "Игры" всем пользователям. |
А еще ты можешь поделиться ею с друзьями в соцсетях. Будет здорово, если они сыграют в твою версию "Сапера", не так ли? |
После публикации, в комментариях напиши краткую инструкцию (какие действия доступны, |
какие клавиши или кнопки нужно использовать для игры), а также особенности твоей реализации. |
Требования: |
1. Запусти игру и поиграй. |
Игра сапер (16/16) |
Как известно, настоящий сапер ошибается только один раз. Но, к счастью, у нас есть право на ошибку, и даже не одну. |
Давай реализуем механизм рестарта игры. Для этого создадим метод restart(), в котором будем запускать |
игру, сбрасывать в исходное состояние количество закрытых ячеек, мин на поле и |
очков. Не забудь об обновлении счета на игровом поле и о вызове метода, который отвечает за создание игры. |
Также в методе restart() нужно очистить игровое поле от флагов, мин, чисел и пр. Рестартовать игру |
будем по нажатию левой кнопки мыши. |
Игра сапер (16/16) |
Согласись, без счета играть не очень интересно. Давай добавим этот функционал в нашу игру. Нам понадобится |
переменная для учета очков. При открытии ячейки без мины счет увеличивается на 5 очков. |
Чтобы счет отображался на игровом поле, нам нужно воспользоваться специальным методом setScore() класса Game, |
в который передадим общее количество очков. Обрати внимание, что вызывать этот метод нужно после увеличения счета — |
иначе будет показан неправильный результат. |
Запусти игру и попробуй набрать максимальное количество очков. |
Игра сапер (16/16) |
Игра считается выигранной, когда количество оставшихся закрытых ячеек равно количеству мин. Для подсчета числа |
закрытых ячеек введем дополнительную переменную, значение которой изначально равно общему количеству ячеек на |
игровом поле. Значение этой переменной будет уменьшаться по мере открытия ячеек. Когда ее значение станет равно |
количеству мин, игра будет выиграна. |
На данный момент, в нашей игре в случае выигрыша ничего не происходит, а должно бы. Пора это исправить. |
Давай напишем метод win(), в котором будем останавливать игру и поздравлять победителя красивым сообщением. |
Запусти игру и проверь, что при выигрыше отработал метод win(). |
Обрати внимание, что метод win() вызывается, если количество закрытых ячеек равно количеству мин на поле. |
При этом, если последняя открытая ячейка оказалась миной, то метод не должен быть вызван. |
Игра сапер (16/16) |
Ячейку можно открыть только раз. Если ячейка отмечена флагом, она не должна открываться. |
Ну и, конечно же, ячейки не должны открываться после того, как игра была остановлена. Давай учтем все эти моменты |
в методе openTile(int, int). Теперь нужно убедиться, что все работает корректно — запусти игру и проверь. |
Игра сапер (16/16) |
Практически в любой игре игрок либо выигрывает, либо проигрывает. Давай для начала реализуем проигрыш. |
Для этого нам пригодится метод gameOver(), который будет останавливать игру и сообщать игроку о проигрыше. |
Для вывода сообщения игроку в движке предусмотрен метод showMessageDialog(). |
Чтобы контролировать остановку игры, введем специальную переменную-флаг isGameStopped. При каких |
обстоятельствах происходит проигрыш? Правильно: при открытии "заминированной" ячейки. Если такое |
событие наступило, нужно ячейку с миной перекрасить в красный цвет (Color.RED) и вызвать метод gameOver(). |
Не забудь учесть остановку игры в методе markTile(int, int). Запусти игру и проверь, что все реализованное |
тобой работает. |