2
\$\begingroup\$

Rock Paper and Scissors is a pretty basic program.

The reason I wrote this program is because I wanted to see what a small script that used all of the main programming paradigms looked like.

My code contains:

  • OOP: A Player object.
  • FP: First class functions : player.intelligence is a function is stored in a variables and I use anonymous lambdas
  • IMP: The code asks for input freely, asking for input freely in a functional paradigm is not possible, so this is the imperative part.

Tell me if you like it or if you think it is too complex for an easy task and should be simplified.

from collections import namedtuple
import random

RPS = ["rock", "paper", "scissors"]

Player = namedtuple('Player', 'name intelligence')

def rock_paper_scissors(player_1, player_2):
    a, b = player_1.intelligence(), player_2.intelligence()
    print("\n{} chose {}\n{} chose {}\n".format(
        player_1.name, RPS[a-1], player_2.name, RPS[b-1]))
    return "Tie" if a == b else \
      "The winner is " + (player_1.name if (a - b) % 3 == 1 else player_2.name)

def human_intelligence(prompt):
    return RPS.index(input("The Player 1 move: ").lower())+1

def random_ai():
    return random.choice((1,2,3))

Human vs Computer

print(rock_paper_scissors(
    Player("The Human", lambda: human_intelligence("The human's move : ")),
    Player("The Computer", random_ai)
    )
)

Human vs Human

print(rock_paper_scissors(
    Player("The Player 1", lambda: human_intelligence("Player 1 move : ")),
    Player("The Player 2", lambda: human_intelligence("Player 2 move : "))
    )
)

Computer vs Computer

print(rock_paper_scissors(
    Player("The Computer 1", random_ai),
    Player("The Computer 2", random_ai)
    )
)
\$\endgroup\$
2
\$\begingroup\$

I'm almost sorry to say, that it feels like you are naming things just because you can name them according to some coding principle.

Calling a named tuple OOP, is stretching it very thin. Yes, it encapsulates something but it doesn't have any options to do actions on the object, and it's not a very good use of it. Could possibly use OOP if you used inheritance for the human player and the computer player incorporating the choice logic.

But then again, that would ruin your so-called FP approach with lambdas and storing of functions. Which again is stretching it rather thin, as you don't use a functional approach avoiding state handling and mathemical functions on lists.

So in the end it is mostly imperative programming, which most paradigms ends up with at some level deep within. And it's imperative programming with a very slight touch of OOP, and a very slight touch of FP.

As this however is Code Review, lets add some review issues as well:

  • User interface is almost non-existent – You don't provide the user with any information on what to enter, nor do you have error handling of any sort. Only after studying the code intensely I see that you enter either "rock", "paper" or "scissors", which is looked up, incremented, and finally decremented to be displayed back within rock_paper_scissors(). Slightly confusing...
  • Not the best of variable names – The names RPS, a and b are not according to style guidelines, nor very descriptive.
  • Neat version to select winner – Simple in code, although undescribed, version to select the winner
  • Add vertical spacing to rock_paper_scissors() – Instead of everything jammed together, I would love to have a little vertical space to help me distinguish the statements of this function.

To summarize, your script does implement a function to play rock, paper or scissors, but it is, in my opinion, too condensed and should be expanded upon rather than simplified any more.

\$\endgroup\$
1
  • \$\begingroup\$ Yes, I too had a felling of over-complicating a simple matter, but wanted some opinions on it. About User interface is almost non-existent just using general_input should fix it, so it's not a problem, and yes, the modular approach should have had a link back to the source. \$\endgroup\$
    – Caridorc
    Dec 11 '15 at 22:14
2
\$\begingroup\$

Borrowing ideas from various programming paradigms is fine: it makes you a better programmer. Be careful about calling it OOP or FP, though, just because you borrowed some ideas. There is a lot more to OOP than just fields in a namedtuple. As for FP, you start to lose some of the benefits as soon as the functions have side-effects.

The 1-based numbering that you used for RPS is awkward for a language where 0-based numbering is the norm. If you're using Python ≥ 3.4, then RPS should be an Enum.

The rock_paper_scissors() function does too much, I think. It asks the players for their choices, prints the choices, and compares them — and most of the code is duplicated for each of the two players. The correspondence between player_1 and a could be better with more logical naming: either player_1 and choice_1, or player_a and choice_a.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ When I said OO or FP I obviously did not mean an in-depth use of them (How can a ten lines script be in-depth?) If came across as a know-it-all it was not my intention. \$\endgroup\$
    – Caridorc
    Dec 11 '15 at 22:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.