Python Forum

Full Version: Stuck with using lists to solve task
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi everyone,

I am struggling with solving below task which I received as a home assignment in my Python course to practice lists (I've been learning Python loosely for a few months).

Task description (translated from Hungarian):

"On the occasion of the Turkish Sultan's birthday, he sent his first servant to the prison to open the doors of all 100 cells. The Sultan had his second servant close every second door after him. With the third servant, the Sultan made him open every third door in case it was closed, and closed it if it was found open. The fourth slave changed the state of every fourth door, and so on, up to the 100th slave. Which cell doors were left open at the end?"

This is where I got so far:

Basically I was trying to use for loops to close/open every 2nd/3rd/4th doors in a sequence. But this only gets me until the fourth slave while the task requires 100 slaves and also it doesn't quite seem correct up to that point either. So I'm out of my depth at this point. Undecided
Could anyone help me with finding the solution? I guess it needs some other approach...

("t" is list)

t=[1]*100
for i in range(0,len(t),2):
    t[i]=0
for i in range(0,len(t),3):
    if t[i]==1:
        t[i]=0
    else:
        t[i]=1
for i in range(0,len(t),4):
    if t[i]==1:
        t[i]=0
    else:
        t[i]=1
print(t)

for i in range(len(t)):
    if t[i]==1:
        print(f"{i+1}. cell: open")
    else:
        print(f"{i+1}. cell: closed")
this is much easier if you define a function:
example:
# zero = open, 1 = close
doors = [1] * 100        # assumption all doors closed at start ... change to 0 if all open

def change_door(door_list, action_every=1, open_close='open'):
    doornum = action_every - 1

    while doornum < len(doors):
        if open_close == 'open':
            doors[doornum] = 0
        else:
            doors[doornum] = 1
        doornum += action_every

# example open every third door:
change_door(doors, action_every=3, open_close='open')
print(doors)
After running example doors:
Output:
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1]
Hi and welcome.

No doubt there are a few different ways this could be done, such as using 0 and 1 for the status of the cell doors. Then, you could use if door: which would return True or False for 1 and 0. That way, you don't need to code if door == 0:, but I would go with a more literal approach and you may not have been introduced to constructing custom functions yet.

I would use the step parameter of the range function. Have you learned about that?

As an example, this will close every other door, as the second servant has been asked to do.
door_open = "open" # door is open
door_closed = "closed" # door is closed

cell_doors = [door_open]*100 # open all the doors

for door in range(1, 100, 2): # close every second door
    if cell_doors[door] == door_open:
        cell_doors[door] = door_closed
The above is where I would start from: it sets all the doors to 'open' and then closes every second door. Technically, you don't need the if: branch at this stage, because we know the status from the get-go, but I've put it in, for completeness.

Caveat: this potential solution is simply my first thoughts and I'll have a think some more about if it's going to be practical or not.

To add: I think this could work, if you set up servants = range(1, 101) then nest for servant in servants: with what I have above, using servant as the 'step' parameter, and simply alternate each door (if it's closed, open; if it's open, close it). For that to work, start with all of the doors closed, not open, and 0 as the first door, not 1.

I can't be more specific, without breaking the Forum rules; I'm close to doing that, as it is.
If using 0 and 1 to represent closed / open doors it's simple to toggle value using XOR (bitwise exclusive OR). Something along those lines (just an idea, haven't tested it):

# 1 means door open, 0 mean doors closed
# create list of 100 doors open
doors = [1] * 100

# toggle every second value
for i in range(1, 100, 2):
     doors[i] ^= True

# toggle nth value with nth step
for n in range(2, 101):
    for i in range(n, 100, n):
        doors[i] ^= True

print(doors)
print(sum(doors))
At last an entertaining question, it's been a while.
I'm interested in the result, so here is my solution (True = open),
Anybody. ? Wink
1 True
4 True
9 True
16 True
25 True
36 True
49 True
64 True
81 True
100 True
Paul.
(Jan-16-2024, 06:57 AM)DPaul Wrote: [ -> ]I'm interested in the result, so here is my solution (True = open),
Anybody. ? Wink
I think the result is True if the number of divisors of n is odd. The number of divisors of a number is given by the sequence https://oeis.org/A000005. This page says
oeis.org Wrote:a(n) is odd iff n is a square.
All of this needs to be clarified.

This page also contains a python code that uses sympy to get the number of divisors of a number.
(Jan-16-2024, 08:33 AM)Gribouillis Wrote: [ -> ]All of this needs to be clarified.
I interpreted the problem as:
"...The fourth slave changed the state of every fourth door, and so on, up to the 100th ..."
The 5th every 5th door
The 6th every 6th door
....
The 100th every 100th door.
Or ?
Paul
(Jan-16-2024, 08:44 AM)DPaul Wrote: [ -> ]
(Jan-16-2024, 08:33 AM)Gribouillis Wrote: [ -> ]All of this needs to be clarified.
I interpreted the problem as:
"...The fourth slave changed the state of every fourth door, and so on, up to the 100th ..."
The 5th every 5th door
The 6th every 6th door
....
The 100th every 100th door.
Or ?
Paul

Yeah, I came to the same conclusion.

My output is a little more "verbose":

Assuming that we don't use 'zero indexing', rather the first door is #1
Output:
Door: 1 - open Door: 4 - open Door: 9 - open Door: 16 - open Door: 25 - open Door: 36 - open Door: 49 - open Door: 64 - open Door: 81 - open Door: 100 - open
Maybe like this:

# first servant opens all doors
tstart = ['open' for i in range(0, 100)]
#  all doors are open, second servant closes every second door and so on
def change(num):
    for i in range(num, len(tstart), num + 1):
        if tstart[i] == 'open':
            tstart[i] = 'closed'
        else:
            tstart[i] = 'open'
# all servants except the first servant
for j in range(1, 100):
    change(j)

count = 0
for i in range(0, 100):
    if tstart[i] == 'open':
        count +=1

print(f'Finally, {count} doors are still open. Mean old Sultan! Unhappy Birthday!')    
Not sure if j needs to go up to 99, check that.
I find it less complicated that it seems.
Why it is called an exercise on lists, dunno...?
I think that starting like this
open = True
closed = not open
cells = [closed] * 100
saves you at least 10 lines of code.
(you save some if .. else statements)
I do use "enumerate", not knowing if that is allowed.
What is our friend the TS doing in the mean time?
Paul