构建一个游戏,其中两个玩家在具有不同策略的剪刀石头布游戏中竞争。谁会赢得更多回合?规则:
剪刀打败纸
剪刀打败石
剪刀打败石
如果两个玩家选择相同,则该回合计为平局。
实施两个玩家:
玩家A总是选择纸张
玩家B随机选择
游戏包括以上两名选手进行100轮比赛。程序的
输出应如下所示:
"Player A wins 31 of 100 games"
"Player B wins 37 of 100 games"
"Tie: 32 of 100 games"
这是我的解决方案:
动作:
import java.util.EnumMap;
import java.util.Map;
/**
* The moves of a {@link Game}
*
* @author ms
*
*/
public enum Move {
ROCK, PAPER, SCISSORS;
/**
* Holds the moves a move beats
*/
private static final Map<Move, Move> beats = new EnumMap<>(Move.class);
// init the beats
static {
beats.put(ROCK, SCISSORS);
beats.put(PAPER, ROCK);
beats.put(SCISSORS, PAPER);
}
/**
* Returns the move this move beats
*
* @param m
* The current move
* @return The move this move beats
*/
public static Move beats(final Move m) {
return beats.get(m);
}
}
玩家:
/**
* The superclass of all players
*
* @author ms
*
*/
public abstract class Player {
/**
* Generates the next move
*
* @return the next move
*/
public abstract Move getNextMove();
}
/**
* A player that always returns a {@link Move#PAPER} move
*
* @author ms
*
*/
public class PaperPlayer extends Player {
@Override
public Move getNextMove() {
return Move.PAPER;
}
}
import java.util.Random;
/**
* A player that always returns a random move
*
* @author ms
*
*/
public class RandomPlayer extends Player {
/**
* Caches all values of {@link Move} for the random generator
*/
private static final Move[] moves = Move.values();
/**
* The random number generator used; created once and then cached
*/
private final Random generator;
public RandomPlayer() {
generator = new Random();
}
@Override
public Move getNextMove() {
return moves[generator.nextInt(moves.length)];
}
}
游戏:
import java.lang.invoke.MethodHandles;
import java.util.EnumMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Game of rock-scissor-paper
*
* @author ms
*
*/
public class Game {
private static final int NUMBER_OF_GAMES = 100;
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/**
* An enum encapsulating the results of one move which also holds the strings needed for
* generating the output
*
* @author ms
*
*/
enum Result {
A_WINS("Player A wins "), B_WINS("Player B wins "), TIE("Tie: ");
private final String output;
private Result(String output) {
this.output = output;
}
public String getOutput() {
return output;
}
}
/**
* @param args
*/
public static void main(final String[] args) {
final Player playerA = new PaperPlayer();
final Player blayerB = new RandomPlayer();
final Map<Result, Integer> results = new EnumMap<>(Result.class);
initResults(results);
playGame(playerA, blayerB, results);
printResults(results);
}
/**
* Initialize the {@code results} map with 0 values
*
* @param results
* the inialized results map
*/
private static void initResults(final Map<Result, Integer> results) {
for (final Result r : Result.values()) {
results.put(r, 0);
}
}
/**
* Plays {@link #NUMBER_OF_GAMES} rounds of the game
*
* @param playerA
* A player
* @param blayerB
* A player
* @param results
* The results are stored here
* @see #playOneRoundOfTheGame(Player, Player, Map)
*/
private static void playGame(final Player playerA, final Player blayerB, final Map<Result, Integer> results) {
for (int i = 0; i < NUMBER_OF_GAMES; i++ ) {
playOneRoundOfTheGame(playerA, blayerB, results);
}
}
/**
* Plays one round of the game
*
* @param playerA
* A player
* @param blayerB
* A player
* @param results
* The results are stored here
* @see #playGame(Player, Player, Map)
*/
private static void playOneRoundOfTheGame(final Player playerA, final Player blayerB,
final Map<Result, Integer> results) {
final Move moveA = playerA.getNextMove();
final Move moveB = blayerB.getNextMove();
final Result result = evaluateMoves(moveA, moveB);
logger.debug("A: {}, B: {}. result: {}", moveA, moveB, result);
results.put(result, results.get(result) + 1);
}
/**
* Evaluates one round of the game
*
* @param moveA
* The move of one player
* @param moveB
* The move of another player
* @return The {@link Result}
*/
static Result evaluateMoves(final Move moveA, final Move moveB) {
final Result result;
if (Move.beats(moveA) == moveB) {
result = Result.A_WINS;
}
else {
if (Move.beats(moveB) == moveA) {
result = Result.B_WINS;
}
else {
result = Result.TIE;
}
}
return result;
}
/**
* Prints the results
*
* @param results
* The results
*/
private static void printResults(final Map<Result, Integer> results) {
for (final Result r : Result.values()) {
System.out.printf("%s %d of %d games%n", r.getOutput(), results.get(r), NUMBER_OF_GAMES);
}
}
}
测试:
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import Game.Result;
import static org.assertj.core.api.Assertions.*;
/**
* @author ms
*
*/
@RunWith(Parameterized.class)
public class GameTest {
@Parameters
public static Iterable<Object[]> testData() {
return Arrays.asList(new Object[][] { { Move.ROCK, Move.ROCK, Result.TIE },
{ Move.ROCK, Move.PAPER, Result.B_WINS }, { Move.ROCK, Move.SCISSORS, Result.A_WINS },
{ Move.PAPER, Move.PAPER, Result.TIE }, { Move.PAPER, Move.ROCK, Result.A_WINS },
{ Move.PAPER, Move.SCISSORS, Result.B_WINS }, { Move.SCISSORS, Move.SCISSORS, Result.TIE },
{ Move.SCISSORS, Move.ROCK, Result.B_WINS }, { Move.SCISSORS, Move.PAPER, Result.A_WINS }, });
}
@Parameter(0)
public Move moveA;
@Parameter(1)
public Move moveB;
@Parameter(2)
public Result expectedResult;
/**
* Test method for
* {@link Game#evaluateMoves(Move, Move)}
* .
*/
@Test
public void testEvaluateMoves() throws Exception {
assertThat(Game.evaluateMoves(moveA, moveB)).isEqualTo(expectedResult);
}
}
游戏逻辑(一拍一拍)保持一体位置(Move的
定义),可以轻松地将规则替换为例如
剪刀石头布-蜥蜴-spock
缺点:
组件的命名感觉太琐碎了
主循环在Game.playGame中可能可以使用Java8转换为Streams / Lambdas,但这会使收集结果更加困难
仅测试移动的评估,因为这是唯一的平凡的代码
#1 楼
但是我仍然对Java8 / Streams解决方案感兴趣。 – @MartinSchröder
嘿...这是表演时间!
Move
enum Move {
ROCK, PAPER, SCISSORS;
boolean beats(Move another) {
switch (this) {
case ROCK:
return another == SCISSORS;
case PAPER:
return another == ROCK;
case SCISSORS:
return another == PAPER;
// note: see alternative below
default:
throw new IllegalStateException();
}
// alternatively, just throw here without the default case
// throw new IllegalStateException();
}
}
如@tim和@OldCurmudgeon所建议,如果
Move
知道自己是否击败了另一个Move
,则更好,而不是将其委托给static
方法。但是,我的方法有所不同,原因是要使用switch
语句而不是依赖static Map
,这有两个原因: 任何优秀的IDE都会建议您为所有
case
值添加enum
。如果Lizard和Spock拜访了您的游戏,则
Map
解决方案将需要大量的重新设计,相反,对于初学者来说,重构switch
语句以谨慎地照顾它们至少更容易些。好的IDE还会提示您为新的throw
值添加IllegalStateException
子句,并且仍然会引发异常。case
enum Player implements Iterator<Move> {
A() {
@Override
public Move next() {
return Move.PAPER;
}
}, B() {
@Override
public Move next() {
return Move.values()[GENERATOR.nextInt(Move.values().length)];
}
};
private static final Random GENERATOR = new Random();
@Override
public boolean hasNext() {
return true;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
@OldCurmudgeon的答案实际上是使用
enum
接口对此实现进行了修订,但是由于某种原因,它不再存在。无论如何,我选择将其建模为Player
,因为我们知道RPS中通常只有两个参与者(打折所有硬核MMORPS-我刚刚弥补了这一点),并且在问题中也对此进行了明确定义。 我也可以在常见的
Iterator
方法实现中执行enum
,但是我想我将使用一种替代方法进行更改。另一点需要注意的是switch
方法中的next()
的throw
-ing:这只是一个好形式。UnsupportedOperationException()
private static final class Round {
private final Move aMove;
private final Move bMove;
private Round(Move aMove, Move bMove) {
this.aMove = aMove;
this.bMove = bMove;
}
public Optional<Player> getWinner() {
return aMove == bMove ? Optional.empty() :
Optional.of(aMove.beats(bMove) ? Player.A : Player.B);
}
public static Round of(Player aPlayer, Player bPlayer) {
if (aPlayer.hasNext() && bPlayer.hasNext()) {
return new Round(aPlayer.next(), bPlayer.next());
}
throw new NoSuchElementException("No more moves by player "
+ (aPlayer.hasNext() ? Player.B : Player.A));
}
}
现在,这是我在建模上有显着差异的地方,也是第一个Java 8功能
remove()
出现的地方。韩元。这意味着给定一个Round
,一个人不知道什么是导致结果的输入。缺点是:必须将
Optional
及其表示形式分别建模为Result
(请参阅Result
/ Player
和Result
/ PaperPlayer
)。更多的代码,如果我想更改播放器的策略,名称或将外部输入映射到移动中,则需要更改更多的地方。
一旦捕获结果,就会丢失输入。
随后,您将无法重玩游戏。
由于无法重新计算分数,因此也很容易躺在代码中。
因此,我继续捕捉了游戏回合的输入,简称为
Result.A_WINS
。它捕获的全部都是动作,然后调用RandomPlayer
然后应用上述函数给我们一个Result.B_WINS
。赢了,还是有平局。这使我可以方便地取消使用Round
和显式执行getWinner()
-checks的工作,或者不必为三值Optional<Player>
添加代码来模拟平局场景。我将在稍后再讨论这一点,如果您考虑一下,平局情况本身也是两个玩家都不获胜的结果。因此,在找出游戏中的平局数目时,由于可以计算出值,因此并没有硬性要求以平局表示形式存储。Optional
内部进行了轻度的检查null
方法,以充分利用实现null
接口的enum
类。 解决方案的另一件事:对每个
static
值使用of()
实际上只是显示结果时要使用的必需前缀。因此,如果需求发生变化,则几乎没有灵活性:名称或模式的更改。Player
public final class Game {
private static final int NUMBER_OF_GAMES = 100;
private static final Logger logger = LoggerFactory.getLogger(Game.class);
private static Map<Player, Long> play() {
return Stream.generate(() -> Round.of(Player.A, Player.B))
.limit(NUMBER_OF_GAMES)
.map(Round::getWinner)
.filter(Optional::isPresent)
.collect(Collectors.groupingBy(Optional::get,
() -> new EnumMap<>(Player.class), Collectors.counting()));
}
public static void main(String[] args) {
Map<Player, Long> results = Game.play();
int wins = results.values().stream().mapToInt(Long::intValue).sum();
results.forEach((k, v) -> logger.info("Player {} wins {} of {} games", k, v,
Integer.valueOf(NUMBER_OF_GAMES)));
logger.info("Tie: {} of {} games", Integer.valueOf(NUMBER_OF_GAMES - wins),
Integer.valueOf(NUMBER_OF_GAMES));
}
}
Iterator
为我们提供了output
的无限连续流对我们来说,是基于调用Result
构造的。 这可以通过调用
Game
来限制。 然后我们必须通过调用
Stream.generate()
-ping来查询每个Round
的优胜者,方法是参考其Round.of(Player, Player)
方法参考。 现在,由于这实际上是一个
limit(NUMBER_OF_GAMES)
包装器,因此我们可以通过调用Round
方法(同样是另一个方法参考)来调用map()
。 最后,我们通过使用适当的参数执行
getWinner
来赢家,记住要先在Optional
包装器上调用filter()
才能访问底层获胜的isPresent()
。我们可以在致电collect()
之后首先计算获胜次数。这是通过在调用groupingBy()
时返回的get()
上执行Optional
来完成的。要显示所需的结果,我们只需要在Player
上执行main()
并相应地“消耗”键和值即可。最后一行显示了我们的联系数量。#2 楼
我喜欢您的代码,它的代码大部分都可读性强且结构良好。static Result evaluateMoves(final Move moveA, final Move moveB) {
if (Move.beats(moveA) == moveB) {
return Result.A_WINS;
} else if (Move.beats(moveB) == moveA) {
return Result.B_WINS;
} else {
return Result.TIE;
}
}
我也会考虑重组
evaluateMoves
枚举,以便您可以编写更好的if-elseif
。这也将允许添加比石头,纸张和石头更容易的其他对象。将其移至调用类,或者-为获得更清晰的代码-创建单独的if-else-if
类,其中包含当前与Move
混合在一起的所有代码(例如初始化,添加等)。像if (moveA.beats(moveB))
这样的东西会比playOneRoundOfTheGame
好很多。评论
\ $ \ begingroup \ $
您可以省略其他。
\ $ \ endgroup \ $
– Heslacher
15年5月12日在9:38
\ $ \ begingroup \ $
您也可以只对前两个条件使用两个单if语句,因为无论如何,当条件为真时从方法中返回,然后@heslacher会说:省略最后一个。这样就变成:如果(a)返回a_win,如果(b)返回b_win,则返回平局。
\ $ \ endgroup \ $
–孩子钻石
15年5月12日在10:04
\ $ \ begingroup \ $
谢谢。是的,Move.beats应该不是静态的。但是我仍然对Java8 / Streams解决方案感兴趣。
\ $ \ endgroup \ $
–马丁·施罗德(MartinSchröder)
15年5月12日在10:23
#3 楼
这是写得很好并且经过深思熟虑的代码。我会回应其他人的建议。
使您的
Move
枚举具有beats
方法。使一个可以维持结果的
Results
对象。这里是我修补后剩下的内容。因此,这可能不是一个理想的解决方案,但这是一个适度的流版本。 >
大多数流式传输是通过
Play
方法实现的。/**
* The moves of a {@link Game}
*
* @author ms
*
*/
public enum Move {
ROCK, PAPER, SCISSORS;
/**
* Holds the moves a move beats
*/
private static final Map<Move, Move> beats = new EnumMap<>(Move.class);
// init the beats
static {
beats.put(ROCK, SCISSORS);
beats.put(PAPER, ROCK);
beats.put(SCISSORS, PAPER);
}
/**
* Returns true if this move beats
*
* @param other move to compare with.
*
* @return true if this move beats the other.
*/
public boolean beats(Move other) {
return beats.get(this) == other;
}
}
/**
* The superclass of all players
*
* @author ms
*
*/
public abstract static class Player {
/**
* Generates the next move
*
* @return the next move
*/
public abstract Move getNextMove();
}
/**
* A player that always returns a {@link Move#PAPER} move
*
* @author ms
*
*/
public static class PaperPlayer extends Player {
@Override
public Move getNextMove() {
return Move.PAPER;
}
}
/**
* A player that always returns a random move
*
* @author ms
*
*/
public static class RandomPlayer extends Player {
/**
* Caches all values of {@link Move} for the random generator
*/
private static final Move[] moves = Move.values();
/**
* The random number generator used; created once and then cached
*/
private final Random generator;
public RandomPlayer() {
generator = new Random();
}
@Override
public Move getNextMove() {
return moves[generator.nextInt(moves.length)];
}
}
/**
* A Game of rock-scissor-paper
*
* @author ms
*
*/
public static class Game {
private static final int NUMBER_OF_GAMES = 100;
/**
* An enum encapsulating the results of one move which also holds the strings needed for generating the output
*
* @author ms
*
*/
enum Result {
A_WINS("Player A wins "), B_WINS("Player B wins "), TIE("Tie: ");
private final String output;
private Result(String output) {
this.output = output;
}
public String getOutput() {
return output;
}
}
private static class Results {
final ConcurrentMap<Result, Integer> results = new ConcurrentHashMap<>(new EnumMap<>(Result.class));
private void result(Result result) {
// Add one (to 0 if it's not present.
results.put(result, results.computeIfAbsent(result, x -> 0) + 1);
}
@Override
public String toString() {
StringBuilder s = new StringBuilder();
for (final Result r : Result.values()) {
s.append(r.getOutput())
.append(results.get(r)).append(" of ")
.append(NUMBER_OF_GAMES)
.append("\r\n");
}
return s.toString();
}
}
/**
* @param args
*/
public static void main(final String[] args) {
final Player playerA = new PaperPlayer();
final Player blayerB = new RandomPlayer();
final Results results = new Results();
playGame(playerA, blayerB, results);
System.out.println(results);
}
/**
* Plays {@link #NUMBER_OF_GAMES} rounds of the game
*
* @param playerA A player
* @param blayerB A player
* @param results The results are stored here
* @see #playOneRoundOfTheGame(Player, Player, Map)
*/
private static void playGame(final Player playerA, final Player blayerB, Results results) {
for (int i = 0; i < NUMBER_OF_GAMES; i++) {
playOneRoundOfTheGame(playerA, blayerB, results);
}
}
/**
* Plays one round of the game
*
* @param playerA A player
* @param blayerB A player
* @param results The results are stored here
* @see #playGame(Player, Player, Map)
*/
private static void playOneRoundOfTheGame(final Player playerA, final Player blayerB,
Results results) {
final Move moveA = playerA.getNextMove();
final Move moveB = blayerB.getNextMove();
final Result result = evaluateMoves(moveA, moveB);
//logger.debug("A: {}, B: {}. result: {}", moveA, moveB, result);
results.result(result);
}
/**
* Evaluates one round of the game
*
* @param moveA The move of one player
* @param moveB The move of another player
* @return The {@link Result}
*/
static Result evaluateMoves(final Move moveA, final Move moveB) {
final Result result;
if (moveA.beats(moveB)) {
result = Result.A_WINS;
} else if (moveB.beats(moveA)) {
result = Result.B_WINS;
} else {
result = Result.TIE;
}
return result;
}
}
public void test() {
Game.main(null);
}
您的计划成功了!效果很好。
/**
* A Game of rock-scissor-paper
*
* @author ms
*
*/
public static class Game {
private static final int NUMBER_OF_GAMES = 100;
/**
* An enum encapsulating the results of one move which also holds the strings needed for generating the output
*
* @author ms
*
*/
enum Result {
A_WINS("Player A wins "), B_WINS("Player B wins "), TIE("Tie: ");
private final String output;
private Result(String output) {
this.output = output;
}
public String getOutput() {
return output;
}
}
/**
* @param args
*/
public static void main(final String[] args) {
final Player playerA = new PaperPlayer();
final Player blayerB = new RandomPlayer();
playGame(playerA, blayerB);
}
/**
* Represents one play of the game.
*/
private static class Play {
final Move a;
final Move b;
public Play(Move a, Move b) {
this.a = a;
this.b = b;
}
}
/**
* Evaluates one round of the game
*
* @param moveA The move of one player
* @param moveB The move of another player
* @return The {@link Result}
*/
static Result evaluateMove(final Move moveA, final Move moveB) {
final Result result;
if (moveA.beats(moveB)) {
result = Result.A_WINS;
} else if (moveB.beats(moveA)) {
result = Result.B_WINS;
} else {
result = Result.TIE;
}
return result;
}
/**
* Plays {@link #NUMBER_OF_GAMES} rounds of the game
*
* @param playerA A player
* @param playerB A player
* @param results The results are stored here
*/
private static void playGame(final Player playerA, final Player playerB) {
Map<Result, Long> results = IntStream.range(0, NUMBER_OF_GAMES)
// Make one play per round.
.mapToObj(i -> new Play(playerA.next(), playerB.next()))
// Evaluate that move to a Result
.map(p -> evaluateMove(p.a, p.b))
// Count each result
.collect(Collectors.groupingBy(r -> r, Collectors.counting()));
// Print them.
printResults(results);
}
/**
* Prints out the results.
*
* @param results
*/
private static void printResults(Map<Result, Long> results) {
StringBuilder s = new StringBuilder();
for (final Result r : Result.values()) {
s.append(r.getOutput())
.append(results.get(r)).append(" of ")
.append(NUMBER_OF_GAMES)
.append("\r\n");
}
System.out.println(s);
}
}
public void test() {
Game.main(null);
}
评论
\ $ \ begingroup \ $
谢谢。尽管恕我直言,Result.result不是一个很好的名字。 Result.toString是Streams的主要候选对象。
\ $ \ endgroup \ $
–马丁·施罗德(MartinSchröder)
2015年5月12日15:40
\ $ \ begingroup \ $
@MartinSchröder-尝试将收集器放入结果中-仍然有点像新手,但是他们渴望练习。
\ $ \ endgroup \ $
–OldCurmudgeon
2015年5月12日15:44
\ $ \ begingroup \ $
更新-更加流化了。
\ $ \ endgroup \ $
–OldCurmudgeon
2015年5月12日15:58
\ $ \ begingroup \ $
直到现在我还没有意识到这一点,但是Lizard和Spock不会在这里玩得开心,因为您不能有重复的键(例如beats.put(SPOCK,SCISSORS); beats.put(SPOCK,岩石);)
\ $ \ endgroup \ $
– h.j.k.
15年5月13日在1:04
\ $ \ begingroup \ $
@ h.j.k。 -好话-我已将其更改为Map
\ $ \ endgroup \ $
–OldCurmudgeon
15年5月13日在8:08
#4 楼
您的解决方案不错,但是可以更短一些,并表示为一个函数从0-2枚举选择
(0: rock, 1: paper, 2: scissors)
从0枚举分数列-2
(0: Tie, 1: Player A, 2: Player B)
瞧,该函数用于确定回合点应该到达的位置:
int [] choices = {0,1,2}; // Rock, Paper, Scissors
int [] players = {0,1,2}; // Tie, Player A, Player B
int [] scores = {0,0,0}; // Scores table
int playerAChoice = ...; //get input from player A
int playerBChoice = ...; //get input from player B
//3 choices with wraparound effect
int winner_index = (3 + playerAChoice - playerBChoice) % 3
scores[winner_index] += 1;
编辑:为什么我选择建议此解决方案而不是枚举。石头剪刀布是平衡游戏类型的子类型,其中每种武器(例如,石头/剪刀/剪刀)与其他所有武器都击败相同数量的武器。例如,可以使用“蜥蜴spock”进行扩展。
如果您要使用枚举对此进行建模...这将是一个乏味且容易出错的过程。您必须从字面上复制/粘贴每个游戏的规则,而且它也不是很灵活。
现在,如果要用数学来计算,则这要简单得多。实际上,我为剪刀石头布指定的规则甚至可以进一步推广。任何此类游戏的规则均可按以下方式建模(来源:rospedambo上有关其他武器的维基百科):
Alternatively, the rankings in rock-paper-scissors-Spock-lizard may be modeled
by a comparison of the parity of the two choices. If it is the same (two odd
numbered moves or two even-numbered ones) then the lower number wins, while if
they are different (one odd and one even) the higher wins.
枚举在Java中有其位置,但洞察力也是如此您实际上正在解决的问题。
评论
\ $ \ begingroup \ $
不。Java具有枚举,类型比int和array多。这不是C99。
\ $ \ endgroup \ $
–马丁·施罗德(MartinSchröder)
15年5月12日在11:18
\ $ \ begingroup \ $
显然。但是RockPaperScissorsEnterprise并非总是必需的(请参阅:github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition)
\ $ \ endgroup \ $
– Arnab Datta
15年5月12日在11:20
\ $ \ begingroup \ $
我同意@MartinSchröder。我们也可以将选择称为啤酒,球员大象和得分,我们可以称之为粉红色。代码仍然有效,但可读性在哪里?
\ $ \ endgroup \ $
– chillworld
15年5月12日在12:21
\ $ \ begingroup \ $
@chillworld我不同意可读性问题。很明显,代码接受了输入选择并评估了获胜者……并相应地更新了分数。让数学表达式计算+1的位置而不是硬编码诸如:Move.ROCK,Move.ROCK,Result.TIE这样的东西真的更糟吗?
\ $ \ endgroup \ $
– Arnab Datta
15年5月12日在12:58
\ $ \ begingroup \ $
Java中的(-1)%3给出-1而不是2。
\ $ \ endgroup \ $
– MarcDefiant
15年5月12日在15:08
评论
\ $ \ begingroup \ $
很好。只需注意:我将移动默认值:抛出新的IllegalStateException();如果您添加了新的枚举值,则将收到警告(无论如何您都会获得异常)。
\ $ \ endgroup \ $
– maaartinus
15年5月13日在0:19
\ $ \ begingroup \ $
@maaartinus不错的建议,将包括在其中。:)
\ $ \ endgroup \ $
– h.j.k.
2015年5月13日,0:53
\ $ \ begingroup \ $
我特别喜欢您使用Player工具实现Iterator
\ $ \ endgroup \ $
–OldCurmudgeon
15年5月13日在8:17
\ $ \ begingroup \ $
如果Round在单独的文件中,则不能为private static。
\ $ \ endgroup \ $
–马丁·施罗德(MartinSchröder)
15年5月18日在13:18
\ $ \ begingroup \ $
另一个要求:我需要测试。目前,我可以测试Move,但是显然有人希望测试Round和Game。任何想法如何添加测试?
\ $ \ endgroup \ $
–马丁·施罗德(MartinSchröder)
15年5月18日在13:19