DM::OJ Slot Machines challenge in Python 3
Code organisation, separation of concerns and tests

The code is a single monolithic piece of code. It could be a good idea to reorganise things a bit: to make it clearer, to make it easier to test, to make it easier to maintain, etc.

The first major improvement could be write a function with a clear input (money, m1, m2, m3) and a clear output solving the issue we care about: computing the number of turns.
The logic handling the input/output is separated from the logic performing the computation - seel also https://en.wikipedia.org/wiki/Separation_of_concerns .

Then, this function could be used with inputs from the user but we could also feed it hardcoded values. This can be used to write tests to ensure that the function behaves properly (at least on the example provided by dmoj).

(In the code provided below, I've a simple assert statement to write the tests but it could be a good chance to read about unit test frameworks and start to use them).

Then, you can add any number of tests easily.

Now that we have unit-tests to prevent us from breaking things too badly, we can start tweaking the code.

Finally, you could use if __name__ == "__main__": to separate the definitions in your code from the code actually using these definitions. It makes your code easier to reuse via the import mechanism.

Style

Python has a Style Guide called PEP 8. It is followed (more or less stricly) by the Python community. It is highly recommended to read it and try to stick to it when relevant. In your case, you have superfluous parenthesis, indentations of 2 spaces instead of 4, superfluous whitespaces.

At this stage, we have:

def get_number_of_games(money, m1, m2, m3):
    """Return the number of games &lt;to be continued&gt;."""
    turns = 0
    while money != 0: 
        #machine 1
        money -= 1
        m1 += 1
        if m1 == 35: 
            money += 30
            m1 = 0
        turns += 1

        #machine 2
        money -= 1
        m2 += 1
        if m2 == 100: 
            money += 60
            m2 = 0
        turns += 1

        #machine 3
        money -= 1
        m3 += 1
        if m3 == 10: 
            money += 9
            m3 = 0
        turns += 1
    return turns

def interactive_main():
    money = int(input())
    m1 = int(input())
    m2 = int(input())
    m3 = int(input())
    print('Martha plays {} times before going broke.'.format(get_number_of_games(money, m1, m2, m3)))

def unit_test():
    """Run unit-tests."""
    assert get_number_of_games(48, 3, 10, 4) == 66
    print("OK")

if __name__ == "__main__":
    unit_test()


Magic numbers

The code is full of magic numbers, making the logic hard to understand.
We could store these values into constant with a meaningful name.

Even better, we could store these into appropriate data structures. For a simple solutions, we could decide to use namedtuples.

from collections import namedtuple

Machine = namedtuple('Machine', ['winning_freq', 'profit'])

MACHINE1 = Machine(35, 30)
MACHINE2 = Machine(100, 60)
MACHINE3 = Machine(10, 9)

def get_number_of_games(money, m1, m2, m3):
    """Return the number of games &lt;to be continued&gt;."""
    turns = 0
    while money != 0:
        money -= 1
        m1 += 1
        if m1 == MACHINE1.winning_freq:
            money += MACHINE1.profit
            m1 = 0
        turns += 1

        #machine 2
        money -= 1
        m2 += 1
        if m2 == MACHINE2.winning_freq:
            money += MACHINE2.profit
            m2 = 0
        turns += 1

        #machine 3
        money -= 1
        m3 += 1
        if m3 == MACHINE3.winning_freq:
            money += MACHINE3.profit
            m3 = 0
        turns += 1
    return turns


Un-handled situations (also known as bugs)

The code is not very robust. A few situations can lead it astray.

Let's take a simple example: we have 1 quarter and the machines haven't been used. This can be written as:

print(get_number_of_games(1, 0, 0, 0))


When we run this, we are stuck into a infinite loop. I'll let you investigate the reason why.

Another example - which could be considered invalid but is definitly worth fixing because of how simple it is: we have a lot of money and the machines have been used a lot. For instance, we have:

print(get_number_of_games(1000, 36, 101, 11))


Assuming we fix the previous issue: how many turns do we play ? How many times have we won ?

As we fix behaviors, you can add corresponding unit-tests to be sure you don't fall into the same issue later on.

Going further

The code relies on duplicated logic to handle the different machines. A better solution could be to handle them via the same logic. We could imagine having a list of machines.

Also, we could imagine having the numbers of turns played on a given machine stored along with the other information in a Machine class. Then, the get_number_of_games functions could take as inputs an amount of money and a list of properly defined Machines.

Take-away for Python and non-Python code


Make your code testable
Make your code tested and correct
Improve it while keeping properties 1 and 2.