Загрузить PDF
Загрузить PDF
«Камень, ножницы, бумага» – это игра «на пальцах» для двоих. Игроки вместе говорят «камень, ножницы, бумага» и выбрасывают вперед руку, пальцами формируя одну из трех фигур (камень, ножницы или бумагу). Победитель определяется следующим образом: ножницы бьют бумагу, бумага бьет камень, камень бьет ножницы. Если оба игрока показывают одну и ту же фигуру, это считается ничьей. Мы напишем простую игру на Java, которая позволит играть в «камень, ножницы, бумага» с компьютером.
Шаги
-
1Создайте основной класс и назовите его
RockPaperScissors
. В этом классе мы опишем игру. Вы можете назвать его иначе, напримерGame
илиMain
. Напишите объявления конструктора и метода main.
public class RockPaperScissors { public RockPaperScissors () { } public static void main ( String [] args ) { } }
-
2Создайте перечисление (enum) для описания возможных ходов (камень, ножницы, бумага). Мы можем задать ходы строками, но перечисление позволяет нам предопределить константы, поэтому использование enum лучше. Назовем наше перечисление
Move
и зададим значенияROCK
,PAPER
иSCISSORS
.
private enum Move { ROCK , PAPER , SCISSORS }
-
3Создайте два закрытых (ключевое слово private) класса
User
иComputer
. Эти классы будут представлять игроков. Вы также можете сделать эти классы открытыми (ключевое слово public). КлассUser
будет запрашивать у пользователя, какой ход он делает – камень, ножницы или бумага – поэтому нам нужно написать методgetMove()
. КлассComputer
также должен иметь методgetMove()
, чтобы мы могли получить ход компьютера. Пока что мы просто объявим эти методы, а реализацию напишем позже. КлассUser
должен иметь конструктор, в котором инициализируется объектScanner
, который будет считывать ввод пользователя. ОбъявимScanner
закрытым членом данных классаUser
и инициализируем его в конструкторе. Поскольку мы собираемся использовать классScanner
, мы должны подключить его, используя ключевое словоimport
. КлассуComputer
конструктор не нужен, поэтому мы не будем его писать; при инициализации объектаComputer
мы просто вызовем конструктор по умолчанию. Вот как классRockPaperScissors
выглядит теперь:
import java.util.Scanner ; public class RockPaperScissors { private enum Move { ROCK , PAPER , SCISSORS } private class User { private Scanner inputScanner ; public User () { inputScanner = new Scanner ( System . in ); } public Move getMove () { // TODO: Реализация метода return null ; } } private class Computer { public Move getMove () { // TODO: Реализация метода return null ; } } public RockPaperScissors () { } public static void main ( String [] args ) { } }
-
4Напишите реализацию метода
getMove()
для классаComputer
. Этот метод будет возвращать случайное значениеMove
. Мы можем получить массив значенийMove
вызвав методvalues()
вот так:Move.values()
. Чтобы выбрать случайное значениеMove
из этого массива, нам нужно сгенерировать случайный индекс между 0 и количеством элементом массива. Для этого вызовем методnextInt()
классаRandom
, который мы подключим так:import java.util.Random
. Получив случайный индекс, вернем значениеMove
с этим индексом в нашем массиве.
public Move getMove () { Move [] moves = Move . values (); Random random = new Random (); int index = random . nextInt ( moves . length ); return moves [ index ]; }
-
5Напишите реализацию метода
getMove()
для классаUser
. Этот метод будет возвращать значениеMove
соответствующее вводу пользователя. Пользователь может ввести "камень", "ножницы", или "бумага". Сначала выведем сообщение:System.out.print("Камень, ножницы или бумага?")
. Затем, с помощью методаnextLine()
объектаScanner
, мы получим ввод пользователя в виде строки. Теперь нужно проверить корректность ввода пользователя. Однако мы не будет обращать внимание на опечатки, а просто проверим первую букву «К», «Н» или «Б». Также мы не будем обращать внимание на регистр букв, так как, предварительно, мы вызовем методtoUpperCase()
классаString
, приводя ввод пользователя к верхнему регистру. Если пользователь не ввел даже приблизительно корректный выбор, запросим его ход еще раз. Затем, в зависимости от ввода пользователя, наш метод вернет соответствующее значениеMove
.
public Move getMove () { // Выведем запрос на ввод System . out . print ( "Камень, ножницы или бумага? " ); // Прочитаем ввод пользователя String userInput = inputScanner . nextLine (); userInput = userInput . toUpperCase (); char firstLetter = userInput . charAt ( 0 ); if ( firstLetter == 'К' || firstLetter == 'Н' || firstLetter == 'Б' ) { // Ввод корректный switch ( firstLetter ) { case 'К' : return Move . ROCK ; case 'Н' : return Move . PAPER ; case 'Б' : return Move . SCISSORS ; } } // Ввод некорректный. Выведем запрос на ввод снова. return getMove (); }
-
6Напишите реализацию метода
playAgain()
классаUser
. Пользователь должен иметь возможность играть снова и снова. Чтобы определить хочет ли пользователь сыграть еще раз, напишите методplayAgain()
, который будет возвращать значение типа bool и, таким образом, сообщать игре хочет ли пользователь сыграть еще раз. В этом методе мы используем объектScanner
, который мы инициализировали в конструкторе, чтобы получить "Да" или "Нет" от пользователя. Мы всего лишь проверим первую букву, если она 'Д', значит, пользователь хочет сыграть еще раз, любая другая буква будет означать "Нет".
public boolean playAgain () { System . out . print ( "Хотите сыграть еще раз? " ); String userInput = inputScanner . nextLine (); userInput = userInput . toUpperCase (); return userInput . charAt ( 0 ) == 'Д' ; }
-
7Свяжите код класса
User
и классаComputer
в классеRockPaperScissors
. Написав код для классовUser
иComputer
, мы можем заняться самой игрой. Объявите классыUser
иComputer
закрытыми членами данных классаRockPaperScissors
. Мы будем обращаться к ним, вызывая методgetMove()
, чтобы получить ходы игроков. Инициализируйте их в конструкторе классаRockPaperScissors
. Также нам нужно хранить счет. ОбъявитеuserScore
иcomputerScore
, затем инициализируйте их нулем. И, наконец, создайте поле данных для хранения количества игр, также инициализировав его нулем.
private User user ; private Computer computer ; private int userScore ; private int computerScore ; private int numberOfGames ; public RockPaperScissors () { user = new User (); computer = new Computer (); userScore = 0 ; computerScore = 0 ; numberOfGames = 0 ; }
-
8Дополните перечисление
Move
методом, который будет сравнивать ходы и определять победителя. Напишем код для методаcompareMoves()
который будет возвращать 0, если ходы одинаковы, 1 – если текущий ход бьет другой и -1 – если другой ход бьет текущий. Текущий ход представлен указателем this, а другой передается в параметре otherMove. Это пригодится для определения победителя. Сначала напишем код определяющий ничью и возвращающий 0, а затем напишем инструкцию switch для определения победителя.
private enum Move { ROCK , PAPER , SCISSORS ; /** * Сравнивает текущий ход с переданным в параметре otherMove и определяет * победу, поражение или ничью. * * @param otherMove * ход, с которым сравнивается текущий * @return 1 если текущий ход бьет другой, -1 если другой ход бьет текущий, * 0 в случае ничьей */ public int compareMoves ( Move otherMove ) { // Ничья if ( this == otherMove ) return 0 ; switch ( this ) { case ROCK : return ( otherMove == SCISSORS ? 1 : - 1 ); case PAPER : return ( otherMove == ROCK ? 1 : - 1 ); case SCISSORS : return ( otherMove == PAPER ? 1 : - 1 ); } // Этот код не должен выполняться никогда return 0 ; } }
-
9Объявите метод
startGame()
в классеRockPaperScissors
. В этом методе будет происходить игра. Начните вызовом методаSystem.out.println
.
public void startGame () { System . out . println ( "КАМЕНЬ, НОЖНИЦЫ, БУМАГА!" ); }
-
10Получите ходы компьютера и пользователя. В методе
startGame()
вызовитеgetMove()
классовUser
иComputer
, чтобы получить их ходы.
Move userMove = user . getMove (); Move computerMove = computer . getMove (); System . out . println ( "\nВаш ход " + userMove + "." ); System . out . println ( "Ход компьютера " + computerMove + ".\n" );
-
11Сравните ход компьютера и ход игрока, чтобы определить кто выиграл. Вызовите метод
compareMoves()
перечисленияMove
, чтобы определить выиграл ли пользователь. Если да, увеличьте его счет на 1. Если нет, увеличьте счет компьютера. В случае ничьей счет остается прежним. После этого увеличьте количество сыгранных игр на 1.
int compareMoves = userMove . compareMoves ( computerMove ); switch ( compareMoves ) { case 0 : // Ничья System . out . println ( "Ничья!" ); break ; case 1 : // Победил игрок System . out . println ( userMove + " beats " + computerMove + ". Вы победили!" ); userScore ++; break ; case - 1 : // Победил компьютер System . out . println ( computerMove + " beats " + userMove + ". Вы проиграли." ); computerScore ++; break ; } numberOfGames ++;
-
12Спросите пользователя хочет ли он сыграть еще раз. Если да, вызовите метод
startGame()
еще раз. Если же нет, вызовите методprintGameStats()
, который выведет статистику игры. Мы напишем его реализацию в следующем шаге.
if ( user . playAgain ()) { System . out . println (); startGame (); } else { printGameStats (); }
-
13Напишите реализацию метода
printGameStats()
. Этот метод будет выводить статистику игры: количество побед, поражений, ничьих, количество сыгранных игр и процент побед игрока. Процент выигранных игр считается так: (кол-во побед + (кол-во ничьих/2))/(кол-во сыгранных игр). Этот метод используетSystem.out.printf
для форматированного вывода текста.
private void printGameStats () { int wins = userScore ; int losses = computerScore ; int ties = numberOfGames - userScore - computerScore ; double percentageWon = ( wins + (( double ) ties ) / 2 ) / numberOfGames ; // Вывод линии System . out . print ( "+" ); printDashes ( 68 ); System . out . println ( "+" ); // Вывод заголовков таблицы System . out . printf ( "| %6s | %6s | %6s | %12s | %14s |\n" , "ПОБЕДА" , "ПОРАЖЕНИЕ" , "НИЧЬЯ" , "ВСЕГО ИГР" , "ПРОЦЕНТ ПОБЕД" ); // Вывод линии System . out . print ( "|" ); printDashes ( 10 ); System . out . print ( "+" ); printDashes ( 10 ); System . out . print ( "+" ); printDashes ( 10 ); System . out . print ( "+" ); printDashes ( 16 ); System . out . print ( "+" ); printDashes ( 18 ); System . out . println ( "|" ); // Вывод значений System . out . printf ( "| %6d | %6d | %6d | %12d | %13.2f%% |\n" , wins , losses , ties , numberOfGames , percentageWon * 100 ); // Вывод линии System . out . print ( "+" ); printDashes ( 68 ); System . out . println ( "+" ); }
-
14Начните игру. В основном классе инициализируйте объект
RockPaperScissors
и вызовите его методstartGame()
.
public static void main ( String [] args ) { RockPaperScissors game = new RockPaperScissors (); game . startGame (); }
-
15Протестируйте игру. Теперь, когда вся работа позади, настало время скомпилировать и протестировать нашу игру!Реклама
Пример программы
import
java.util.Random
;
import
java.util.Scanner
;
public
class
RockPaperScissors
{
private
User
user
;
private
Computer
computer
;
private
int
userScore
;
private
int
computerScore
;
private
int
numberOfGames
;
private
enum
Move
{
ROCK
,
PAPER
,
SCISSORS
;
/**
* Сравнивает текущий ход с переданным в параметре otherMove и определяет
* победу, поражение или ничью.
*
* @param otherMove
* ход, с которым сравнивается текущий
* @return 1 если текущий ход бьет другой, -1 если другой ход бьет текущий,
* 0 в случае ничьей
*/
public
int
compareMoves
(
Move
otherMove
)
{
// Ничья
if
(
this
==
otherMove
)
return
0
;
switch
(
this
)
{
case
ROCK
:
return
(
otherMove
==
SCISSORS
?
1
:
-
1
);
case
PAPER
:
return
(
otherMove
==
ROCK
?
1
:
-
1
);
case
SCISSORS
:
return
(
otherMove
==
PAPER
?
1
:
-
1
);
}
// Этот код не должен выполняться никогда
return
0
;
}
}
private
class
User
{
private
Scanner
inputScanner
;
public
User
()
{
inputScanner
=
new
Scanner
(
System
.
in
);
}
public
Move
getMove
()
{
// Выведем запрос на ввод
System
.
out
.
print
(
"Камень, ножницы или бумага? "
);
// Прочитаем ввод пользователя
String
userInput
=
inputScanner
.
nextLine
();
userInput
=
userInput
.
toUpperCase
();
char
firstLetter
=
userInput
.
charAt
(
0
);
if
(
firstLetter
==
'К'
||
firstLetter
==
'Н'
||
firstLetter
==
'Б'
)
{
// Ввод корректный
switch
(
firstLetter
)
{
case
'К'
:
return
Move
.
ROCK
;
case
'Н'
:
return
Move
.
PAPER
;
case
'Б'
:
return
Move
.
SCISSORS
;
}
}
// Ввод некорректный. Выведем запрос на ввод снова.
return
getMove
();
}
public
boolean
playAgain
()
{
System
.
out
.
print
(
"Хотите сыграть еще раз? "
);
String
userInput
=
inputScanner
.
nextLine
();
userInput
=
userInput
.
toUpperCase
();
return
userInput
.
charAt
(
0
)
==
'Y'
;
}
}
private
class
Computer
{
public
Move
getMove
()
{
Move
[]
moves
=
Move
.
values
();
Random
random
=
new
Random
();
int
index
=
random
.
nextInt
(
moves
.
length
);
return
moves
[
index
];
}
}
public
RockPaperScissors
()
{
user
=
new
User
();
computer
=
new
Computer
();
userScore
=
0
;
computerScore
=
0
;
numberOfGames
=
0
;
}
public
void
startGame
()
{
System
.
out
.
println
(
"КАМЕНЬ, НОЖНИЦЫ, БУМАГА!"
);
// Получение ходов
Move
userMove
=
user
.
getMove
();
Move
computerMove
=
computer
.
getMove
();
System
.
out
.
println
(
"\nВаш ход "
+
userMove
+
"."
);
System
.
out
.
println
(
"Ход компьютера "
+
computerMove
+
".\n"
);
// Сравнение ходов и определение победителя
int
compareMoves
=
userMove
.
compareMoves
(
computerMove
);
switch
(
compareMoves
)
{
case
0
:
// Ничья
System
.
out
.
println
(
"Tie!"
);
break
;
case
1
:
// Победил игрок
System
.
out
.
println
(
userMove
+
" beats "
+
computerMove
+
". Вы победили!"
);
userScore
++;
break
;
case
-
1
:
// Победил компьютер
System
.
out
.
println
(
computerMove
+
" beats "
+
userMove
+
". Вы проиграли."
);
computerScore
++;
break
;
}
numberOfGames
++;
// Предложим пользователю сыграть еще раз
if
(
user
.
playAgain
())
{
System
.
out
.
println
();
startGame
();
}
else
{
printGameStats
();
}
}
/**
* Вывод статистики. Ничьи учитываются как полпобеды
* при подсчете процента побед.
*/
private
void
printGameStats
()
{
int
wins
=
userScore
;
int
losses
=
computerScore
;
int
ties
=
numberOfGames
-
userScore
-
computerScore
;
double
percentageWon
=
(
wins
+
((
double
)
ties
)
/
2
)
/
numberOfGames
;
// Вывод линии
System
.
out
.
print
(
"+"
);
printDashes
(
68
);
System
.
out
.
println
(
"+"
);
// Вывод заголовков таблицы
System
.
out
.
printf
(
"| %6s | %6s | %6s | %12s | %14s |\n"
,
"WINS"
,
"LOSSES"
,
"TIES"
,
"GAMES PLAYED"
,
"PERCENTAGE WON"
);
// Вывод линии
System
.
out
.
print
(
"|"
);
printDashes
(
10
);
System
.
out
.
print
(
"+"
);
printDashes
(
10
);
System
.
out
.
print
(
"+"
);
printDashes
(
10
);
System
.
out
.
print
(
"+"
);
printDashes
(
16
);
System
.
out
.
print
(
"+"
);
printDashes
(
18
);
System
.
out
.
println
(
"|"
);
// Вывод значений
System
.
out
.
printf
(
"| %6d | %6d | %6d | %12d | %13.2f%% |\n"
,
wins
,
losses
,
ties
,
numberOfGames
,
percentageWon
*
100
);
// Вывод линии
System
.
out
.
print
(
"+"
);
printDashes
(
68
);
System
.
out
.
println
(
"+"
);
}
private
void
printDashes
(
int
numberOfDashes
)
{
for
(
int
i
=
0
;
i
<
numberOfDashes
;
i
++)
{
System
.
out
.
print
(
"-"
);
}
}
public
static
void
main
(
String
[]
args
)
{
RockPaperScissors
game
=
new
RockPaperScissors
();
game
.
startGame
();
}
}
Реклама