目前,我已经完成了JavaScript中的这款Rock,Paper,剪刀,Lizard,Spock小游戏。游戏运行正常,但是我对代码不满意。有没有一种方法可以重构这些if语句?我当时在考虑三元运算符,但我尝试这样做但失败了。这基本上是我根据其获得结果的函数。

function result(userChoice, cpuChoice) {
    var result = '';

     if(userChoice == 'rock' ) {
        if (cpuChoice == 'rock') {
            result = 'Tie';
            ties++;
        } else if ( cpuChoice == 'spock') {
            result = 'Spock vaporizes rock';
            loses++;
        } else if ( cpuChoice == 'lizard' ) {
            result = 'Rock crushes lizard';
            wins++;
        }  else if ( cpuChoice == 'paper' ) {
            result = 'Paper covers rock';
            loses++;
        }  else if ( cpuChoice == 'scissors' ) {
            result = 'Rock crushes scissors';
            wins++;
        };
    } else if(userChoice == 'paper') {
        if (cpuChoice == 'paper') {
            result = 'Tie';
            ties++;
        } else if ( cpuChoice == 'spock') {
            result = 'Paper disproves Spock';
            wins++;
        } else if ( cpuChoice == 'lizard' ) {
            result = 'Lizard eats paper';
            loses++;
        }  else if ( cpuChoice == 'rock' ) {
            result = 'Paper covers rock';
            wins++;
        }  else if ( cpuChoice == 'scissors' ) {
            result = 'Scissors cuts paper';
            loses++;
        };
    } else if(userChoice == 'scissors') {
        if (cpuChoice == 'scissors') {
            result = 'Tie';
            ties++;
        } else if ( cpuChoice == 'spock') {
            result = 'Spock distroys scissors';
            loses++;
        } else if ( cpuChoice == 'lizard' ) {
            result = 'Scissors beheads lizard';
            wins++;
        }  else if ( cpuChoice == 'rock' ) {
            result = 'Rock crushes scissors';
            loses++;
        }  else if ( cpuChoice == 'paper' ) {
            result = 'Scissors cuts paper';
            wins++;
        };  
    } else if(userChoice == 'lizard') {
        if (cpuChoice == 'lizard') {
            result = 'Tie';
            ties++;
        } else if ( cpuChoice == 'spock') {
            result = 'Lizard poisons Spock';
            wins++;
        } else if ( cpuChoice == 'scissors' ) {
            result = 'Scissors beheads lizard' ;
            loses++;
        }  else if ( cpuChoice == 'rock' ) {
            result = 'Rock crushes lizard';
            loses++;
        }  else if ( cpuChoice == 'paper' ) {
            result = 'Lizard eats paper';
            wins++;
        };  
    } else if(userChoice == 'spock') {
        if (cpuChoice == 'spock') {
            result = 'Tie';
            ties++;
        } else if ( cpuChoice == 'lizard') {
            result = 'Lizard poisons Spock';
            loses++;
        } else if ( cpuChoice == 'scissors' ) {
            result = 'Spock distroys scissors';
            wins++;
        }  else if ( cpuChoice == 'rock' ) {
            result = 'Spock vaporizes rock';
            wins++;
        }  else if ( cpuChoice == 'paper' ) {
            result = 'Paper disproves Spock';
            loses++;
        };  
    } else {
        return false;
    };

    return result;
};


评论

您可能没有意识到,但是Rock Paper Scissors Lizard Spock在这里是一个古老的“社区挑战”,这就是为什么我在您的帖子中添加了相关标签。您可能对阅读其他RPSLS提交的挑战感兴趣。特别是一种不错的方法:Mat's Mug的RPSLS。

另请参见stackoverflow.com/a/17977389/103081

此外,它还面临PCG挑战,并提供了一些不错的答案。

#1 楼

要按原样查看代码:

