
Java Entwickler Experte
Wer von uns würde nicht das beliebte Spiel Stein, Papier, Schere kennen, das wir als Kinder gespielt haben. Aber wer hätte damals gedacht, dass er es eines Tages in seiner Lieblingsprogrammiersprache, zum Beispiel Java, programmieren könnte. Die wenigsten wissen, dass Rock, Paper, Scissors ein Handspiel ist, das seinen Ursprung in China haben soll, von wo aus es sich nach Japan verbreitet hat. Dort entstand es in seiner modernen Form, wie wir sie kennen, und zu Beginn des 20. Jahrhunderts hatte es sich sehr schnell über die ganze Welt verbreitet.
In diesem Artikel erfährst du:
Wir müssen uns die Spielregeln sicher nicht vorstellen. Aber falls es jemanden gibt, der es noch nicht kennt, werden wir sie kurz erwähnen. Es wird meist von zwei Spielern (oder mehr) gespielt, von denen jeder unbewusst entweder einen Stein, Papier oder eine Schere wählt. Auf das Kommando eins, zwei, drei zeigen beide Spieler gleichzeitig, was sie gewählt haben – Stein (geschlossene Faust) oder Schere (mit Zeige- und Mittelfinger) oder Papier (offene Hand). Das Ergebnis des Spiels, das natürlich über mehrere Runden gespielt wird, ist ein Unentschieden, ein Sieg oder eine Niederlage. Der Spieler, der den Stein spielt, schlägt den anderen Spieler, der die Schere wählt (der Stein stumpft die Schere ab), verliert aber gegen den Spieler, der das Papier spielt (das Papier umhüllt den Stein). Der Spieler mit dem Papier verliert gegen den Spieler, der die Schere gewählt hat (die Schere schneidet das Papier). Wenn beide Spieler die gleiche Form wählen, ist das Spiel unentschieden und wird normalerweise wiederholt, um das Unentschieden aufzulösen. Stein, Papier, Schere wird oft als Methode der fairen Auswahl zwischen Kindern verwendet, wenn es darum geht, welches Kind zuerst etwas anfangen darf. Wusstet ihr das schon? Für Rock, Paper, Scissors wurden auch schon verschiedene Turniere organisiert. Die Gewinner der Turniere haben zum Beispiel zwischen 5.000 und 20.000 Dollar mit nach Hause genommen.
Heute werden wir dieses Spiel gemeinsam in Java programmieren. Um das Spiel für die Spieler interessanter zu machen, werden wir auch eine künstliche Intelligenz (KI) programmieren, die nicht zufällig entscheidet, ob sie in jeder Runde Stein, Papier oder Schere benutzt, sondern in jeder Runde eine der Standardstrategien wählt. Natürlich hat der Spieler keine Ahnung, welche Geste die Computer-KI gerade gewählt hat.
Sie wollen bestimmt nicht Rock, Paper, Scissors mit einem Roboter spielen. Im Jahr 2012 haben Forscher des Ishikawa Watanabe Laboratory an der Universität von Tokio einen Roboterarm entwickelt, der jedes Spiel gegen einen menschlichen Gegner gewinnen kann. Mithilfe einer Hochgeschwindigkeitskamera erkennt der Roboter innerhalb einer Millisekunde, welche Form die menschliche Hand macht, und erstellt dann die entsprechende Siegerform.
Das Spiel wird über eine vordefinierte Anzahl von Runden gespielt, die bei der Erstellung der Spielinstanz festgelegt wird. Da die Spielrunden sehr schnell sind und wir das Verhalten der KI testen wollen, setzen wir den Standardwert für die Anzahl der Runden auf 20. Zu Beginn jeder Runde müssen wir die Auswahl des Spielers aufzeichnen, die KI-Strategie für diese Runde auswählen und die Auswahl des KI-Computers auf der Grundlage dieser Strategie bestimmen. Die KI wählt nach dem Zufallsprinzip aus den Standardstrategien aus, so dass es für den Spieler schwierig ist, zu bestimmen, welche Geste der Computer spielen wird. Wir prüfen dann, wer was gewählt hat und vergeben entsprechend Punkte, +1 für einen Sieg, 0 für ein Unentschieden oder eine Niederlage. Der erste Spieler, der 20 Punkte erreicht, gewinnt das Spiel.
Die künstliche Intelligenz des Spiels zeichnet die Gewinnergesten des Spielers auf und entscheidet auf der Grundlage der Historie, welche Geste gespielt werden soll. Zu den grundlegenden Strategien gehören:
Auch heute noch wird darüber diskutiert, welche Spielstrategie die beste ist. In unseren Artikeln versuchen wir, den Lesern etwas Neues beizubringen, ihnen zu zeigen, wie sie einige Probleme lösen können, und wir freuen uns am meisten, wenn sie anfangen, mit dem Programm zu experimentieren und sich ihre eigenen Spielstrategien auszudenken. Du kannst dich auch von diesem Video oder von diesem Artikel über Rempton-Spiele auf Englisch inspirieren lassen. Dann legen wir los und programmieren das Spiel in Java!
Das Strategy Entwurfsmuster eignet sich gut für die Implementierung von KI-Strategien. Bei diesem Programm handelt es sich um ein einfaches Konsolenspiel, bei dem der Spieler Stein, Papier oder Schere wählt und gegen den KI-Computer spielt, der in jeder Runde zufällig eine von vielen Strategien auswählt. Der Gewinner wird auf der Grundlage der Spielregeln ermittelt.
Enum Move
Die Enum Move definiert die möglichen Züge (Stein, Papier, Schere) und bietet Methoden zum Vergleich der Züge des Spielers und der KI sowie zur Bestimmung des besten Konterzugs für einen bestimmten Zug.
package games.rockpaperscissors;
public enum Move {
ROCK, PAPER, SCISSORS;
// Method to check who won
public static int compareMoves(Move player, Move ai) {
// Draw
if (player == ai) {
return 0;
}
switch (player) {
case ROCK:
// Rock beats Scissors, loses to Paper
return (ai == SCISSORS) ? 1 : -1;
case PAPER:
// Paper beats Rock, loses to Scissors
return (ai == ROCK) ? 1 : -1;
case SCISSORS:
// Scissors beats Paper, loses to Rock
return (ai == PAPER) ? 1 : -1;
}
return 0;
}
public static Move counterMove(Move move) {
switch (move) {
case ROCK:
return Move.PAPER;
case PAPER:
return Move.SCISSORS;
case SCISSORS:
return Move.ROCK;
}
throw new IllegalArgumentException();
}
}
Schnittstelle AIStrategy
Schnittstelle AIStrategy definiert eine nextMove()-Methode, die entscheidet, welchen Zug die KI basierend auf der Historie machen wird. Spezifische Strategien
Die KI hat verschiedene Strategien, die sie verwenden kann. Die Strategie wird vor jeder Runde nach dem Zufallsprinzip ausgewählt, was bedeutet, dass es für den Spieler schwierig ist, vorherzusagen, welchen Zug die KI wählen wird.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.List;
public interface AIStrategy {
Move nextMove(List<Move> playerHistory, List<Move> aiHistory);
}
Klasse RandomStrategy
Zufällige Auswahl einer Geste.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.List;
import java.util.Random;
public class RandomStrategy implements AIStrategy {
private final Random random = new Random();
@Override
public Move nextMove(List<Move> playerHistory, List<Move> aiHistory) {
return Move.values()[random.nextInt(Move.values().length)];
}
}
Klasse RepeatLastMoveStrategy
Das Wiederholen der letzten Geste des Spielers.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.List;
public class RepeatLastMoveStrategy implements AIStrategy {
@Override
public Move nextMove(List<Move> playerHistory, List<Move> aiHistory) {
return aiHistory.isEmpty()
? new RandomStrategy().nextMove(playerHistory, aiHistory)
: aiHistory.get(aiHistory.size() - 1);
}
}
Klasse CounterLastPlayerMoveStrategy
Ein Kontrazug zu einer Geste eines Spielers aus der vorherigen Runde.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.List;
public class CounterLastPlayerMoveStrategy implements AIStrategy {
@Override
public Move nextMove(List<Move> playerHistory, List<Move> aiHistory) {
if(!playerHistory.isEmpty()) {
Move lastPlayer = playerHistory.get(playerHistory.size() - 1);
return Move.counterMove(lastPlayer);
}
return new RandomStrategy().nextMove(playerHistory, aiHistory);
}
}
Klasse RepeatMostFrequentPlayerMoveStrategy
Wiederholt die Geste, die der Spieler am häufigsten verwendet hat.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RepeatMostFrequentPlayerMoveStrategy implements AIStrategy {
@Override
public Move nextMove(List<Move> playerHistory, List<Move> aiHistory) {
if(!playerHistory.isEmpty()) {
Map<Move, Integer> moveFrequency = new HashMap<>();
for(Move move : playerHistory) {
moveFrequency.put(move, moveFrequency.getOrDefault(move, 0) + 1);
}
return Collections.max(moveFrequency.entrySet(), Map.Entry.comparingByValue()).getKey();
}
return new RandomStrategy().nextMove(playerHistory, aiHistory);
}
}
Klasse CounterMostFrequentPlayerMoveStrategy
Der Gegenzug zu der Geste, die der Spieler am häufigsten verwendet hat.
package games.rockpaperscissors.ai.strategies;
import games.rockpaperscissors.Move;
import java.util.List;
public class CounterMostFrequentPlayerMoveStrategy implements AIStrategy {
@Override
public Move nextMove(List<Move> playerHistory, List<Move> aiHistory) {
if(!playerHistory.isEmpty()) {
Move mostFrequentMove = new RepeatMostFrequentPlayerMoveStrategy().nextMove(playerHistory, aiHistory);
// Counter the most frequent player's move
return Move.counterMove(mostFrequentMove);
}
return new RandomStrategy().nextMove(playerHistory, aiHistory);
}
}
RockPaperScissors Klasse
Klasse RockPaperScissorsGame implementiert die gesamte Spiellogik und verwaltet den Spielablauf, die Punkteaufzeichnung und die Strategieauswahl.
package games.rockpaperscissors;
import games.rockpaperscissors.ai.strategies.*;
import java.util.*;
public class RockPaperScissors {
private final int totalRounds;
private final List<Move> playerHistory = new ArrayList<>();
private final List<Move> aiHistory = new ArrayList<>();
private int playerScore = 0;
private int aiScore = 0;
private final List<AIStrategy> aiStrategies = Arrays.asList(
new RandomStrategy(),
new RepeatLastMoveStrategy(),
new CounterLastPlayerMoveStrategy(),
new RepeatMostFrequentPlayerMoveStrategy(),
new CounterMostFrequentPlayerMoveStrategy()
);
public RockPaperScissors(int totalRounds) {
this.totalRounds = totalRounds;
}
private Move getPlayerMove(int input) {
switch (input) {
case 1:
return Move.ROCK;
case 2:
return Move.PAPER;
case 3:
return Move.SCISSORS;
default:
Move playerMove = new RandomStrategy().nextMove(playerHistory, aiHistory);
System.out.println("Chybny vstup, vyberam za hraca: " + playerMove);
return playerMove;
}
}
public void play() {
Scanner scanner = new Scanner(System.in);
Random random = new Random();
while (playerScore < totalRounds && aiScore < totalRounds) {
System.out.println("Vyber si: (1) Kamen, (2) Papier, (3) Noznice");
Move playerMove = getPlayerMove(scanner.nextInt());
Move aiMove = aiStrategies.get(random.nextInt(aiStrategies.size()))
.nextMove(playerHistory, aiHistory);
System.out.println("HRAC vybral: " + playerMove);
System.out.println("AI vybrala: " + aiMove);
// Compare moves
int result = Move.compareMoves(playerMove, aiMove);
if (result > 0) {
System.out.println("Vyhral si toto kolo.");
playerScore++;
} else if (result < 0) {
System.out.println("AI vyhrala toto kolo.");
aiScore++;
}
// Record moves
playerHistory.add(playerMove);
aiHistory.add(aiMove);
System.out.println("Aktualne skore - Hrac: " + playerScore + " | AI: " + aiScore);
System.out.println();
}
if(playerScore >= totalRounds) {
System.out.println("Gratulujeme! Vyhral si tuto hru!");
}
else {
System.out.println("AI vyhrala tuto hru! Skus ju porazit.");
}
}
}
Klasse Main
import games.rockpaperscissors.RockPaperScissors;
public class Main {
public static void main(String[] args) {
RockPaperScissors game = new RockPaperScissors(20);
game.play();
}
}
Der Ausgang eines 3-Runden-Spiels kann wie folgt aussehen:
In diesem Java-Spiel spielt die künstliche Intelligenz sehr gut und es ist nicht so einfach, in einem Spiel mit mehreren Runden zu gewinnen. Hier kannst du den Quellcode von RockPaperScissors in Java herunterladen RockPaperScissors in Java Wenn du auf der Suche nach einem Job sind und ein Java-Programmierer bist, schau dir unsere Mitarbeitervorteile an und reagiere auf die neuesten Stellenausschreibungen.