exercism / python

Exercism exercises in Python.
https://exercism.org/tracks/python
MIT License
1.94k stars 1.29k forks source link

Currency Exchange Instructions & Variable Descriptions Need Updating? #2591

Closed devi0s closed 3 years ago

devi0s commented 3 years ago

Has anyone taken a look at https://exercism.org/tracks/python/exercises/currency-exchange lately? Does anyone else think the instructions and variable descriptions need to be expanded for "5. Calculate value after exchange" and "6. Calculate unexchangeable value"? Apologies if it makes perfect sense to others but I just can't wrap my head around it as constructed. For example, 5 seems to actually be asking for the rounded number of foreign bills you'd have after the exchange times the value of each bill which is not what I would think "value after exchange" means. Furthermore, the instructions show:

exchangeable_value(127.25, 1.20, 10, 20) 80 ... and I think the working/accepted solution with those parameters would actually return 100.

J08K commented 3 years ago

Hiya, thank you for (as I can see) your first Issue! You want to update the instructions of exercise number 5 & 6. The name function exchangeable_value does imply that it is the value and not number of bills, but I do think that the number of code blocks used in the instruction is a little much and it makes it crowded. Might write a separate issue myself for that. :)

Exercise 5 is asking for the actual value of the bills that have been exchanged, since you cannot get half bills. I did the calculations of the example by hand again and I did get 80 as well. Are you rounding up the 4.8 to a 5, because that will equal to 100, which wouldn't be allowed because the exchange office would be giving you free money. Here are my hand calculations:

budget = 127.25
exchange_rate = 1.20
spread = 10%
denomination = 20

actual_exchange_rate = exchange_rate * (1 + spread/100)
actual_exchange_rate = 1.20 * (1 + 10 / 100)
actual_exchange_rate = 1.20 * (1 + 0.1)
actual_exchange_rate = 1.20 * 1.1
actual_exchange_rate = 1.32

exchanged_value = budget / actual_exchanged_rate
exchanged_value = 127.25 / 1.32
exchanged_value = 96.40151515...

# The exchanged value is not divisible by 20, so you won't get 5 bills, since 5 * 20 = 100.
# To get the number of bills of 20:

bills_exchanged = exchanged_value // denomination
bills_exchanged = 96.40151515 // 20
bills_exchanged = 4
# The '//' operator means "floor division", so it only calculates a natural number and doesn't return anything decimal.

# After this, you just want the actual value of those bills.
end_value = bills_exchanged * denomination
end_value = 4 * 20
end_value = 80

I hope this atleast explains why you would get 80 and not 100.

Please let me know what you exactly mean, but you could also fork the repository, change the instructions to what you think is better. Then you just submit a PR and link that PR to this issue. If you need any help with that, feel free to contact me on Slack (My name is Job van der Wal or J08K).

Let me know!

solt87 commented 3 years ago

@J08K Thank you for the worked example, that explains it. Like @devi0s, I also had problems with understanding the instructions. Unless someone beats me to it, I'd like to open a pull request with proposed changes, but I'd also appreciate some preliminary feedback on the following ideas:

IsaacG commented 3 years ago

I also found the exercise quite confusing. I think the naming and word crafting could benefit from more clear language.

J08K commented 3 years ago

This exercise, like a lot of other python exercises, has a lot of things that we need to change/revise. @BethanyG and I are trying to get it all done, but we do rely on your help. So please do submit a PR, but we might need to do some other work on this exercise, just to make it fully working for this version of the website, since it was ported from V2.

If @devi0s wants to work together on this with you, @solt87 and @IsaacG, I would be all for it! I love collaboration. I'll talk with @BethanyG about what exactly needs to be changed about this exercise and I will let y'all know! For now, a PR would be greatky appreciated! :)

Rafeqm commented 3 years ago

Hello, I go straight right into this repo to create an issue to express my depression and confusion after lots of trying to understanding what exactly the instructions tell me to do. But I found this issue first. So without explaining what is my issue just is:

