Python Forum
Python Connect 4 refactoring
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Python Connect 4 refactoring
#1
Hello, I was wondering if it's possible to refactor this piece of code to make a connect 4 game? I understand that it can be done way more efficiently, but I'm stuck.. Could somebody help me out?

grid1 = [0, 0, 0, 0]
grid2 = [0, 0, 0, 0]
grid3 = [0, 0, 0, 0]
grid4 = [0, 0, 0, 0]

grids = [grid1, grid2, grid3, grid4]

check = []

user = 1


class FullCapacity_error(Exception):
    pass


def playerWins():
    print("player " + str(user) + " has won")


def grid_def():
    print("", grid4, "\n", grid3, "\n", grid2, "\n", grid1)


def user_def():
    global user
    if user < 2:

        user = 2
    else:
        user = 1
    return user


def FullCapacity():
    while True:
        try:
            if grid4[userInput - 1] != 0:
                raise FullCapacity_error
            else:
                break
        except FullCapacity_error:
            print("This row is full, try another one!")
            confirmed()


def confirmed():
    PlayTheGame = True
    while PlayTheGame:
        try:
            global userInput
            userInput = int(input("\ninput a slot player " + str(user) + "(1,4)\n"))
            if userInput < 5 and 0 < userInput:
                PlayTheGame = False
            else:
                print("invalid int")
        except ValueError:
            print("invalid input")


def placement_def():
    for i in range(0, 4):
        counter = 0
        FullCapacity()
        if grids[i][userInput - 1] == 0:
            grids[i][userInput - 1] = int(user)
            grid_def()
            break


def check_def():
    global loop
    global check
    for i in range(0, 4):
        for a in range(0, 4):
            check.append(grids[i][a])
        if check == [1, 1, 1, 1] or check == [2, 2, 2, 2]:
            playerWins()
            loop = False
            return loop

        else:
            check = []
    for i in range(0, 4):
        for a in range(0, 4):
            check.append(grids[a][i])
        if check == [1, 1, 1, 1] or check == [2, 2, 2, 2]:
            playerWins()
            loop = False
            return loop

        else:
            check = []


def checkEmpty_def():
    global check
    for i in range(0, 4):
        for a in range(0, 4):
            check.append(grids[i][a])
    if 0 not in check:
        print("full")


def checks_def():
    check_def()
    checkEmpty_def()
    diagcheck_def()


def diagcheck_def():
    global loop
    global check
    check = []
    diag = 0
    for i in range(0, 4):
        check.append(grids[diag][diag])
        diag = diag + 1
        if check == [1, 1, 1, 1] or check == [2, 2, 2, 2]:
            playerWins()
            loop = False
            return loop

    check = []
    diag = 3
    diag2 = 0
    for i in range(0, 4):
        check.append(grids[diag][diag2])
        if check == [1, 1, 1, 1] or check == [2, 2, 2, 2]:
            playerWins()
            loop = False
            return loop


loop = True

while loop:
    check_def()
    confirmed()
    placement_def()
    checks_def()
    if not loop:
        break
    user_def()
Reply
#2
What exactly is the problem you are having?

I would note that the first thing you want to do is get rid of the global statements. At least pass variables between the functions using parameters and return values. Better yet would be to put all of this in a class.
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#3
(Oct-27-2018, 09:02 PM)ichabod801 Wrote: What exactly is the problem you are having?

I would note that the first thing you want to do is get rid of the global statements. At least pass variables between the functions using parameters and return values. Better yet would be to put all of this in a class.

Ah okay, I suppose I can get rid of the global statements. Any leads on how to change all of this? I just started learning Python to be honest.

[Image: lb9tlu]

Also I can't seem to resolve the issue where Player 2 wins the game despite that there is not 4, but 3. Specifically on the diagonal part.
Reply
#4
I tried a couple times to get a diagonal win for player 2 with 3 pieces and couldn't do it. But the second for loop in diag_check is messed up. It's always pulling from the same square (grid[3][0]), so whoever can get a piece their wins. I would just use one for loop. Use it to gather two checks, one using grids[diag][diag], and one using grids[diag][3-diag]. That will get you both diagonals. And move the conditional outside the loop. It's not until the last iteration of the loop that you have four items in check, so you might as well check it once after the loop is done.

As for getting rid of the globals, take loop. The three check functions return loop, but only if it's False. If they returned True if the game was not over, then checks_def could be:

def checks_def():
    return check_def() and checkEmpty_def() and diagcheck_def()
As soon as a chain of and operators hits a False, it short circuits and returns False. So if check_def returns False, it won't waste time checking the other two. Note that at this point it's returning the value of loop you want, so in the main while loop you can just have loop = checks_def() (although you would need to rearrange it so that's at the end, or change the condition to picode]if not checks_def():[/icode])

As for grid, you would pass that down the function chain as a parameter (checks_def(grids) would call check_def(grids)).
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#5
(Oct-28-2018, 01:47 AM)ichabod801 Wrote: I tried a couple times to get a diagonal win for player 2 with 3 pieces and couldn't do it. But the second for loop in diag_check is messed up. It's always pulling from the same square (grid[3][0]), so whoever can get a piece their wins. I would just use one for loop. Use it to gather two checks, one using grids[diag][diag], and one using grids[diag][3-diag]. That will get you both diagonals. And move the conditional outside the loop. It's not until the last iteration of the loop that you have four items in check, so you might as well check it once after the loop is done.

As for getting rid of the globals, take loop. The three check functions return loop, but only if it's False. If they returned True if the game was not over, then checks_def could be:

def checks_def():
    return check_def() and checkEmpty_def() and diagcheck_def()
As soon as a chain of and operators hits a False, it short circuits and returns False. So if check_def returns False, it won't waste time checking the other two. Note that at this point it's returning the value of loop you want, so in the main while loop you can just have loop = checks_def() (although you would need to rearrange it so that's at the end, or change the condition to picode]if not checks_def():[/icode])

As for grid, you would pass that down the function chain as a parameter (checks_def(grids) would call check_def(grids)).

Ah unfortunately I'm still stuck on it. Could you elaborate, please?
Reply
#6
The way you pass information between functions is with parameters and return values:

def add_two(x):
    return x + 2

five = add_two(3)
The 3 is passed as the parameter to the add_two function. The function returns the value 3 + 2, and that is stored in the variable five.

So you need to do two things. First, everywhere you have a global statement or otherwise access a global variable, make that a parameter of the function. You will also need to make sure that value is passed to the function whenever it is called. Second, wherever you modify a global variable, return the value instead. Assign it back to the variable where the function is called. For example:

count = 1

def count_more():
    global count
    count += 1

count_more()
would become:

count = 1

def count_more(count):     # made the global a parameter
    return count + 1       # returned the changed value

count = count_more(count)  # assigned the returned value
Craig "Ichabod" O'Brien - xenomind.com
I wish you happiness.
Recommended Tutorials: BBCode, functions, classes, text adventures
Reply
#7
Appreciated!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  refactoring kerzol81 8 3,430 Nov-02-2019, 09:49 AM
Last Post: Gribouillis
  Generalized Dice refactoring Beginner_coder123 2 2,185 Feb-05-2019, 08:45 AM
Last Post: Beginner_coder123

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020