最好不要甚至将result作为变量,并在else-if内交换从(result = X分配结果的结果中的操作顺序gameResult++)到(gameResult++return X
if语句的末尾不需要分号:


} else {
    return false;
};




而不是单独测试(userInput == X,然后是X == cpuInput),请将其删除,然后在顶部添加以下if语句。

if (userChoice === cpuChoice){
    ties++;
    return "Tie";
}
//The rest follows



因此,要修复if-else

所以,我将使用一个对象,而不是冗长的if-else语句,它使您可以指定键和值对,这实际上可以清理进程,因为您不需要必须先遍历所有选项,然后再找到所需的选项。

这就是我想出的:

var results = {
    wins: 0,
    loses: 0,
    ties: 0
};

function RPSLZ(userChoice, cpuChoice) {
    var RULES = {
        rock: {
            lizard: 'Rock crushes lizard',
            scissors: 'Rock crushes scissors'
        },
        paper: {
            spock: 'Paper disproves Spock',
            rock: 'Paper covers rock'
        },
        scissors: {
            lizard: 'Scissors beheads lizard',
            paper: 'Scissors cuts paper'
        },
        lizard: {
            spock: 'Lizard poisons Spock',
            paper: 'Lizard eats paper'
        },
        spock: {
            scissors: 'Spock distroys scissors',
            rock: 'Spock vaporizes rock'
        }
    };
    if (userChoice == cpuChoice) {
        results.ties++;
        return 'Tie';
    } else if (!userChoice in RULES){
        return 'Invalid Input';
    } else {
        return (cpuChoice in RULES[userChoice]
                    ? (results.wins++, RULES[userChoice][cpuChoice])
                    : (results.loses++, RULES[cpuChoice][userChoice])
                );
    }
}






这是一个好问题。它遵循以下逻辑流程:


在函数外部声明results,因此它可以继续记录更多函数调用的结果(有一种方法可以在函数内部执行此操作,但是我无法确定方法。)
声明游戏RULES(注意全大写,表示它是一个常量)
有两个特殊规则:tieInvalid Input。可以如上所述测试它们,就像测试输入是否存在于RULES变量中一样,因为如果不存在,则为undefined
通过使用相同的undefined测试规则,可以对cpuChoice进行测试查看它是否在userChoice的对象内,具体取决于结果,相应的计数器递增,然后返回结果。


评论


\ $ \ begingroup \ $
您不应该使用typeof RULES [userChoice] ==='undefined'。您应该使用in运算符。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月27日在14:25

\ $ \ begingroup \ $
您也可以摆脱最后两个
\ $ \ endgroup \ $
–凯文
15年8月27日在21:04

#2 楼


我已将此答案发布在以下评论中:带OOP的石头,纸张,剪刀,蜥蜴和Spock


我很快注意到的一件事是重复性。令我印象深刻的是尝试次数。您可以像这样使用早期的return

if(userChoice == cpuChoice) {
    tries++;
    return 'Tie';
}


这样,您可以清理领带!您曾经两次错误地拼写过destroys


要使代码正常工作,您必须了解什么。

您可以尝试创建完全面向对象的东西。 :

function RockPaperScissors(name, hard_action, soft_action) {
    this.name = (name + '').toLowerCase();
    this.hard_action = hard_action + '';
    this.soft_action = (soft_action || hard_action) + '';
    this.strengths = {};
    this.weaknesses = {};
}

