Random()
随机生成的0-9之间的4位数字,这4位数字彼此不同,没有重复的数字。用户尝试了5次猜测,每一次失败(几乎正确)的猜测都会告诉用户正确的部分。您认为这对用户来说太难还是太容易猜测?我还需要对此代码进行一些审查。也许其中一些可以简化?
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Game {
public static void main(String[] args) {
System.out.println("The computer has generate a unique 4 digit number.\n"
+ "You can try to guess the 4 digits number in 5 attempts.\n");
System.out.println("_______________________________________________________\n");
int[] random=numberGenerator();
int maxTry=5;
int indexMatch=0;
int match=0;
while(maxTry>0 && indexMatch!=4){
int[] guess=getGuess();
indexMatch=0;
match=0;
for(int i=0;i<guess.length;i++){
if(guess[i]==random[i]){
indexMatch++;
}
else if(guess[i]==random[0] || guess[i]==random[1] || guess[i]==random[2] || guess[i]==random[3]){
match++;
}
}
if(indexMatch==4){
System.out.print("Well done! Your guess is Correct! The number is: ");
for(int i=0;i<guess.length;i++){
System.out.print(guess[i]);
}
}
else{
maxTry--;
if(maxTry>1){
System.out.println("You have guess "+indexMatch+" correct number in correct position,"+
" and "+match+" correct number in incorrect position. \n"+maxTry+" attempt remaining.");
}
else if(maxTry==1){
System.out.println("You have guess "+indexMatch+" correct number in correct position,"+
" and "+match+" correct number in incorrect position. \nLast attempt!. Good luck");
}
else{
System.out.println("Sorry, you failed to guess the number in 5 attempts.");
System.out.print("The number is: ");
for(int i=0;i<random.length;i++){
System.out.print(random[i]);
}
}
}
}
}
public static int[] getGuess(){
Scanner keyboard = new Scanner(System.in);
System.out.println("Please enter your guess: ");
String input = keyboard.nextLine();
if(input.length()!=4 || input.replaceAll("\D","").length()!=4){
System.out.println("Invalid number. You must enter 4 digits between 0-9 only.");
return getGuess();
}
int[] guess = new int[4];
for (int i = 0; i < 4; i++) {
guess[i] = Integer.parseInt(String.valueOf(input.charAt(i)));
}
return guess;
}
public static int[] numberGenerator() {
Random randy = new Random();
int[] randArray = {10,10,10,10};
for(int i=0;i<randArray.length;i++){
int temp = randy.nextInt(9);
while(temp == randArray[0] || temp == randArray[1] || temp == randArray[2] || temp == randArray[3]){
temp=randy.nextInt(9);
}
randArray[i]=temp;
}
return randArray;
}
}
#1 楼
我不会评论随机数的生成,变量命名或一般的代码结构-您在上面的内容中提供了足够的信息。但是,这是我的两分钱,“这太难了吗?”您的问题的一部分。
您描述的游戏曾经被称为“牛和牛”,并且
事实证明,任何数字都可以解决多达七个回合。
最小平均游戏时间为26274/5040 = 5.2131转。
参考文献:http://fourdigits.sourceforge.net,http://www.cs.nccu。 edu.tw/~chaolin/papers/science3203.pdf
所以是的,只有四个猜测很难。五个猜测给您带来更少的机会,六个比给您带来更好的机会。
如果您尝试使用计算机解决游戏问题,通常希望找到使最大有效数最小化的猜测剩下的组合。原来,如果您从猜测开始
1234
您可以得到的“最差答案”是
1 white peg (one number correct, in the wrong location)
这将为您提供1440种可能的组合(4个数字中的任何一个都可能是带有白色钉的数字,但位置不正确。这使您在三个位置中的每一个中都有4个可能的数字,乘以6x5x4其他三个未结头寸(必须用一个尚未使用的数字来填补)。
您实际上可以列出所有可能的组合,并“划掉”那些组合。轮流放进去;将其与“如果我猜为abcd,且响应为[x白色,y黑色],还剩下多少组合?”相结合,然后再次选择使该数字最小化的猜测。一台计算机。
代码中的另一个错误
在某些情况下,最好的猜测是“非法”的-也就是说,您要求的组合是与您所掌握的信息不一致 至今。它甚至可以包含加倍的数字-例如
1123
您必须确保您的代码正确处理了该输入。这样做的方法是稍微更改测试循环-而不是
for(int i=0;i<guess.length;i++){
if(guess[i]==random[i]){
indexMatch++;
}
else if(guess[i]==random[0] || guess[i]==random[1] || guess[i]==random[2] || guess[i]==random[3]){
match++;
}
}
您需要
for(int i=0;i<guess.length;i++)
if(guess[i]==random[i]){
indexMatch++;
}
else if( random[i] == guess[0] || random[i] == guess[1] || random[i] == guess[2] || random[i] == guess[3]){
match++;
}
}
看看如果随机代码是
1234
而猜测是
3132
正确的答案会发生什么?将是“一个黑色,两个白色”。但是您的代码将给出“一个黑色,三个白色”,因为猜测中重复的三个被计算了两次。通过切换测试,随机数中的每个值都只会被查看一次-而这一切都不同。
#2 楼
由于问题的这一部分到目前为止已被跳过,我将接受它:您认为这太难了吗?
我认为是。与您的游戏类似,在经典的Mastermind中,玩家必须猜测4个非唯一彩色钉子的组合,并且每次都会给正确位置和颜色组合的数量打上标记。
64 = 1,296种可能的组合
但是,在您的游戏中(借用术语),有10种可能的钉,并且由于它们是唯一的,组合是:
10 x 9 x 8 x 7 = 5,040种可能的组合
增加288.8%,此外,您只给用户5次尝试猜测的机会,而与Mastermind的6、8或12相反。策划大师至少要打六局,就是要测试每种组合,例如:
但是,当您将可能性增加到10并减少时,对5的猜测,您将无法再执行此操作,因此永远不会猜对正确数字的机会急剧增加,例如:
因此,我认为您需要要么增加猜测数量至少为10(或至少10个),或者选择较小的一组猜测对象,例如A-F,1-6或基于Mastermind的GUI。
#3 楼
现在仅关注一个特定点:int temp = randy.nextInt(9);
这将永远不会生成数字
9
。 如果要生成0到9之间的数字(包括10个不同的数字),则需要执行以下操作:
int temp = randy.nextInt(10);
如果想要排除0(在这种情况下可能是合理的...。):
int temp = randy.nextInt(9) + 1;
评论
\ $ \ begingroup \ $
ouch,我真的很想念这个!谢谢。包含0,所以我将使用nextInt(10)
\ $ \ endgroup \ $
–婴儿
2014年1月24日7:12
\ $ \ begingroup \ $
您也不需要循环。您可以将数字0-9放入列表中,将列表随机排序,然后从列表中获取前四个条目。
\ $ \ endgroup \ $
–大卫·康拉德(David Conrad)
2014年1月27日在16:49
#4 楼
较少关注功能,而更多关注术语:我不会将您的new Random()
称为randy
。尽管名称很清楚,但randy一词的含义还不成熟。您永远都不知道谁会看到您的源代码,因此,如果您的任何客户看到的代码中的变量名或注释都有些不成熟,他们可能会认为您的不成熟扩展到了功能,即使它没有。因此而不是
Random randy = new Random();
写
Random rand = new Random();
通常,避免使用不成熟的词,即同事,公司或产品或外语单词,除非您要使用的单词与该变量的用途相关。
EPAComplianceCheck()
是可以接受的。 ScrewYouGinaMcCarthy()
少一些。评论
\ $ \ begingroup \ $
哈哈。好吧,实际上我也觉得这很有趣。我只是忘了在发布之前更改所有这些变量的名称。不管怎么说,还是要谢谢你!
\ $ \ endgroup \ $
–婴儿
2014年1月24日上午11:45
\ $ \ begingroup \ $
令人惊讶的是,人们在代码中放了多少个小玩笑然后忘记了……直到不该看到的人看到了它们。
\ $ \ endgroup \ $
– Tim B
2014年1月24日13:17
#5 楼
在getGuess()
中,Integer.parseInt(String.valueOf(input.charAt(i)))
可以写为
Character.digit(input.charAt(i), 10)
。在
getGuess()
中,验证失败时重新进行是不适当的。 (按住Enter键会使堆栈溢出!)请改用循环:public static int[] getGuess(){
Scanner keyboard = new Scanner(System.in);
do {
System.out.print("Please enter your guess: ");
String input = keyboard.nextLine();
if (input.matches("\d{4}")) break;
System.out.println("Invalid number. You must enter 4 digits between 0-9 only.");
} while (true);
int[] guess = new int[4];
for (int i = 0; i < guess.length; i++) {
guess[i] = Character.digit(input.charAt(i), 10);
}
return guess;
}
在
numberGenerator()
中,将while循环更改为do-while。 />评论
\ $ \ begingroup \ $
酷。 Character.digit()对我来说是新事物。大约一会儿,嗯,是的,我想你是对的
\ $ \ endgroup \ $
–婴儿
2014年1月24日在7:34
\ $ \ begingroup \ $
如何使用do-while验证用户输入?我以为递归很简单。
\ $ \ endgroup \ $
–婴儿
2014年1月24日8:30
\ $ \ begingroup \ $
@RafaEl从概念上讲是{prompt(); input = getInput(); while(!isValid(input));
\ $ \ endgroup \ $
–棘轮怪胎
2014年1月24日在8:44
\ $ \ begingroup \ $
好的,那确实很有意义。并感谢您使用的正则表达式(“ \\ d {4}”)更加简短。
\ $ \ endgroup \ $
–婴儿
2014年1月24日8:53
\ $ \ begingroup \ $
@Tibos我不知道执行尾部调用优化的任何Java实现。
\ $ \ endgroup \ $
– 200_success
2014年1月24日15:47
#6 楼
首先出发:public class Game {
真的吗?这是什么游戏?这是俄罗斯方块之类的东西吗?使其类似于
CodeGuessGame
,并向该类添加javadoc注释,以准确解释其含义和作用。System.out.println("The computer has generate a unique 4 digit number.\n"
+ "You can try to guess the 4 digits number in 5 attempts.\n");
除了拼写错误之外,您不应该这样做该行的末尾有
\n
,因为您使用的是println
。就我个人而言,我总是将我的\n
放在每条连续行的开头,但这并不是完全必要。 System.out.println("_______________________________________________________\n");
再次,额外的
\n
。我个人建议使用连字符(-
)或等号(=
),因为连字符在创建水平规则时更为常见。下划线表示用户应键入的空格。 int[] random = numberGenerator();
int maxTry = 5;
int indexMatch = 0;
int match = 0;
为了简洁起见,应将
maxTry
,indexMatch
和match
的声明合并为一个语句。 while(maxTry>0 && indexMatch!=4){
int[] guess=getGuess();
indexMatch=0;
match=0;
for(int i=0;i<guess.length;i++){
if(guess[i]==random[i]){
indexMatch++;
}
else if(guess[i]==random[0] || guess[i]==random[1] || guess[i]==random[2] || guess[i]==random[3]){
match++;
}
}
if(indexMatch==4){
System.out.print("Well done! Your guess is Correct! The number is: ");
for(int i=0;i<guess.length;i++){
System.out.print(guess[i]);
}
}
else{
maxTry--;
if(maxTry>1){
System.out.println("You have guess "+indexMatch+" correct number in correct position,"+
" and "+match+" correct number in incorrect position. \n"+maxTry+" attempt remaining.");
}
else if(maxTry==1){
System.out.println("You have guess "+indexMatch+" correct number in correct position,"+
" and "+match+" correct number in incorrect position. \nLast attempt!. Good luck");
}
else{
System.out.println("Sorry, you failed to guess the number in 5 attempts.");
System.out.print("The number is: ");
for(int i=0;i<random.length;i++){
System.out.print(random[i]);
}
}
}
}
}
该给我们这个shpaghetti吗?请学习使用
System.out.format
和三元运算(condition?valueIfTrue:valueIfFalse
)。至此,我不再忍受阅读您的代码了。请编写一个新程序,并在编写时考虑到可配置性和可重用性。
游戏应作为单独的实例运行。 main方法不应包含任何与实际游戏有关的逻辑。它要做的就是(1)初始化
Game
,(2)设置可配置选项,(3)调用Game
的实例方法(称为类似play
)来运行游戏。理想情况下,您的主要方法最终应如下所示:
public static void main(String [] args){
new MastermindGame()
.setLanes(4)
.setColors("0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
.setGuesses(5)
.setStartFlavor("The computer has generated a 4 digit number."
+ "\nYou must guess this 4 digit number in 5 attempt(s).")
.setPrompt("Enter guess:")
.setResponse("Correct digit in correct position count = %1"
+ "\nCorrect digit in incorrect position count = %2"
+ "\nGuesses remaining = %3")
.setLose("Sorry, you failed to guess the number (%1) in 5 attempts.");
.setWin("Congratulations, you win!");
.play();
}
评论
\ $ \ begingroup \ $
我绝对不会推荐这种主要方法。这就要求所有返回void的方法都将其返回。再加上调试将是一件繁琐的事情。我认为这是非常不好的做法。
\ $ \ endgroup \ $
–sixtyfootersdude
2014年1月24日19:34
\ $ \ begingroup \ $
再想一想,也许还可以。该术语似乎是“流利接口”或“方法链”。处理此类事情的堆栈跟踪会很麻烦,但是有些有趣。请参阅此问题以进一步讨论它们:stackoverflow.com/questions/1345001/…
\ $ \ endgroup \ $
–sixtyfootersdude
2014年1月24日19:47
\ $ \ begingroup \ $
这不会影响堆栈跟踪,并且唯一使调试混乱的是,您需要在子表达式上设置断点(或仅将它们放在函数本身而不是调用站点上)。
\ $ \ endgroup \ $
– Ben Voigt
2014年1月24日19:54
评论
\ $ \ begingroup \ $
很好。以0.001的获胜概率,也许我应该把它作为一个赌博游戏。
\ $ \ endgroup \ $
–婴儿
2014年1月24日,11:51
\ $ \ begingroup \ $
-1 Mastermind与您刚才描述的完全不同。在Mastermind中,会告诉玩家正确的颜色有多少个钉子,但位置错误,正确的颜色和位置有多少个钉子。因此,在您的第一个示例中,将为1234分配3个白色的钉子,为玩家提供比此处显示的信息更多的信息。而且,策划者总是可以在5个步骤中被击败。
\ $ \ endgroup \ $
– BlueRaja-Danny Pflughoeft
2014年1月24日19:56