[EDIT] In regard to this, I suggest to change the naming conventions:

  1. estimate_value() --> change_currnecy()
  2. get_value() --> get_bills_value()
  3. get_number_of_bills(budget, denomination): --> get_number_of_bills(foreign_value, denomination)
  4. exchangeable_value() --> get_exchangeable_value
  5. unexchangeable_value --> get_unexchangeable_value()

I hope by this way, others can comprehend better.

J08K commented 3 years ago

Hey @Rafeqm, I can understand your confusion, this exercise is definitely not perfect, but we are working to make that better.

Task 3: The exercise is not about exchanging currencies or about money. The exercise hopes to explain to a student how numbers work in Python. A simple multiplication is quite important to learn in Python. Plus, understanding this task sets the student's brain into thinking. get_value() is also useful for task 5 & 6 because you can use the function inside of these two tasks.

Task 4: The type of currency should not matter, currency around the world (I think) works the same in this regard. We want the solution to return the maximum number of bills you can get from the budget. This result is achieved by doing a floor division using the // operator. The // just returns the natural number of a division, so floating point decimals are excluded. The tasks solution is practically just:

def get_number_of_bills(budget, denomination):
    return budget // denomination

It is just about the numbers, the student has to realize that the type of currency does not matter here.

Task 5 & 6: The instructions can indeed be really confusing at first, but most people understand it after trying some code and reading the instructions a few times. We will be working on this: Shortening the sentences, making it more clear what exactly has to happen, etc. But right now, me and especially @BethanyG are extremely busy with getting the most important parts of the Python track done and fixed.

Naming conventions:

Thank you for your ideas, @Rafeqm. It really helps. Please continue to use this issue to coordinate the exact way currency exchange needs to be better explained. Please use PEP8 as your guidelines, because that is the way we are teaching students to code Python as well. :)

Rafeqm commented 3 years ago

I found that in HINTS.MD, \\ should return float if both operands is float. But you said it exclude decimal number, which one is true? Sorry the Python docs is a bit hard to navigate.

J08K commented 3 years ago

@Rafeqm, Sorry, it will still return a variable of type float, but the decimal will be .0. So this is an example:

a = 11.0
b = 5.0

a / b                     # Normal division, returns: 5.5
a // b                    # Floor division, returns: 5.0

If you want to get an integer, convert it to an integer.

Please do keep in mind that this issue is about improving the exercise and not about me explaining the ins-and-outs of it. Please if you have any questions. Ask your mentor, or if you're really stuck, please post it in the #track-python channel on slack. Good luck!

joaoguilherme1 commented 3 years ago

For me the task 5 and 6 was confusing because he needs the maximum value (?) but doesn't explain for what. If you guys add something like amount to pay the bills or something like that will help, in my opinion :).

"This function should return the maximum value you can get to pay the bills considering the budget, exchange_rate, spread, & denomination."

And maybe integrate the necessity to pay the bills on the instruction history will help the user to think on int() numbers and the // operator.

J08K commented 3 years ago

Heya @joaoguilherme1, Thanks for your comment. Maximum value refers to the maximum_amount_of_bills * denomination, in turn you will need to re-use your code from previous functions in your solution to finish the tasks.

def exchangeable_value(budget, exchange_rate, spread, denomination):
    """

    :param budget: float - the amount of your money you are planning to exchange.
    :param exchange_rate: float - the unit value of the foreign currency.
    :param spread: int - percentage that is taken as an exchange fee.
    :param denomination: int - the value of a single bill.
    :return: int - maximum value you can get
    """
    return get_value(denomination, get_number_of_bills(estimate_value(budget, exchange_rate * (1.0 + spread/100)), denomination))

This is my one-liner to solve task 5, it's not the most pretty, but it does work and it's compact. Please do not use this example for when you're mentoring, this is just a showcase that it is a good idea to re-use the code you already wrote.

In my opinion, I do not think it's a good idea to add "pay the bills" to that sentence, as it adds more words (=more information for the student to swallow) to the sentence. We could add something to hints.md and show them a bit more information there, but adding more to the instructions is something that we have to watch out for.