RockPaperScissors.prototype = {
    getName: function(){
        return this.name;
    },
    addStrength: function(strength) {
        if( !(strength instanceof RockPaperScissors) ) {
            throw new TypeError('A strength must be an instance of RockPaperScissors');
        }

        this.strengths[strength.getName()] = strength;
    },
    getStrengths: function() {
        var strengths = {};
        for(var k in this.strengths)
        {
            strengths[k] = this.strengths[k];
        }
        return strengths;
    },
    addWeakness: function(weakness, soft) {
        if( !(weakness instanceof RockPaperScissors) ) {
            throw new TypeError('A weakness must be an instance of RockPaperScissors');
        }

        this.weaknesses[weakness.getName()] = {
            enemy: weakness,
            soft: !!soft
        };
    },
    getWeaknesses: function() {
        var weaknesses = {};
        for(var k in this.weaknesses)
        {
            weaknesses[k] = this.weaknesses[k];
        }
        return weaknesses;
    },
    getAction(soft){
        return soft? this.soft_action : this.hard_action;
    },
    winsTo: function(enemy) {
        if( !(enemy instanceof RockPaperScissors) ) {
            throw new TypeError('An enemy must be an instance of RockPaperScissors');
        }

        return (enemy.getName() in this.strengths);
    }
};

function RockPaperScissorsGame(){
    this.score = {
        won: 0,
        lost: 0,
        tied: 0
    };
    this.games = 0;
}

RockPaperScissorsGame.prototype = {
    match: function(user, enemy){
        if( !(user instanceof RockPaperScissors) ) {
            throw new TypeError('The user must be an instance of RockPaperScissors');
        }
        if( !(enemy instanceof RockPaperScissors) ) {
            throw new TypeError('The enemy must be an instance of RockPaperScissors');
        }

        this.games++;

        if( user == enemy ) {
            this.score.tied++;
            return 'Tie';
        }

        var userName = user.getName();
        var enemyName = enemy.getName();

        if( user.winsTo(enemy) ) {
            this.score.won++;
            var enemyWeakness = enemy.getWeaknesses()[userName] || {enemy: enemy, soft: false};

            return userName + ' ' + user.getAction(enemyWeakness.soft) + ' ' + enemyName;

        } else {
            this.score.lost++;
            var userWeakness = user.getWeaknesses()[enemyName] || {enemy: enemy, soft: false};

            return enemyName + ' ' + enemy.getAction(userWeakness.soft) + ' ' + userName;
        }
    },
    getMatches: function(){
        return this.games;
    },
    getWins: function(){
        return this.won;
    },
    getLosses: function(){
        return this.lost;
    },
    getTies: function(){
        return this.tied;
    }
};


这允许进行更多的抽象,因为您不必知道在特定情况下,这将胜任that和所有条件。

您在新游戏上运行一种方法,它可以为您完成所有工作。您只需要担心将其大写正确即可。您只需创建元素,添加优点和缺点,就完成了!

要运行它,您只需执行以下操作即可:




 function RockPaperScissors(name, hard_action, soft_action) {
	this.name = (name + '').toLowerCase();
	this.hard_action = hard_action + '';
	this.soft_action = (soft_action || hard_action) + '';
	this.strengths = {};
	this.weaknesses = {};
}

RockPaperScissors.prototype = {
	getName: function(){
		return this.name;
	},
	addStrength: function(strength) {
		if( !(strength instanceof RockPaperScissors) ) {
			throw new TypeError('A strength must be an instance of RockPaperScissors');
		}
		
		this.strengths[strength.getName()] = strength;
	},
	getStrengths: function() {
		var strengths = {};
		for(var k in this.strengths)
		{
			strengths[k] = this.strengths[k];
		}
		return strengths;
	},
	addWeakness: function(weakness, soft) {
		if( !(weakness instanceof RockPaperScissors) ) {
			throw new TypeError('A weakness must be an instance of RockPaperScissors');
		}
		
		this.weaknesses[weakness.getName()] = {
			enemy: weakness,
			soft: !!soft
		};
	},
	getWeaknesses: function() {
		var weaknesses = {};
		for(var k in this.weaknesses)
		{
			weaknesses[k] = this.weaknesses[k];
		}
		return weaknesses;
	},
	getAction(soft){
		return soft? this.soft_action : this.hard_action;
	},
	winsTo: function(enemy) {
		if( !(enemy instanceof RockPaperScissors) ) {
			throw new TypeError('An enemy must be an instance of RockPaperScissors');
		}
		
		return (enemy.getName() in this.strengths);
	}
};

function RockPaperScissorsGame(){
	this.score = {
		won: 0,
		lost: 0,
		tied: 0
	};
	this.games = 0;
}

RockPaperScissorsGame.prototype = {
	match: function(user, enemy){
		if( !(user instanceof RockPaperScissors) ) {
			throw new TypeError('The user must be an instance of RockPaperScissors');
		}
		if( !(enemy instanceof RockPaperScissors) ) {
			throw new TypeError('The enemy must be an instance of RockPaperScissors');
		}
		
		this.games++;
		
		if( user == enemy ) {
			this.score.tied++;
			return 'Tie';
		}
		
		var userName = user.getName();
		var enemyName = enemy.getName();
		
		if( user.winsTo(enemy) ) {
			this.score.won++;
			var enemyWeakness = enemy.getWeaknesses()[userName] || {enemy: enemy, soft: false};
			
			return userName + ' ' + user.getAction(enemyWeakness.soft) + ' ' + enemyName;
			
		} else {
			this.score.lost++;
			var userWeakness = user.getWeaknesses()[enemyName] || {enemy: enemy, soft: false};
			
			return enemyName + ' ' + enemy.getAction(userWeakness.soft) + ' ' + userName;
		}
	},
	getMatches: function(){
		return this.games;
	},
	getWins: function(){
		return this.score.won;
	},
	getLosses: function(){
		return this.score.lost;
	},
	getTies: function(){
		return this.score.tied;
	}
};


var rock = new RockPaperScissors('rock', 'crushes');
var paper = new RockPaperScissors('paper', 'wraps', 'disproves');
var scissor = new RockPaperScissors('scissor', 'cuts', 'beheads');

scissor.addStrength(paper);
rock.addStrength(scissor);
paper.addStrength(rock);

var game = new RockPaperScissorsGame();

alert([
	game.match(rock,paper),
	game.match(rock,rock),
	game.match(scissor,paper),
	game.getWins(),
	game.getLosses(),
	game.getTies(),
	game.getMatches()
].join('\r\n')); 





通过这样做,您可以抽象出获胜条件和游戏玩法,从而简化了编程,可读性,可维护性和灵活性。您可以添加各种优点和缺点的任意数量的敌人。

#3 楼

使用Javascript的switch语句代替长链(如果不是,则用长链)。它基本上允许您传入一个参数,即。 userChoicecpuChoice,然后根据它的值运行不同的代码。

    switch (cpuChoice) {
        case 'rock':
            result = 'Tie';
            ties++;
            break;
        case 'spock':
            result = 'Spock vaporizes rock';
            loses++;
            break;
        case 'lizard':
            result = 'Rock crushes lizard';
            wins++;
            break;
        case 'paper':
            result = 'Paper covers rock';
            loses++;
            break;
        case 'scissors':
            result = 'Rock crushes scissors';
            wins++;
            break;
    }


您还可以嵌套switch语句以将开关放入开关的case块中。如果没有其他情况评估为default:,则也可以使用true作为最后一种情况。

评论


\ $ \ begingroup \ $
我将尝试看看是否也可以按照您的方式进行操作,我发现尝试几种方法来获得相同的结果是一种很好的做法。干杯!我对它满意后将在这里发布代码:D。
\ $ \ endgroup \ $
– Daria M
15年8月27日在11:48

#4 楼

如果您想象对象以特定顺序放在轮子上,则可以完全摆脱if-else。然后,您可以通过比较每个符号与另一个符号(负,相等或正)之间的距离来确定谁获胜。

下面是一些Python代码:

我知道它被标记为JavaScript,但是很容易转换为JavaScript

# The key idea of this program is to equate the strings
# "rock", "paper", "scissors", "lizard", "Spock" to numbers
# as follows:
#
# 0 - rock
# 1 - Spock
# 2 - paper
# 3 - lizard
# 4 - scissors

