Знакомимся с Java 2 (или крестики-нолики в консоли)

В прошлый раз мы с вами установили IDE Eclipse и создали в ней свой первый проект. Но пришла пора заняться чем-то посерьезней! Поскольку обучение легче всего происходит в игровой форме, предлагаю вашему внимаю небольшую консольную игру. Крестики-нолики, так же известную как tic-tac-toe :-).


Теперь нам необходимо определиться с тем, как мы собственно будем писать нашу игру? Прежде всего нам нужно игровое поле. Пусть это будет двумерный массив символов размером 3×3 (почитать про разные типы данных в Java можно тут). Если в какой-то клетке игрового поля у нас ничего нет, то ставим туда например плюсик, если в ячейке нолик пусть это будет буква «О» если крестик то буква «Х». Начнем с задания самого поля:

	// Игровое поле
	public static char[][] field =
		{ 	{ '+', '+', '+' },
			{ '+', '+', '+' },
			{ '+', '+', '+' } };

Наше игоровое поле представляет собой двумерный массив символов Field, все значения в котором задаются при его создании. О том, что этот массив двумерный говорят две квадратные скобочки после описания типа char. При этом сначала у нас везде стоят плюсики — т.е. все поле свободно. Следующее, что мы сделаем — это организуем ход пользователя:

// Ход человека
	public static void HumanMove() throws IOException {
		int x , y;
		System.out.println("Enter y (1..3):");
		BufferedReader br = new BufferedReader(new InputStreamReader(
				System.in));
		x = Integer.parseInt(br.readLine())-1;
		System.out.println("Enter x (1..3):");
		y = Integer.parseInt(br.readLine())-1;
		while (field[x][y] == '0' || field[x][y] == 'X' || x < 0 || x > 2
				|| y < 0 || y > 2) {
			System.out.println("Enter x:");
			x = Integer.parseInt(br.readLine())-1;
			System.out.println("Enter y:");
			y = Integer.parseInt(br.readLine())-1;
		}
		field[x][y] = 'X';
	}

Итак, что же здесь происходит? Первая строка — это описание матода, который реализует ход человека. О методах и их описании этом мы поговорим попозже. Во второй строке объявляются две переменные x и y, это будут координаты, куда поставит крестик игрок. Затем, с помощью конструкции System.out.println() мы выводим на экран приглашение ввести координату по оси Y. В следующей строке создается буфферизированный поток br с помошью которого можно считывать из консоли вводимые пользователем строки.

В строке 7 конструкция х=Integer.parseInt(String p) преобразует строковый параметр p в целочисленное значение и это значение мы записываем в переменную х.

Думаю две следующие строки, думаю, понятны по аналогии 🙂  А вот дальше мы проверяем в цикле с предусловием во-первых, не попал ли ход игрока на уже занятое поле, во-вторых, не выходят ли введенные пользователем цифры за границы нашего игрового поля. Если хоть одно из этих условий не выполняется, тогда мы заново просим ввести позицию Y и X. Ну а если все нормально, то цикл не выполнится и мы запишем на игровое поле ход игрока.

Теперь думаем что делать со вторым игроком. Поскольку заморачиваться на стратегии игры мне совсем не хотелось то бот ходит просто случайно. Алгоритм очень прост и код сильно напоминает предидущий кусок:

	// Ход компьютера (random-бот)
	public static void CompMove() {
		int x = (int) (Math.random() * 3), y = (int) (Math.random() * 3);
		while (field[x][y] == '0' || field[x][y] == 'X') {
			x = (int) (Math.random() * 3);
			y = (int) (Math.random() * 3);
		}
		field[x][y] = '0';
	}

Здесь Math.random() генерирует случайное число в интервале от 0 до 1, затем полученное число мы умножаем на три и округляем до целого. В итоге получаем числа X и Y в итервале от нуля до двух включительно. Проверяем, может ли бот сделать ход на полученные координаты, и если не может, то точно так же генерируем два новых числа и проверяем их. Алгоритм прост и реализация, как мне кажется не должна вызывать вопросов. 

Следующий метод определяет остались ли еще на игровом поле свободные клетки.

	public static boolean CanMove() {
		boolean p = false;
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				if (field[i][j] == '+') {
					p = true;
					break;
				}
			}
			if (p = true) {
				break;
			}
		}
		return p;
	}

