Доброго времени суток, дорогие друзья, падаваны и магистры, маленькие дети, а также дети младшего, среднего, старшего, очень старшего и пожилого возраста! Снова сегодня на арене игра "Крестики-нолики", но на этот раз будем использовать язык программирования Java.
Правила игры
Правила игры "Крестики-нолики" известна нам еще со школы. Рисуется игровое поле из клеток, размером 3х3 (3 клетки в ширину, 3 клетки в высоту). Два игрока поочередно рисуют в эти клетки либо крестик, либо нолик (каждый игрок рисует "фигуры" одного типа). Задача игрока - занять своими фигурами либо три клетки на одной горизонтали, либо три клетки на одной вертикали, либо три клетки на одной диагонали. Кто первый выполнит это условие, тот и выиграл. Естественно, после выигрыша одного из игроков игра прекращается.
Вся наша жизнь - игра!
Итак, в нашем случае игра будет консольной, за X будет играть человек (мы), за О - компьютер. Следовательно, Х будем вводить мы с клавиатуры, а О - компьютер, пользуясь собственными системами ввода, которые мы ему опишем. Но обо всём по порядку.
Создаем проект программы на Java - весь код у нас будет внутри класса Game (он public), и методом main создаем экземпляр класса Game и запускаем его методом startGame (пока конструктора класса и метода startGame нет, напишем чуть позже).
С чего начать
Начнем писать код. Зададим основные константы (свойства Game): размер поля SIZE, игроки PLAYER_X, PLAYER_0, которые играют соответственно играют крестиками PLAYER_X и ноликами PLAYER_0 и пустой символ EMPTY, который нам понадобится при первичном заполнении полей.
Задали? Отлично! Теперь создаем игровое поле board, представляющее собой двумерный массив из символов char и currentPlayer - текущий игрок.
Инициация игрового поля и заполнение полей.
Ну а вот и долгожданный конструктор класса Game. В нем мы создаем поле board размером SIZExSIZE (напоминаем, SIZE=3) и инициируем поле методом initiaizeBoard.
initiaizeBoard - пустой (void) метод, который ничего не возвращает, а просто через цикл заполняет элементы board значениями константы EMPTY. Ничего сложного.
Ну и соответственно игровое поле нам надо выводить на печать в консоли. Создадим для этого сразу метод printBoard(). Вложенный цикл, вывод значений и псевдографики через System.out.print() и System.out.println()
Победа, поражение или ничья
- Пап, а разве из палки можно попасть в человека?
- Поверь сынок, это не самое сложное. Сложнее потом доказать, что ты попал!
(из юмористической сценки об играх во дворе в 80-е)
Итак, как мы здесь докажем, что победили (или компьютер докажет, что победил)? Пропишем для этого методы проверки на победу или ничью.
Итак, для проверки, есть ли победитель, у нас есть метод checkWin(), который во-первых запускает поиск по циклам. Проверка в циклах ведется по горизонтали и вертикали. Какие условия необходимы, чтобы сообщить, что есть победитель? Для этого первый элемент горизонтали или вертикали должен быть непустым (т.е. не первоначальное состояние board) и он должен быть равен второму и третьему элементу горизонтали или вертикали (или все элементы по горизонтали или вертикали - крестики, или они же - все нолики). Если такое состояние находится - работа метода прерывается и возвращается true.
Если же в горизонталях или вертикалях не найдены "победные" варианты, проверяем диагонали. Тут точно так же: критерий того что победитель есть, - первые элементы (0,0) и (2,0) не пустые, и они равны остальным элементам соответствующим диагоналям. Если подобные комбинации есть - работа метода также прерывается и возвращается true. Если нет - возвращается false - на данном этапе победитель не выявлен, и игра продолжается.
Проверка на состоянии ничьи isDraw() осуществляется, если на этапе не выявлен победитель. Циклично проверяются все элементы игрового поля board на пустоту. Если есть пустые элементы (board[i][j]==EMPTY), игру можно продолжить, ничьи нет, возвращаем false. Если же нет пустых элементов, но и победитель не выявлен, метод возвращает true, и провозглашается ничья.
Ход и смена игрока
Итак, поскольку проще реализовать смену игрока, её и реализуем через метод switchPlayer(). Здесь всё проще пареной репы (которую не во всяком продуктовом магазине найдешь ))) ):
currentPlayer = (currentPlayer == PLAYER_X) ? PLAYER_O : PLAYER_X;
Можно через if...else, можно короткой записью: если текущий игрок PLAYER_X (поля заполняются крестиками), то при смене он будет PLAYER_O, (при ходе поля будут заполняться ноликами) иначе при смене он будет PLAYER_X(поля снова заполняются крестиками).
Теперь проверка хода игрока. Поскольку мы с консоли будем задавать координаты того поля, где поместим наш знак(об этом позже), то вполне возможно случайно (или намеренно) попасть в поле, где есть крестик или нолик. Поэтому и введена особая проверка хода игрока makeMove(int row, int col) - если board[row][col] не пустое поле, то return false, и игроку или компьютеру надо сделать ход в другую клетку. Иначе значение клетки заполняется значением знака текущего игрока board[row][col]=currentPlayer и return true.
Долгожданный startGame
А вот и долгожданный startGame().Вначале в этом методе производится ход игрока или компьютера. Если игрок - PLAYER_X (т.е. человек), то ввод строки и столбца заполняемой клетки осуществляется с клавиатуры в консоль методом scanner.nextInt(), если же PLAYER_О (компьютер) - клетка выбирается случайным образом (методом random.nextInt() выбираются значения числового массива numbers (0,1 или 2))
Введенные данные проверяются на корректность ввода (makeMove()), потом, если всё корректно, на наличие победителя после хода (checkWin). Если победитель не определен, проверяется, нет ли ничьи (isDraw). Если и ничьи нет, то производится смена игрока (switchPlayer()) и игра продолжается. Для того, чтобы не вылететь из игры раньше времени, в начале метода создана переменная gameRunning=true, и игра будет продолжаться в бесконечном цикле while(gameRunning). Если выявлен победитель или ничья, после соответствующих сообщений gameRunning=false, и игра прекращается.
Запускается startGame, как мы уже говорили выше, методом main при запуске программы.
Ну и вывод частички процесса игры (в консоли):
Что дальше?
То, что мы с вами сейчас создали, доступно на gitflic по ссылке. На android посредством Android Studio мы перенесем нашу программу в следующих статьях цикла (следите за публикациями). Отсюда на андроид возьмем смену игрока, поиск победителя, проверку на ничью.