I am trying to become a better coder, which includes getting rid of my \'hard-coding\' habits to keep my programs dynamic and easy to maintain.
Right now I am writing a
What I initially thought about the Rock–Paper–Scissors (RPS) rules:
Apparently (thanks to [Wikipedia]: Rock–paper–scissors), for a balanced game (odd number of elements):
Each element beats half of the other ones (and as a consequence, loses to the other half)
This is a generalization of the 3 element (RPS) game (and also applies to RPSLS)
Here's what the above rule looks like when put into code (I've also redesigned it to correct some errors in your snippet). All the "magic" happens in 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.")
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\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.