В переменной p изначально хранится значение false (ложь). То есть сначала считаем, что свободных клеток не осталось. А потом начинаем проверять, есть ли они на самом деле или их нет. Мы проходим по каждой клетке игрового поля (два вложенных друг в друга цикла for) и если (почитать про условия в Java) где-то встречаем хоть одну свободную клетку, то записываем в p значение true (истина) и прерываем циклы. Затем при любом раскладе мы возващаем значение p. Получается что если мы встретили хоть одно пустое поле, то мы вернем истину, а если свободных клеточек больше не осталось, то вернем ложь.

Следующий метод просто выводит на экран содержимое игрового поля:

	// Вывод игрового поля на экран
	public static void PrintField() {
		for (int i = 0; i < 3; i++) {
			for (int j = 0; j < 3; j++) {
				System.out.print(field[i][j]);
			}
			System.out.println();
		}
	}

Комментировать думаю излишне?

На этом на сегодня думаю пора прекращать 🙂 Если есть какие-то вопросы, то не стетсняйтесь, постараюсь ответить. Если Я где-то что-то упустил, пишите! Закончим в следующий раз!

Вам понравилось? Было полезно? Поделитесь!

Опубликовать в Facebook
Опубликовать в Google Buzz
Опубликовать в Google Plus
Опубликовать в LiveJournal
Опубликовать в Мой Мир
Опубликовать в Одноклассники
Опубликовать в Яндекс
Запись опубликована в рубрике Знакомимся с Java с метками , , , , . Добавьте в закладки постоянную ссылку.

18 комментариев на «Знакомимся с Java 2 (или крестики-нолики в консоли)»

  1. Slava говорит:

    Приветствую.
    Хорошая статья! Хотелось бы добавить:
    — Не хватает итогового листинга программы.
    — Хоть и код больше образовательный и я лично не написал ещё ни одной программы на Java, но для чистоты кода думаю заменить циклы на do-while с пост условием.
    — CanMove можно использовать метку для прерывания цикла, дабы избежать двойного прерывания цикла.

    • davidmd говорит:

      Спасибо!
      Вот в этой статье есть готовый проект там весь код полностью.
      По поводу цикла согласен, смотреться будет значительно лучше 🙂
      На то Вам и код в руки! 🙂

  2. mmvds говорит:

    «генерирует случайное число в интервале от 0 до 1, затем полученное число мы умножаем на три и округляем до целого»
    на самом деле не «округляет», а отбрасывает целую часть

  3. Александр говорит:

    Да в строчках где вводятся x и y запрашивается y, а вводится x и наоборот.

  4. Yarik говорит:

    А почему для получения данных от человека использовался именно буферизированный поток?
    Ведь можно и так сделать:
    Scanner reader = new Scanner(System.in);
    System.out.println(«Enter y (1..3):»);
    x=reader.nextInt()-1;
    System.out.println(«Enter x (1..3):»);
    y=reader.nextInt()-1;
    И при этом меньше импорта получается…
    Я спрашиваю, потому что эти крестики-нолики — моя вторая программа после «Hello World» на яве 🙂

    • davidmd говорит:

      🙂 Тут объяснение крайне просто 🙂 Я на момент написания не знал о такой конструкции 🙂

  5. Александр говорит:

    Комп ходит абы как. Неосмысленно. Как обезьяна.
    А что если поле будет 5х5 ? Он вообще никогда не выиграет.

  6. Alex говорит:

    Статья написана хорошо, но, имхо, все слишком закручено. То же самое, а может и лучше можно сделать существенно упростив код.

  7. Max говорит:

    Подскажите, как добавить проверку — ввелось ли число и в диапозоне от 1 до 3? если ввелась буква или чего другое, то выдавалась бы ошибка и цикл повторялся.
    А то сейчас при вводе вместо 1 например «а» программа рушиться.
    А также всеже было бы здорово написать стратегию для компьютера, если кто смог бы поделитья, буду очень благодарен!

    • davidmd говорит:

      Считывайте строку, переводите ее в число, используя try catch и проверяйте полученное число.

  8. Серг говорит:

    скриншота нехватает

  9. Дима говорит:

    В методе, определяющем остались ли свободные клетки во внешнем цикле в условии if, вероятно, должен быть двойной знак равенства. Иначе, условие «(p = true)» всегда будет верным, так как выполняется присваивание.

    • Геннадий говорит:

      да-да-да!!! Потратил на это минут 30, пока понял в чем баг… ((((
      должно быть просто if (p) , ну или if(p==true)

      • davidmd говорит:

        Пожалуйста извините, счас так мало времени на сайт, что просто не успеваю даже на комментарии отвечать 🙁

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *