用公式从逻辑上确定游戏结果
Logically determine game outcome with formula
我正在努力成为一名更好的编码员,其中包括摆脱我的 'hard-coding' 习惯,以保持我的程序动态且易于维护。
现在我正在写一个简单的剪刀石头布游戏作为练习:
import time
validoptions = ["rock", "paper", "scissors"]
u1input = input("User 1, do you want to choose rock, paper or scissors?").lower()
if not u1input in(validoptions):
u1input = input("What the hell User 1, choose a valid option: rock, paper or scissors?").lower()
u2input = input("User 2, do you want to choose rock, paper or scissors?").lower()
if not u2input in(validoptions):
u2input = input("What the hell User 2, choose a valid option: rock, paper or scissors?").lower()
u1 = validoptions.index(u1input)
u2 = validoptions.index(u2input)
if u1 - u2 == 0:
result = "It's a draw! Both parties have proven to be of equal strength."
print("Stakes are high... The battle is on... Calculating losses...")
for i in range(1,4):
time.sleep(1)
print("...")
time.sleep(1)
print(result)
对于剪刀石头布这样的游戏,结果并不多(6 wins/losses 和 1 个平局结果,或 3^2 个单独结果)。我可以很容易地在我已经编码的平局结果旁边编码所有可能的结果。但是,如果游戏扩展了 3 个选项怎么办?说:Rock, Paper, Scissors, Pans, Swords, and Rifles
:那将是 6^2 = 36 个结果!
随着此列表的扩展,潜在结果的数量变得越来越难以硬编码。我想使用公式或其他 'smart' 动态方法来确定游戏结果,其方式与 if u1 - u2 == 0:
行类似。
这有可能吗?
这真的很酷!所以,我想我会用字典来控制什么输给什么:
dict_loss = dict()
dict_loss['paper']='scissors'
dict_loss['scissors']='rock'
dict_loss['rock']='paper'
然后玩家做出选择,你只需要检查他们的选择是否在字典中:
player_1='paper'
player_2='rock'
if player_2 in dict_loss[player_1]:
print("Player 2 Wins")
else:
if player_1 in dict_loss[player_2]:
print("Player 1 Wins")
else:
print("DRAW")
你可以用你得到的新对象来扩展字典,我不确定平底锅、剑和步枪是如何工作的,但你可以这样做:
dict_loss['paper']=['scissors', 'riffle']
如果纸输给浅滩,以此类推...
希望这对您有所帮助,如果您有任何 "data structure" 限制,请告诉我,我会尝试想一些不同的东西。
列表是个好主意。在你的情况下 validoptions = ["rock", "paper", "scissors"]
你可以看到,一切都击败了它之前的唯一一个("paper"
击败了 "rock"
,"rock"
击败了 "scissors"
和 "scissors"
胜过 "paper"
。所以如果你这样排序,它可以只使用索引来解决。如果你想增加选择,你可以,但要注意,只有奇数将提供公平的比赛。
一般来说,如果你做一个options
的列表,长度为length
,那么:
if u1 == u2:
#it is a draw
elif u2input in validoptions[u1 - int((length-1)/2):u1]:
#player1 has won
else:
#player2 has won
由于规则没有明确定义,给出一个放之四海而皆准的解决方案并非易事。如果 "win/lose",我可能会假设有一些循环定义,给我模演算例如:
winner = ["None", "Player 1", "Player 2"]
win_index = (u1 - u2) % len(validoptions)
print("Winner: " + winner[win_index])
也许看看也很有趣:https://en.wikipedia.org/wiki/Rock%E2%80%93paper%E2%80%93scissors#Additional_weapons。
我最初想到的Rock–Paper–S剪刀 (RPS) 规则:
- 这是元素之间的循环关系,每个元素都击败了它之前的元素(Scissors beats (cuts) Paper)
- 第 1st 个元素(之前没有任何元素)击败最后一个元素(并且循环完成)
- 添加更多的元素,只是为了让更多的用户玩(只要用户数少1 比元素计数),但现在我看到 它是错误的 因为在某些情况下结果可能是不确定的(实际上唯一有效的情况是没有 2 个玩家选择了相同的选项)
显然(感谢 [Wikipedia]: Rock–paper–scissors),对于 平衡 游戏(奇数个元素):
每个元素都打败了其他一半(结果,输给了另一半)
- 第(1st)个
- 前三
- 前5
- ...
- 到达列表开头时,跳转到结尾(环绕)
这是 3 元素 (RPS) 游戏的概括(也适用于 RPSLS)
这是将上述规则放入代码后的样子(我还对其进行了重新设计以更正代码段中的一些错误)。所有的“魔法”都发生在 outcome.
code00.py:
#!/usr/bin/env python3
import sys
_elements_list = [
["Rock", "Paper", "Scissors"],
["Rock", "Paper", "Scissors", "Spock", "Lizard"], # !!! The order is DIFFERENT (RPSSL) than the name of the game: RPSLS !!!
]
elements_dict = {len(item): item for item in _elements_list}
del _elements_list
def get_users_choices(valid_options):
ret = [-1] * 2
for i in (0, 1):
user_choice = None
while user_choice not in valid_options:
user_choice = input("Enter user {0:d} option (out of {1:}): ".format(i + 1, valid_options))
ret[i] = valid_options.index(user_choice)
return ret
def outcome(idx0, idx1, count): # Returns -1 when 1st player wins, 0 on draw and 1 when 2nd player wins
if idx0 == idx1:
return 0
index_steps = [-i * 2 - 1 for i in range(count // 2)] # Index steps (n // 2 items) from current index: {-1, -3, -5, ...} (negative values mean: before)
idx0_beat_idxes = [(idx0 + i + count) % count for i in index_steps] # Wrap around when reaching the beginning of the list
if idx1 in idx0_beat_idxes:
return -1
return 1
def main():
element_count = 3 # Change it to 5 for RPSLS
if element_count <= 2:
raise ValueError("Can't play game")
elements = elements_dict.get(element_count)
if not elements:
raise ValueError("Invalid option count")
choices = get_users_choices(elements)
res = outcome(*choices, element_count)
if res == 0:
print("'{0:s}' and '{1:s}' are DRAW.".format(elements[choices[0]], elements[choices[1]]))
elif res < 0:
print("'{0:s}' WINS over '{1:s}'.".format(elements[choices[0]], elements[choices[1]]))
else:
print("'{0:s}' LOSES to '{1:s}'.".format(elements[choices[0]], elements[choices[1]]))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
输出:
[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q057491776]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
Enter user 1 option (out of ['Rock', 'Paper', 'Scissors']): Rock
Enter user 2 option (out of ['Rock', 'Paper', 'Scissors']): Scissors
'Rock' WINS over 'Scissors'.
Done.
我正在努力成为一名更好的编码员,其中包括摆脱我的 'hard-coding' 习惯,以保持我的程序动态且易于维护。
现在我正在写一个简单的剪刀石头布游戏作为练习:
import time
validoptions = ["rock", "paper", "scissors"]
u1input = input("User 1, do you want to choose rock, paper or scissors?").lower()
if not u1input in(validoptions):
u1input = input("What the hell User 1, choose a valid option: rock, paper or scissors?").lower()
u2input = input("User 2, do you want to choose rock, paper or scissors?").lower()
if not u2input in(validoptions):
u2input = input("What the hell User 2, choose a valid option: rock, paper or scissors?").lower()
u1 = validoptions.index(u1input)
u2 = validoptions.index(u2input)
if u1 - u2 == 0:
result = "It's a draw! Both parties have proven to be of equal strength."
print("Stakes are high... The battle is on... Calculating losses...")
for i in range(1,4):
time.sleep(1)
print("...")
time.sleep(1)
print(result)
对于剪刀石头布这样的游戏,结果并不多(6 wins/losses 和 1 个平局结果,或 3^2 个单独结果)。我可以很容易地在我已经编码的平局结果旁边编码所有可能的结果。但是,如果游戏扩展了 3 个选项怎么办?说:Rock, Paper, Scissors, Pans, Swords, and Rifles
:那将是 6^2 = 36 个结果!
随着此列表的扩展,潜在结果的数量变得越来越难以硬编码。我想使用公式或其他 'smart' 动态方法来确定游戏结果,其方式与 if u1 - u2 == 0:
行类似。
这有可能吗?
这真的很酷!所以,我想我会用字典来控制什么输给什么:
dict_loss = dict()
dict_loss['paper']='scissors'
dict_loss['scissors']='rock'
dict_loss['rock']='paper'
然后玩家做出选择,你只需要检查他们的选择是否在字典中:
player_1='paper'
player_2='rock'
if player_2 in dict_loss[player_1]:
print("Player 2 Wins")
else:
if player_1 in dict_loss[player_2]:
print("Player 1 Wins")
else:
print("DRAW")
你可以用你得到的新对象来扩展字典,我不确定平底锅、剑和步枪是如何工作的,但你可以这样做:
dict_loss['paper']=['scissors', 'riffle']
如果纸输给浅滩,以此类推...
希望这对您有所帮助,如果您有任何 "data structure" 限制,请告诉我,我会尝试想一些不同的东西。
列表是个好主意。在你的情况下 validoptions = ["rock", "paper", "scissors"]
你可以看到,一切都击败了它之前的唯一一个("paper"
击败了 "rock"
,"rock"
击败了 "scissors"
和 "scissors"
胜过 "paper"
。所以如果你这样排序,它可以只使用索引来解决。如果你想增加选择,你可以,但要注意,只有奇数将提供公平的比赛。
一般来说,如果你做一个options
的列表,长度为length
,那么:
if u1 == u2:
#it is a draw
elif u2input in validoptions[u1 - int((length-1)/2):u1]:
#player1 has won
else:
#player2 has won
由于规则没有明确定义,给出一个放之四海而皆准的解决方案并非易事。如果 "win/lose",我可能会假设有一些循环定义,给我模演算例如:
winner = ["None", "Player 1", "Player 2"]
win_index = (u1 - u2) % len(validoptions)
print("Winner: " + winner[win_index])
也许看看也很有趣:https://en.wikipedia.org/wiki/Rock%E2%80%93paper%E2%80%93scissors#Additional_weapons。
我最初想到的Rock–Paper–S剪刀 (RPS) 规则:
- 这是元素之间的循环关系,每个元素都击败了它之前的元素(Scissors beats (cuts) Paper)
- 第 1st 个元素(之前没有任何元素)击败最后一个元素(并且循环完成)
- 添加更多的元素,只是为了让更多的用户玩(只要用户数少1 比元素计数),但现在我看到 它是错误的 因为在某些情况下结果可能是不确定的(实际上唯一有效的情况是没有 2 个玩家选择了相同的选项)
显然(感谢 [Wikipedia]: Rock–paper–scissors),对于 平衡 游戏(奇数个元素):
每个元素都打败了其他一半(结果,输给了另一半)
- 第(1st)个
- 前三
- 前5
- ...
- 到达列表开头时,跳转到结尾(环绕)
这是 3 元素 (RPS) 游戏的概括(也适用于 RPSLS)
这是将上述规则放入代码后的样子(我还对其进行了重新设计以更正代码段中的一些错误)。所有的“魔法”都发生在 outcome.
code00.py:
#!/usr/bin/env python3
import sys
_elements_list = [
["Rock", "Paper", "Scissors"],
["Rock", "Paper", "Scissors", "Spock", "Lizard"], # !!! The order is DIFFERENT (RPSSL) than the name of the game: RPSLS !!!
]
elements_dict = {len(item): item for item in _elements_list}
del _elements_list
def get_users_choices(valid_options):
ret = [-1] * 2
for i in (0, 1):
user_choice = None
while user_choice not in valid_options:
user_choice = input("Enter user {0:d} option (out of {1:}): ".format(i + 1, valid_options))
ret[i] = valid_options.index(user_choice)
return ret
def outcome(idx0, idx1, count): # Returns -1 when 1st player wins, 0 on draw and 1 when 2nd player wins
if idx0 == idx1:
return 0
index_steps = [-i * 2 - 1 for i in range(count // 2)] # Index steps (n // 2 items) from current index: {-1, -3, -5, ...} (negative values mean: before)
idx0_beat_idxes = [(idx0 + i + count) % count for i in index_steps] # Wrap around when reaching the beginning of the list
if idx1 in idx0_beat_idxes:
return -1
return 1
def main():
element_count = 3 # Change it to 5 for RPSLS
if element_count <= 2:
raise ValueError("Can't play game")
elements = elements_dict.get(element_count)
if not elements:
raise ValueError("Invalid option count")
choices = get_users_choices(elements)
res = outcome(*choices, element_count)
if res == 0:
print("'{0:s}' and '{1:s}' are DRAW.".format(elements[choices[0]], elements[choices[1]]))
elif res < 0:
print("'{0:s}' WINS over '{1:s}'.".format(elements[choices[0]], elements[choices[1]]))
else:
print("'{0:s}' LOSES to '{1:s}'.".format(elements[choices[0]], elements[choices[1]]))
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
输出:
[cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q057491776]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32 Enter user 1 option (out of ['Rock', 'Paper', 'Scissors']): Rock Enter user 2 option (out of ['Rock', 'Paper', 'Scissors']): Scissors 'Rock' WINS over 'Scissors'. Done.