import random

# helper functions

def number_to_name(number):
    """
    Converts a number to its name equivalent
    and returns said name
    """

    if number == 0:
        return "rock"
    elif number == 1:
        return "Spock"
    elif number == 2:
        return "paper"
    elif number == 3:
        return "lizard"
    elif number == 4:
        return "scissors"
    else:
        return "That is not a valid number!"


def name_to_number(name):
    """
    Converts a name to its number equivalent
    and returns said number
    """

    if name == "rock":
        return 0
    elif name == "Spock":
        return 1
    elif name == "paper":
        return 2
    elif name == "lizard":
        return 3
    elif name == "scissors":
        return 4
    else:
        return "That is not a valid name!"


def rpsls(name): 

    # convert name to player_number
    player_number = name_to_number(name)

    # compute random guess for comp_number
    comp_number = random.randrange(0, 4)

    # compute difference of player_number and comp_number modulo five
    difference = (player_number - comp_number) % 5

    # determine winner
    if difference == 0:
        winner = "It's a tie!"
    elif difference <= 2:
        winner = "Player wins!"
    elif difference >= 3:
        winner = "Computer wins!"
    else:
        return "Something went horribly wrong"

    # convert comp_number to name using number_to_name
    comp_name = number_to_name(comp_number)

    # print results
    print ""
    print "Player chooses", name
    print "Computer chooses", comp_name
    print winner


# test the code
rpsls("rock")
rpsls("Spock")
rpsls("paper")
rpsls("lizard")
rpsls("scissors")


评论


\ $ \ begingroup \ $
请提供您希望成为答案的代码,也可以添加链接,但请记住,链接有时会变烂。
\ $ \ endgroup \ $
–马拉奇♦
15年8月27日在15:56

\ $ \ begingroup \ $
Python和Javascript是不同的语言。区别之一是打印语句。 Javascript中没有这样的东西。但是,有document.writeln(),但这是一个不好的做法。
\ $ \ endgroup \ $
–伊斯梅尔·米格尔(Ismael Miguel)
15年8月27日在16:18

\ $ \ begingroup \ $
关键是确定谁获胜的方法...这不是打印获胜者的愚蠢方法。
\ $ \ endgroup \ $
–嵌合体
15年8月27日在16:21

\ $ \ begingroup \ $
您可以轻松删除带有数组的number_to_name()和name_to_number()函数(使用array.indexOf()进行反向查找)
\ $ \ endgroup \ $
–IQAndreas
15年8月28日在7:03

\ $ \ begingroup \ $
@IQAndreas谢谢。你是对的。除了展示一种避免if-else或lookup方法来确定游戏获胜者的方法外,我没有在关注其他优化。
\ $ \ endgroup \ $
–嵌合体
15年8月28日在19:51

#5 楼

要“拉平”规则并避免嵌套的switch语句,请尝试以下操作:

switch (userChoice + cpuChoice) {
  case "rockscissors":
    msg = "Rock crushes scissors";
    wins++;
    break;
  case "scissorsrock":
    msg = "Rock crushes scissors";
    losses++;
    break;    
  case "spockrock":
    msg = "Spock vaporizes rock";
    wins++;
    break;
// etc
}


为什么?每个原子规则只有一个规则条目要容易得多。您可以将所有可能的响应放入一个对象中,并具有一个更通用的函数来计算结果:


#6 楼

尽管已经有了14个投票的答案,但我还是不得不指出这个程序正在为查找表大喊大叫。

该代码应该由数据驱动,并且可以简化为一个代码行(肯定只有几行)。

为什么不...

if (superior[spock][lizard])


表示我的意思(总是false) 。

以您的情况

if (superior[userChoice][cpuChoice])


我留给读者练习来对数组superior[][]进行硬编码,并构建适当的文本字符串。