59. Консольная игра «Крестики-нолики» #
Условие задачи:
📌 Написать консольную игру «Крестики-нолики» с произвольным размером поля. Структура:
Main
— точка входа, спрашивает размер поля и запускает игру.Game
— логика игры (ходы, проверка победы/ничьи).Desk
— хранит состояние поля, рисует доску.AI
— интерфейс для хода компьютера.Player
— класс для живого игрока (вводит координаты с консоли).IndianAI
— реализацияAI
, делает ход «компьютерно» (случайным выбором).
Спойлеры к решению
Подсказки
💡 Инкапсулируйте логику хода в интерфейсе
💡
💡
💡
AI
— расширяемость.💡
Desk
отвечает за хранение и проверку победы/ничьи.💡
Game
управляет игровым циклом.💡
Player
читает ввод с консоли, IndianAI
генерирует случайные ходы.Решение
Код:
// Main.java
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("Введите размер поля: ");
int size = scanner.nextInt();
Game game = new Game(size, new Player(scanner, 'X'), new IndianAI('O'));
game.play();
scanner.close();
}
}
// Desk.java
public class Desk {
private final char[][] field;
private final int size;
public Desk(int size) {
this.size = size;
this.field = new char[size][size];
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
field[i][j] = '.';
}
public boolean isCellEmpty(int row, int col) {
return field[row][col] == '.';
}
public void setCell(int row, int col, char symbol) {
field[row][col] = symbol;
}
public void print() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.print(field[i][j] + " ");
}
System.out.println();
}
}
public boolean hasWon(char symbol) {
// Проверка строк и столбцов
for (int i = 0; i < size; i++) {
if (checkLine(symbol, i, 0, 0, 1) || checkLine(symbol, 0, i, 1, 0))
return true;
}
// Диагонали
if (checkLine(symbol, 0, 0, 1, 1) || checkLine(symbol, 0, size - 1, 1, -1))
return true;
return false;
}
private boolean checkLine(char symbol, int startRow, int startCol, int dRow, int dCol) {
for (int k = 0, r = startRow, c = startCol; k < size; k++, r += dRow, c += dCol) {
if (field[r][c] != symbol) return false;
}
return true;
}
public boolean isFull() {
for (int i = 0; i < size; i++)
for (int j = 0; j < size; j++)
if (field[i][j] == '.') return false;
return true;
}
}
// AI.java
public interface AI {
void makeMove(Desk desk);
}
// Player.java
import java.util.Scanner;
public class Player implements AI {
private final Scanner scanner;
private final char symbol;
public Player(Scanner scanner, char symbol) {
this.scanner = scanner;
this.symbol = symbol;
}
@Override
public void makeMove(Desk desk) {
int row, col;
do {
System.out.print("Ход игрока '" + symbol + "' (строка и колонка от 1 до "
+ deskSize(desk) + "): ");
row = scanner.nextInt() - 1;
col = scanner.nextInt() - 1;
} while (!validMove(desk, row, col));
desk.setCell(row, col, symbol);
}
private boolean validMove(Desk desk, int r, int c) {
int size = deskSize(desk);
if (r < 0 || r >= size || c < 0 || c >= size) {
System.out.println("Неверные координаты.");
return false;
}
if (!desk.isCellEmpty(r, c)) {
System.out.println("Ячейка занята.");
return false;
}
return true;
}
private int deskSize(Desk desk) {
try {
java.lang.reflect.Field f = desk.getClass().getDeclaredField("size");
f.setAccessible(true);
return f.getInt(desk);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// IndianAI.java
import java.util.Random;
public class IndianAI implements AI {
private final char symbol;
private final Random rand = new Random();
public IndianAI(char symbol) {
this.symbol = symbol;
}
@Override
public void makeMove(Desk desk) {
int size = getSize(desk);
int r, c;
do {
r = rand.nextInt(size);
c = rand.nextInt(size);
} while (!desk.isCellEmpty(r, c));
System.out.println("Ход компьютера '" + symbol + "': " + (r + 1) + " " + (c + 1));
desk.setCell(r, c, symbol);
}
private int getSize(Desk desk) {
try {
java.lang.reflect.Field f = desk.getClass().getDeclaredField("size");
f.setAccessible(true);
return f.getInt(desk);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
// Game.java
public class Game {
private final Desk desk;
private final AI playerX;
private final AI playerO;
public Game(int size, AI playerX, AI playerO) {
this.desk = new Desk(size);
this.playerX = playerX;
this.playerO = playerO;
}
public void play() {
desk.print();
while (true) {
playerX.makeMove(desk);
desk.print();
if (desk.hasWon(getSymbol(playerX))) {
System.out.println("Победил '" + getSymbol(playerX) + "'!");
break;
}
if (desk.isFull()) {
System.out.println("Ничья!");
break;
}
playerO.makeMove(desk);
desk.print();
if (desk.hasWon(getSymbol(playerO))) {
System.out.println("Победил '" + getSymbol(playerO) + "'!");
break;
}
if (desk.isFull()) {
System.out.println("Ничья!");
break;
}
}
}
private char getSymbol(AI ai) {
if (ai instanceof Player) return ((Player) ai).symbol;
if (ai instanceof IndianAI) return ((IndianAI) ai).symbol;
return '?';
}
}
Пример запуска:
Введите размер поля: 3
. . .
. . .
. . .
Ход игрока 'X' (строка и колонка от 1 до 3): 1 1
X . .
. . .
. . .
Ход компьютера 'O': 2 2
...