I'll be making an issue about this exercise where I will put all the improvements that need to happen to it. Then we'll ask someone to do that.

BethanyG commented 3 years ago

Thank you all for your discussion and suggestions! 🌟 🌈
I have logged issue 2594 as a task list of what needs to be done to improve this exercise.

It's currently assigned to @J08K -- but anyone here is welcome to help with a PR. Please coordinate with @J08K if you do so.

Minamikaze392 commented 3 years ago

I don't understand the meaning of bills... I thought if that are some additional charges I need to pay during the exchange...

And what means the unexchangeable_value in Task 6? Should it mean the remaining budget after the exchange, in the original currency (Should be USD in this Exercise, and would be float instead of int)?

J08K commented 3 years ago

Hey @Minamikaze392, could you please clarify what you mean with bills, there are a few times bills is mentioned in the exercise.

About task 6, the unexchangeable_value() function returns the value (in the foreign currency) that is not able to be exchanged due to it not being properly divisible by the denomination. I am currently rewriting the instructions to make matters like these more clear. We are working on it in #2594.

People, I would like to make it clear, these issues are for improving the exercise itself. If you do not understand the exercise, please contact a mentor. If you need help with an exercise and cannot contact us via Exercism.org, please do not hesitate to join the #track-python channel on our slack. Thank you.

BethanyG commented 3 years ago

Closing this discussion. Items to improve are listed under #2594.

MondoBurrito commented 2 years ago

I know this is late to the game, but as a beginner, I too found most of this exercise VERY confusing. Especially part 6. And the worst thing is that I can get the answer I need when I code in Replit. But when I copy and past that code over to Exercism I get failed. I have resorted to asking Reddit for help, but those guys are confused as well. And as a beginner, I have problems even knowing what questions to ask, or how to properly articulate what I need help with. So some better hints in the instructions would be nice. After a few days of slugging away at part 6, I still can't figure it out.

BethanyG commented 2 years ago

Hi @MondoBurrito 👋🏽

Thanks for your comment. 💙

We do indeed have problems with this exercise, and have an open issue to re-examine and re-work it. We just need to get the bandwidth/volunteer time/space to do so! See issue #2951 for all the linked problems, rationals, attempts and ... discussion. Feel free to add thoughts and suggestions there as well.

My apologies that that this has been a struggle. It was far from our intention to make learning about numbers in Python this difficult! Two suggestions for you at this point:

  1. There are some really friendly and helpful people who hang out on our (just launched!) exercism forum in the Programming --> Python category. They'd be very interested in talking you through your struggles with task 6 in this problem. They'd probably also be really interested to hear your thoughts on how to make the exercise better (as would I!!).
  2. There is an exemplar solution to this problem stored in this repo, and reviewing it might help you make sense of what is being asked, and what you might do to solve the problem in code. And no -- looking at it is not cheating, especially since you are stuck and frustrated and demotivated. We're here to help you learn -- and sometimes, you just need to review someones solution to get unstuck. 😄

So I hope those two things help a little. And I hope the next exercise is way less frustrating for you! Here's to making your experience going forward a better one.

MondoBurrito commented 2 years ago

Thanks for the reply. My main issue is that this exercise jumps right into mathamatical formulas. I know there are a few hints here and there, but it just felt overwhelming. I think this was a case of the challange asking too much from a beginner all at once. It is better to be eased into problems like this, rather than throwing us in head-first. At this point, I was 100% fine with the syntax... it was figuring out the math that I failed at. I did eventually look at the solution. I still feel conflicted about this because every single other learning resouce preaches to NOT look at solutions. So I am left banging my head against the wall going around in circles for days... when all I need are some hints to keep my momentumn in a forward direction. Anyway. Sorry for complaining, but I just hate having to give up and look at the solution. It shows that I failed to figure it out myself.

modulok commented 1 year ago

Section 6 is still confusing. I felt like I was doing my taxes.

BethanyG commented 1 year ago

@modulok -

While I empathize, it would be better if you either added your comments to the thread referred to above, or discussed the topic on the forum. Many thanks!