0

I am making new program in Python (Mastermind). I have a problem with references of variables:

def user_turn():
    try_counter = 1
    user_code = []
    guessed_code = random_code()
    print("Twoja kolej na zgadywanie!")
    while try_counter <= max_tries and user_code != guessed_code:
        good_number, good_number_and_position = 0, 0
        appearance_types_guessing_code = [0 for i in range(types)]
        appearance_types_user_code = [0 for i in range(types)]
        user_code = input("Próba nr {}: ".format(try_counter))
        user_code = list(map(int, str(user_code)))
        count_xos()
        print_xos()
        try_counter += 1

    print_result_user_turn()

Body of the function print_xos():

def print_xos():
    for i in range(good_number_and_position):
        print("x", end='')
    for i in range(good_number):
        print("o", end='')
    print("")

And my problem is that in function print_xos() variables good_number and good_number_and_position are unknown, despite of fact I declared this variables in the while loop in the body of the function user_turn(). How can I solve this problem? I don't want to send the reference as an argument of the function. In my opinion it isn't elegant. Is it possible to do it in another way?

EDIT:

OK, I changed a code a little bit then:

def user_turn():
    try_counter = 1
    user_code = []
    guessed_code = random_code()
    appearance_types_guessed_code = [0] * types
    how_many_appearance(guessed_code, appearance_types_guessed_code)
    print("Twoja kolej na zgadywanie!")
    while try_counter <= max_tries and user_code != guessed_code:
        good_number, good_number_and_position = 0, 0
        appearance_types_user_code = [0] * types
        user_code = input("Próba nr {}: ".format(try_counter))
        user_code = list(map(int, str(user_code)))
        how_many_appearance(user_code, appearance_types_user_code)
        print(appearance_types_guessed_code, appearance_types_user_code)
        count_xos(guessed_code, appearance_types_guessed_code, user_code, appearance_types_user_code, good_number, good_number_and_position)
        print(good_number_and_position, good_number)
        print_xos(good_number_and_position, good_number)
        try_counter += 1

    print_result_user_turn(guessed_code, user_code)

And the body of function count_xos:

def count_xos(guessed_code, appearance_types_guessed_code, user_code, appearance_types_user_code, good_number, good_number_and_position):
    for i in range(len(appearance_types_guessed_code)):
        good_number += np.min([appearance_types_guessed_code[i], appearance_types_user_code[i]])

    for i in range(code_size):
        if guessed_code[i] == user_code[i]:
            good_number_and_position += 1
            good_number -= 1
    print(good_number_and_position, good_number)

And I got this output:

RUNDA 1
Twoja kolej na zgadywanie!
Próba nr 1: 0011
[0, 2, 0, 1, 0, 0, 0, 1, 0, 0] [2, 2, 0, 0, 0, 0, 0, 0, 0, 0]
1 1
0 0

You can be certain that function count_xos counts good_number, good_number_and_position counts properly. It should be 1 1, but I don't know why after running the method count_xos, variables good_number_and_position, good_number are not changed?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • 3
    quite the contrary, the elegant solution is for your function to receive those values as argument, not to rely on those being set as global variables outside the function. – njzk2 Mar 03 '19 at 07:43
  • as a side note, `[0 for i in range(types)]` is better written as `[0] * types` – njzk2 Mar 03 '19 at 07:46
  • Read about [Scoping rules](https://stackoverflow.com/questions/291978/short-description-of-the-scoping-rules) - it it best to keep the scope as small as possible and provide data to the function they need. There is seldom need to do something `global`. – Patrick Artner Mar 03 '19 at 09:09

1 Answers1

0

Your last attempt does not return the numbers so the provided numbers do not carry out into your calling function.

Your code does the equivalent of:

def one(aa,bb):
    aa *= 2
    bb *= 3
    print("In function", aa, bb)
    return aa, bb

a = 5
b = 11
one(a,b)      # does not reassign returned values - similar to not return anything like yours
print(a,b)

Output:

In function 10 33
5 11   

You need to return and reassign the values:

a,b = one(a,b) # reassign returns
print(a,b)

Output:

In function 10 33
10 33

Have a look at Scoping rules - it it best to keep the scope as small as possible and provide data to the function they need.

If you modify things inside function return its new values and reassign them - this is not deeded if you pass a list, they are mutable references and "autoupdate" because you operate through the ref on the data:

# same function used as above

a = 5
b = [11]
one(a,b)
print(a,b)

Output:

In function 10 [11, 11, 11]
5 [11, 11, 11]

If you take a look at the id()s of the variables you can see that altering aa will repoint the name aa to some other id - but a on the outside still points to the original one. Altering the list does not alter the reference-id - it alters the data the ref "points" to:

def one_ids(aa,bb):
    print(id(aa),id(bb))
    aa *= 3   # modify an integer
    bb *= 3   # modify the list
    print(id(aa),id(bb))

a = 5
b = [11]
print(id(a),id(b))
one_ids(a,b)
print(id(a),id(b))

Output:

139647789732288   139647790644808   # id of a,b
139647789732288   139647790644808   # id of aa,bb before changing
139647789732**6**08   139647790644808   # id of aa,bb after changing
139647789732288   139647790644808   # id of a,b 

You can read further in Function changes list values and not variable values in Python - see if those explanaitions fit you better.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69