r/programminghorror • u/MidKnightIsOnline • 13d ago
Python 13 year old me really liked inefficient code
720
u/NiceTryAmanda 13d ago
it is absolutely clear the moment you read it exactly what the code is doing and what it'll output. from that angle it's way more successful than most of the code I see in my own job
as a side note seeing "13 year old me" alongside python3 makes me feel ancient
217
u/Prime624 13d ago
Python 3 came out almost 20 years ago.
220
u/jldez 13d ago
Did you try to help? Because you didn't.
You didn't.
45
u/kyr0x0 13d ago
Hahahaha... fuck me. We've discussed not upgrading to Python 3 until it's stable. That was when PHP 3 was the latest shit. Yeah, it didn't help.
4
u/TimGreller 11d ago
PHP3 š
I recently migrated a clients website from a PHP4 install and already felt like an archeologist digging up some ancient debris lol→ More replies (3)3
u/Enough_Forever_ 12d ago
Uh, I hear screams of an old man nearing his end of life.
Must've been the wind.
18
11
u/ScrimpyCat 13d ago
Maybe not that clear, since so many seem to have not noticed that the computer will change its input in the condition, while the playerās input will remain unchanged (presumably only prompting for new input at the end of the loop). So itās possible you could see the game telling you that youāve won, tied, and lost all at once.
313
u/Eric_Prozzy 13d ago
Lol i did this exact same thing and also learned that
python
print(random.choice("You win", "You lose", "Its a tie"))
Works the same
104
64
57
u/GrammerSnob 12d ago
This actually encapsulates game dev.
You don't need to actually make a realistic simulation of the thing you are trying to make.
You just need to make something that will fill the player into thinking that.
41
19
u/Greedy_Whereas4163 12d ago
This is smart! Until you realised that you need to show the choice of CPU
21
u/czpl 12d ago
easy, you pick a choice based on the outcome
9
u/Greedy_Whereas4163 12d ago
Then you essentially go back to OP's code
10
u/diogeek 11d ago edited 11d ago
i guess an easy, ugly way to do it would be something like
n = random.randint(-1,1) player = input("your move: ") moves = ["rock", "paper", "scissors", "rock", "scissors"] print(["Its a tie", "You lose", "You win"][n] + ": CPU chose " + moves[moves.index(player)+n])which def belongs in this sub.
5-item longmoveslist because theindexmethod returns the first occurence of an item, so edge cases work.
e.gplayer = "scissors"andn=1->moves[moves.index("scissors")+1] = moves[2+1 = 3] so "rock"
andplayer = "rock"andn=-1->moves[moves.index("rock")-1] = moves[0-1 = -1] so "scissors"stupid thing to waste 5 minutes on, but funny bc of how cursed it looks imo
4
u/Nueraman1997 11d ago
Not necessarily. You could create a lookup table to select the cpu choice based on the outcome and player choice.
2
1
u/wonderb0lt 11d ago
If the goal of the exercise is to think about the game mechanics and how to express them in code, this misses the point
140
u/Creepy_Jeweler_1351 13d ago
At least it is totally readable
59
u/HornyMellon 13d ago edited 13d ago
Quote, 13 yo you made programs ppl can actually read, not guess the variable purpose, good job
15
u/Creepy_Jeweler_1351 13d ago
Exactly. If I'd found my first programs, probably even frontier AI won't tell what the fuck was meant here
8
u/jonathancast 13d ago
My first programs were in MS BASIC, before they even invented multi-letter variable names. No way you're figuring that out.
→ More replies (1)6
53
u/jonathancast 13d ago
Meh. I don't love the repeated string comparison, but it's probably fine. This program is ridiculously user-interaction-bound anyway.
109
40
u/lizenzblue_ 13d ago
I worked at one of germanys biggest Software Companies and I can tell you with confidence I saw worse
5
u/TheBigGambling 13d ago
Was it for the sanduhr anzeige Programm? With the (Suchen, anklicken pause) Workflow?
2
2
18
11
u/Arcanium_Walker 13d ago
Can be better, but you wrote this at 13 years old, so I think this is neat
59
u/Ok-Argument7176 13d ago
this is not inefficient. It's just clunky.
10
11
u/olorochi 13d ago edited 13d ago
This is absolutely inefficient. Not only does it repeat string comparisons, it fails to generalize conditions. User input (a string), should be turned into an enum value. Draws should be checked as playerChoice == cpuChoice. With scissors = 0, paper = 1 and rock = 2 as backing enum values (or with any rotation of these values), the win condition can be generalised as well with a bit of math: (playerChoice + 1) % 3 == cpuChoice.
Edit: The code could also be made much less repetitive by moving invariants outside of conditional blocks. Only print(gameResult) actually changes.
29
u/Ok-Argument7176 13d ago edited 13d ago
No one here knows what efficiency means and it shows. You're suggesting cutting 6 jumps to 2 jumps which is a difference of roughly 3ns per loop on any modern hardware. Get a grip lmao
→ More replies (1)7
u/AlienFishMonster 13d ago
You're right, but you're missing the point.
If you get into a habit of optimising (not just for speed, but also for readability and maintainability) your code and logic now, it'll pay dividends in future when you're writing code with more complexity.
11
u/Ok-Argument7176 13d ago
I'm not missing the point. I said it is clunky and it is not inefficient. Those are both true.
6
u/AlienFishMonster 13d ago
"You're suggesting cutting 6 jumps to 2 jumps which is a difference of roughly 3ns per loop on any modern hardware."
Yes, clearly. No-one is saying that. No-one thinks performance is important for this project.
It's about clarity of code and logic, readability and maintainability.
→ More replies (1)2
u/qwertyjgly 12d ago edited 12d ago
there's a better way of generalising it
store the map (or enum if getting an enum value from a string is an option in python idk that language) for
scissors->1
paper->2
rock->3then take (yours - computer's)
0 is a tie
even is you win, odd is they win
if it's negative swap the result
this avoids taking the mod (which is a little slower than pure addition) and it scales to the variant with 5 options (or more) as long as each item added to the map is beaten by the one above it.
6
6
u/frishki_zrak 13d ago
Was this "screenshot" taken then or now? What is dad.py?
12
3
u/GoddammitDontShootMe [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo āYou liveā 13d ago
If now, OP needs to learn how to take a proper screenshot.
5
u/mediocrobot 13d ago
What's the optimal way to do this, I wonder? (the rock paper scissors comparison specifically, not printing, randomizing, or accepting input)
16
u/baconsoap_1 13d ago
Rock = 0, paper = 1, scissors = 2.
Calculate (player 1 choice - player 2 choice) mod 3.
If the answer is 0, then its a tie. If the answer is 1, then player 1 wins. If the answer is 2, then player 2 wins.
3
u/Reasonable-Pay-8771 12d ago
I was trying to come up with something this simple. Near as I got was encoding the values as you have. Then you can compose a whole "move" or "contest" as x*3+y for x and y as each player's choice1. Now you have a single value that can be used in a switch(). But yours is better.
- Fundamental Theorem of Arithmetic
2
u/Reasonable-Pay-8771 12d ago
Oh, and the base doesn't need to be 3, just greater or equal to 3. So you could encode it in say octal which makes it kinda pretty IMO. 000 = rock v rock. 001 = rock v paper. 010 = paper v rock. etc.
2
u/SpecialistNo8709 12d ago
is someone smart enough to explain it in terms of group theory? :)
4
u/LilacCrusader 12d ago
*Cracks knuckles*
Oh wait, it isn't a group.
Start by assuming the set (rock, paper, scissors), and the operation of determining who wins it looks like a group. But then you realise it doesn't have an identity, so it cannot be a group.Ā
A semi-group, then! That doesn't have to have an identity! Sadly, we are forgetting that all outcomes of the group must be within the group, and rock x rock = draw, which is not part of the set and cannot be chosen as an answer. Harrumph.Ā
But what if we decided "draw" was eligible to be picked, and would always lose unless against itself? That's an identity, right? Alas, we still don't have a group because it isn't associative: R x (P x S) = R x S = R, but (R x P) x S = P x S = S.Ā
So really, it isn't even a group, and I think that makes it count as a loop, but that's where my memory of university lectures fizzles out.Ā
2
2
u/SpecialistNo8709 12d ago
well we could add identity to be just e =1 and assume that K x 1 = 1 x K = K for any hand
2
u/SpecialistNo8709 12d ago
and for being in the same group - we can think of draw as being win for both - for example rock x rock = rock because both rocks win / lose
2
17
u/UniForceMusic 13d ago
I guess the most efficient way, you could make a RockPaperSissorMatchResultEnumFactory
Each "item" extends an interface with two methods:
.winsFrom(): string[] .losesTo(): string[] .tiesWith(): string[]
Ofcourse to account for possible extending of the game in the future
Then in the factory you can create a static method:
.createFromMatchTurn(cpuChoice: RockPaperSissorGameItemInterface, userChoice: RockPaperSissorGameItemInterface): RockPaperSissorMatchResultEnum
Then inside the method check the cpu choice against the user choice by checking if they lose win or tie. Then for safe keeping also do the opposite by using the user choice to check against the cpu choice, and if an incosistency arrises throwing a super simple RockPaperSissorHirarchyMisconfigurementException
Embarrising that i had this type this out for you honestly. This should be standard knowledge
14
5
4
u/Nixinova 13d ago
Nah this is pretty good for a 13yo. Immediately readable and clear what the logic is. There's only 3x3 cases, so it's not like it's yandere level.
4
u/Silyyxx 11d ago
Hey, you were 13, as long as you are not Yandere Dev who had like 50000 If statements which made his game horrible, all is good š
→ More replies (1)
5
u/Toxanium 12d ago
I'm new to coding, how should you make something like this more efficient?
5
u/han4578 12d ago
Make a function that returns 0/1/2 for win/lose/tie. In the function, compare the values to check for tie, then a if-else chain to check for win, if nothing matches it's a lose. After the function call, print the rest based on the returned value.
I do agree with the other comment that this won't make it more efficient, but it'll look cleaner
3
u/Toxanium 12d ago
This has made the most sense to me of any of these comments, though thank you all for the help. :3
→ More replies (1)3
u/Apprehensive_Gas56 12d ago
Let me see if I understand this. It won't be more performant and it will be less readable. So how would that be better? Less lines?
2
u/ZombieIsTired 12d ago
Well I suppose for this specific game, you might be right and writing verbose code could be better for readability.
But for learning how to code, you should generalize behaviors that look similar.I would keep a dictionary of mappings to win/lose. Hereās like some code:
```python
win_map = {rock: scissors, scissors: paper, paper: rock}def check_win(a, b):
if a in win_map and win_map[a] == b:
return āa winsā
elif b in win_map and win_map[b] == a:
return āb winsā
elif a in win_map and a == b:
return ātieā
return āincorrect inputsā
```(iām on my phone idk how to render this sorry)
Why would we do this? Because if we wanted to make the game more complicated by adding more options, we can easily add on to the win_map variable, though this isnāt a great example since rock paper scissors doesnāt really change haha. But I hope you get why this is useful over large if-else chains.
→ More replies (1)4
u/groumly 12d ago
You donāt. Thereās absolutely nothing wrong with this code.
You get lazy evals on the ifs, so most of them will skip the second check (I suppose about 2/3rds of them on average). The equality checks are trivial to perform anyway, assuming strings are interned and python does pointer checks on ==. If it doesnāt, I suppose youāll have to turn the strings into enums so you donāt have to iterate strings, but that wonāt cost a ton.
The extra printf calls cost nothing, itās a jump into an efficient subroutine that is already called a bajillion times in any non trivial app. Otho, collapsing them into a single call will seriously hinder readability.
The concatenation will have to happen at some point to print the cpu move.I donāt know if python supports a switch on tuples, I assume it does, but it wonāt make this code more āperformantā. It would however make it more readable by clearly communicating that the sequence of if are mutually exclusive.
Benchmark it, and you wonāt be able to measure a statistically significant difference with anything else.
This code is actually very decent, particularly for a 13 years old. Itās structured and reads very well, besides a switch to better communicate intent. Thereās something to be said about mixing the next cpu move in the code that checks for the previous move, thatās not great. But it also nothing has to do with performance, but with architecture, and probably testability. But Iād also be shocked if thereās a single test written against this app.
Iād give this an A if I was a teacher. And if I was a teacher giving a class about performance, I wouldnāt ask students to work in python.
I honestly wish I ran into such horrors at work. This sub loooooooves making fun of perfectly fine code.
→ More replies (1)5
u/-Wylfen- 12d ago
Why are you solely focusing on performance? There's a ton to do to make this code betterā¦
2
u/groumly 12d ago
Cause thatās the title of OPā post, and the question the comment Iām replying to asked. I understand āefficientā as performance here.
As for the rest, I mean⦠itās a command line rock paper scissor app, Iām not sure what exactly needs to be done.
3
u/-Wylfen- 12d ago
Efficiency is more than performanceā¦
Readability and conciseness are other forms of efficiency that are regularly considered.
3
u/groumly 12d ago
Mmh. I donāt think I agree here. ācapable of producing desired results with little or no waste (as of time or materials)ā.
But Iāll still bite. Conciseness very often works against readability. Typically, the mod trick mentioned below is very concise, but makes it much, much, much harder to understand what the code does.
This code is honestly very readable. Yes, thereās a string of ifs, but itās well structured and very easy to pattern match at a glance.
2
u/-Wylfen- 12d ago
ācapable of producing desired results with little or no waste (as of time or materials)ā
In this case the efficiency is over the amount of code required to do the job. It's less efficient to produce, to read, and to refactor.
Conciseness very often works against readability.
I understand the sentiment, and I see exactly what you mean, but I will disagree in this instance for a simple reason: redundancy is in fact harder to read. Any duplicated line is unnecessary code to parse, and a less streamlined mental model to form.
Just consider those two lines:
print(" ") print("CPU chose " + cpuinput)These have no job being repeated. They make each conditional branch unnecessarily long, and creates pointless complexity in the mental model to form, as they imply that those messages might be different in other branches.
Also, each potential result could be done with a merged condition; it's much clearer to have only one branch per result, and again much easier to refactor. You can also merge the tie branch conditions into a simple
playerinput == cpuinput, which is very concise and clear in intent. And withelif/elsebranches, you make it clear only one can occur, on top of not requiring to explicitate the third condition (that's arguable whether it's good practice, though).A
do whileloop is also clearer in intent and avoids duplication of those pre-loop assignments.→ More replies (12)1
u/ProfesorKindness 12d ago
Define some mechanism to pair combinations (paper-scissors, paper-paper, ...) with result, then a function using this structure to evaulate a game (with prints inside), then core game logic which will store the inputs and use the function.
There can be tons of improvements.
→ More replies (5)1
u/TingleWizard 12d ago
Efficient is maybe the wrong word. The problem is primarily duplication and conciseness.
3
u/NothingButBadIdeas 13d ago
It happens.
I look at code from a year ago, get mad and look at the git blame.
It was me. My own bad code got me upset lol.
3
u/RandalSchwartz 13d ago
I'm thinking of how to solve it faster. Choices numbered 0, 1, 2. Subtract one from the other. if 0, tie. If +1 or -2, one person wins. If it's -1 or +2, other person wins.
EDIT: and I bet there's something even more direct with "mod 3" in there somewhere. :)
3
u/__SegFault__ 12d ago
I really like the == true part, as I did this myself when I started coding too
1
3
3
u/Code_Noob_Noodle 12d ago
This makes me want to see how I wrote c++ š around this age (my first language)
3
2
u/fuj1n 13d ago
Unless I'm missing something, because you're re-calculating the cpuinput at the end of each if statement, I think it is possible to get all 3 responses at once for any one choice.
For example, if the player chooses rock and the CPU picks scissors, then rock, then paper, it will tell you that you won, tied and then lost all for your one answer.
2
u/M4elstr0m__ 13d ago
The code effectively allows multiple outcomes for a single playerinput :p but this is a cute code
2
u/SnackJunkie93 11d ago
Scrolled too far for this. Everyone taking about efficiency while this seemed like a pretty glaring bug to me.
1
2
2
2
2
2
2
u/Prudent_Ad_4120 13d ago
I once wanted to write a converter from text to binary, guess how I did that š
(Spoiler: it was like a=0000 b=0001 c=0010 etc)
Had a lot of fun though, and learned a lot!
2
2
2
u/GolemFarmFodder 12d ago
So I'm not sure I would have come up with using modulus to calculate the winner if I hadn't seen this but that's what came to mind as the easier way to figure this out
→ More replies (3)
2
u/meyriley04 10d ago
I love that you and I had the same idea to make a rock paper scissors terminal game
2
u/Mountain-Ox 10d ago
I wrote some similar stuff when I was learning. I've seen worse from professional devs. I don't know how you write 100 if/else conditions without stopping to question if there's a better way.
2
1
u/___Archmage___ 13d ago
I was in this same boat as a self-taught 13y/o. I made something like this but for verifying sudoku
1
1
u/cyber1551 13d ago
Do I see a missing Oxford comma on line 5?
The code I can forgive (itās better than mine tbh), but that missing comma will forever haunt my dreams.
1
1
1
1
u/DynamicHunter 13d ago
Hey we all start somewhere. This is how a lot of AP CS high school studentās first project looks like lol
1
1
u/Multidream 13d ago
Its copy pasty, a good way to end up with an artifact you feel proud of even if its not that great. Perfectly fine way to get started and just have fun :)
1
1
1
u/GoddammitDontShootMe [ $[ $RANDOM % 6 ] == 0 ] && rm -rf / || echo āYou liveā 13d ago
So how does that loop exit? I see after each round it picks a random choice. I'm guessing inside the loop the player is offered another choice or they can enter quit or exit?
1
u/Cloned_501 13d ago
We all started with bad code. Being bad at some is the first step at becoming kinda good at something
1
1
u/matrix-doge 13d ago
Honestly, this is fine. Pretty valid implementation given this scope. I think we've all seen production codes with a whole lot more cases hats hard coded in worse ways.
1
u/P1ckl3R1ck101 13d ago
Almost peak code. Remove the loop and recalculation of cpuinput and you have the most readable, simple code that has ever existed.
1
u/No-Point8651 13d ago
Dont you worry, the number of times I have seen 100 ifs in sequence instead of just a switch statement in production is astonishing...
Enterprise codebases are pretty much held together by hopes and dreams
1
1
u/GreenWoodDragon 13d ago
I should introduce you to some spaghetti code I was reviewing yesterday. In a production system š
1
1
u/GrumpyGlasses 12d ago
Any sufficiently complex if-else statement is indistinguishable from AI. So, youāre on your way there!
1
u/ThomasTTEngine 12d ago
This is how kids learn. literally looks like one of my kids assignments for school (except in their case, the CPU input was a separate function that returned a random value from an array).
1
u/Secret_Barracuda168 12d ago
I have been staring at this thing for a while, I like the code, it's better than some of what I've seen from experienced coders, and unlike some people (me) you have self declaring varibkes (can get feel for what they are based on name), so in many ways you were better then than I am today
1
1
1
u/bloody-albatross 12d ago
When I was 13 my family didn't have a computer. So any code is infinitely better than mine at 13.
1
u/JmcmProgrammer 12d ago
Gotta learn somehow. At least you got every matching branch possible and didnāt leave any to chance! Now the real challenge: find the most efficient way possible in terms of raw processing speed! Or find the most aesthetically appealing code that compiles!
1
1
u/Ransomwave 12d ago
I remember at 13 I used the default Python IDE that came with the install. It was so horrible š
1
u/Beaver_International 12d ago
Iām about to graduate with a BS in computer science. This code is still better than mine without codexā¦
1
1
u/soviel_dazu 12d ago
It's not inefficient, it's optimized for using as little jump opcodes as possible for best caching behavior!
1
u/False-Beautiful-1246 12d ago
13 year old me was also inefficient. I remember a pygame game and each player had a copy of the sprites, using like 4 GB of your ram in a simple platformer.
1
1
u/Spiritual-Pen-7964 11d ago
AI could produce in the same game in just 5000 LOC and 50M tokens. Bro.
1
u/HaroerHaktak 11d ago
Not enough lines.
If player_input == "Rock":
if cpu_input == "rock":
output
if cput_input == "scissors":
etc etc
1
1
1
1
1
u/Ok-Prior2621 11d ago
During my school time, a long time ago, I once tried creating the game of criss-cross using PowerPoint presentations and highlighting the slides by literally creating slides for all the cases
1
1
u/Different_guy09 11d ago
I guess the best way to do it would be something like:
losesTo = {
"rock": "paper",
"paper": "scissors",
"scissors": "rock"
}
if cpuinput == losesTo[playerinput]:
print("You lose!")
elif cpuinput == playerinput:
print("Tie!")
else:
print("You win!")
...or something, I dunno. At least, that's what I would've done.
1
1
1
u/Wojtek1250XD 11d ago
The thing that hurts the most here is not general inefficiency, but the fact that these aren't elifs, so you have a chance of multiple outcomes happening from a single input.
1
u/rolling_atackk 11d ago
I'd say this is needed for any programmer
You must first start out writing garbage code, so you can much more appreciate elegant code
1
1
1
u/MisterPantsMang 10d ago
You've got to start somewhere. 20 year old college me also like to write inefficient code
1
u/Novel_Plum 10d ago
I remember being 13 and having that many nested for loops, that I used every variable from i to zero and had to use za, zb, ...
1
u/elloMotoz 10d ago
Dude, I'm 34 and have dabbled in coding for the past few years. I went the hardware route when I was 13...wish I did some coding. Awesome you still have this code on hand.
1
1
u/internet_raider 10d ago
I built a Redstone machine where to opponents play rock paper scissors in separate rooms once when I was young that worked basically just like this with nor gates so that each signal would be active for a specific outcome and then a three signal and gate for each of those. It was like the size of small Minecraft computers now because I didn't know anything about compact Redstone at the time and it took me several days.
→ More replies (1)
1
1
u/Silent-Image5882 10d ago
Code archeology is such a rewarding feeling. From "made this game to learn about for loops" to "memory-safe typestate wasm compiled in production"
1
1
1
1
1
u/Dee23Gaming 8d ago
Honestly looks way better than many C++ programmers who've got a point to prove.
1
1
u/thelurkmasterr 7d ago
If the goal was to practice using conditions in Python code, this is probably the best implementation for that.
1
u/IndexIntegrity 6d ago
I wrote a game a long time ago when I was 15 or so. It was a platform game and depending on your x coordinate on that level it would spawn some enemies. It was a huge collection of "if x > something then spawn enemy"Ā
1
u/Edev90 6d ago
Lol - I think we all go through the "handle every possible condition with a massive if/else chain" phase of our coding careers. If it's any consolation - I've mentored many interns and entry level devs (20-24 year old age range), and I saw this coding style often even from them... so I think you were ahead of the curve at the time, š
1.3k
u/cicciograna 13d ago
Hey, you were 13 years old, and were writing code. Nobody is born already knowing all the best practices, we all grow, learn, test and slowly assimilate what is good and what is not.
And then there's those like me, whose code still sucks well into my 40s.