1
\$\begingroup\$

I tried to make a python code that would answer the Joseph problem. I really had a hard time with this and the try blocks was the only thing I could come up with. Can anyone tell me if the way I did it is valid or I have to rewrite the code because its too bad?

The problem is:

People are standing in a circle waiting to be executed. Counting begins at a specified point in the circle and proceeds around the circle in a specified direction. After a specified number of people are skipped, the next person is executed. The procedure is repeated with the remaining people, starting with the next person, going in the same direction and skipping the same number of people, until only one person remains, and is freed.

The problem — given the number of people, starting point, direction, and number to be skipped — is to choose the position in the initial circle to avoid execution.

My solution:

class Game:
    def __init__(self, n):
        self.n = n
        self.ppl = []
        self.has_gun = 1

    def creating_list(self):
        for i in range(1, self.n+1):
            self.ppl.append(i)

    def kill(self):
            number = self.ppl.index(self.has_gun)
            try:
                print("{} shoots {}".format(self.has_gun, self.ppl[number + 1]))
                del self.ppl[number + 1]
            except IndexError:
                print("{} shoots {}".format(self.has_gun, self.ppl[0]))
                del self.ppl[0]
            try:
                print("{} gives his gun to {}".format(self.has_gun, self.ppl[number+1]))
                self.has_gun = self.ppl[number + 1]
            except IndexError:
                if len(self.ppl) > 1:
                    print("{} gives his gun to {}".format(self.has_gun, self.ppl[0]))
                else:

                    print("{} is the only one remaining person in the circle".format(self.ppl[0]))
                self.has_gun = self.ppl[0]
            print("*" * 40)

    def run(self):
        self.creating_list()
        while True:
            self.kill()
            if len(self.ppl) == 1:
                print("{} survives".format(self.ppl[0]))
                break

while True:
    try:
        question = int(input("How many people in the circle do you want to be?\n"))
        break
    except:
        print("Type a number\n")
cos = Game(question)
cos.run()
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$
  1. You can simplify the code if you use (number + 1) % len(self.ppl). This is as it loops back around to the front of the list for you.
  2. If you remove the prints then the code is easier to understand.
  3. You can change creating_list to list(range(...)).
  4. You don't need creating_list to be its own function.
  5. You can combine run into kill removing the class. Leaving:

    def game(n):
        ppl = list(range(1, n+1))
        has_gun = 1
        while True:
            number = ppl.index(has_gun) + 1 % len(ppl)
            del ppl[number]
            if len(ppl) > 1:
                number = ppl.index(has_gun) + 1 % len(ppl)
                has_gun = ppl[number]
            if len(ppl) == 1:
                return ppl[0]
    
  6. You can move the if len(ppl) == 1: check into the statement of the while loop. This makes it easier to see that the function will always return.

  7. You should rename your variables to make it easier to understand things. people over ppl.
  8. Rather than using people.index store the index.

    def game(people):
        people = list(range(1, people+1))
        index = 0
        while len(people) >= 1:
            index = (index + 1) % len(people)
            del people[index]
        return people[0]
    
  9. Error if there is less than one person.

  10. Allow taking a custom skip.

And you'd get to the function that I wrote to test your code:

def josephus_problem(people, amount):
    if people < 1:
        raise ValueError("There has to be at least one person")
    people = list(range(1, people+1))
    index = 0
    while len(people) > 1:
        index = (amount + index) % len(people)
        people.pop(index)
    return people[0]
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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