7
\$\begingroup\$

Please Review and share suggestion :

https://github.com/prosenjitj/ConnectFour

enter image description here

Code:

import re
import string
import sys


PLAYING = "PLAYING"
WAITING = "WAITING"
WINNERX = "XXXX"
WINNERO = "OOOO"

## User Class
class User:
    state = ""
    name = ""
    def __init__(self,name, stateParam):
        self.name = name
        self.state = stateParam

    def userInfo(self):
        return self.name

    def getState(self):
        return self.state
    def setState(self, stateParam):
        self.state = stateParam

def printBoard(matrix):
    for num in range(1, 7):
        print(" "+ str(num) +" ", end = " ")
    print()

    for row in range(0, 6):
        for col in range(0, 6):
            print(" "+ str(matrix[row][col]) +" ", end = " ")
        print("")

def createMatrix(row, column) :
    mat = ["*"] * row
    for i in range(row):
        # mat[i] = ["" + str(i)] * column
        mat[i] = ["*"] * column
    return mat



def findMatrixMatched(matrix) :
    winFlg = False
    rowStrArr = []
    # get rows in String format
    for row in range(0, 6):
        str = ""
        for col in range(0, 6):
            str = str + matrix[row][col]
        rowStrArr.append(str)

    for rowStr in rowStrArr:
        # print("Row-" , rowStr)
        if WINNERX in rowStr or WINNERO in rowStr:
            winFlg = True
            break


    # get columns in String format
    colStrArr = []
    for col in range(0, 6):
        str = ""
        for row in range(0, 6):
            str = str + matrix[row][col]
        colStrArr.append(str)

    for colStr in colStrArr:
        # print("Col-" , colStr)
        if WINNERX in colStr or WINNERO in colStr :
            winFlg = True
            break

    # get diagonal match
    diagStrArr = [""] * 25
    for col in range(0, 6):
        diagNum = col

        for row in range(0, 6):
            if row + col > 5 :
                break
            if col == 0:
                diagStrArr[diagNum] = diagStrArr[diagNum] + matrix[row][row]  # middle
            else :
                diagStrArr[diagNum] = diagStrArr[diagNum] + matrix[row][row + col]  # upper
                diagStrArr[diagNum + 5] = diagStrArr[diagNum + 5] + matrix[row + col][row]  # lower

    # get diagonal match
    for col in range(0, 6):
        diagNum = col + 12

        for row in range(0,6):
            rowId = 5-row
            # print(col , " ---- " , rowId, " ---- " , row)
            if rowId - col < 0 :
                break

            if col == 0:
                diagStrArr[diagNum] = diagStrArr[diagNum] + matrix[row][rowId]  # middle
            else :
                diagStrArr[diagNum] = diagStrArr[diagNum] + matrix[row][rowId - col]  # upper
                diagStrArr[diagNum + 5] = diagStrArr[diagNum + 5] + matrix[row + col][rowId]  # lower


    for diagStr in diagStrArr:
        # print("Diag-" , diagStr)
        if WINNERX in diagStr or WINNERO in diagStr:
            winFlg = True
            break

    return winFlg



def appConnect():
    userA = User("A" , PLAYING)
    userB = User("B" , WAITING)

    matBoard = createMatrix(6,6)
    printBoard(matBoard)

    turn = 0
    while True:
        user = userA
        if turn % 2 == 0 :
            user = userA
            userA.setState(PLAYING)
            userB.setState(WAITING)
        else :
            user = userB
            userB.setState(PLAYING)
            userA.setState(WAITING)

        print(".................................................. ")
        print("Preference : ", user.userInfo() , " SEQ : ", str(turn + 1))
        print(".................................................. ")

        try:
            print( user.userInfo() , " turn >>>>>......................... ")
            color = str(input("Please select X or O > "))
            if color != 'X' and color != 'O' :
                print("Wrong Entry", color)
                continue

            colNum = int(input("Please Enter column Number >"))
            if colNum > 6 and colNum < 0:
                print("Wrong Entry -> Please Enter 1 - 5 :", colNum)
                continue

            colNum = colNum - 1; # column starting from 0
            for row in range(5, -1, -1):
                if matBoard[row][colNum] == "*" :
                    matBoard[row][colNum] = color
                    break;

            turn += 1
        except ValueError:
            print('Invalid Number !! Please try again')

        printBoard(matBoard)
        if findMatrixMatched(matBoard) :
            print(".................................................. ")
            print("User : ", user.userInfo() , " Win the Match by ", str(turn / 2) , " Steps")
            print(".................................................. ")
            break

        if turn >= 20:
            print("You have crossed maximum limits. Please start again.")
            break

if __name__ == '__main__':
    appConnect()
\$\endgroup\$

1 Answer 1

4
\$\begingroup\$

I've had a quick scan over the code, and a few things pop up:

The User class is overly complex for what you're actually doing with it (though you might have plans to use it more in future?)

You could get away with something simple like:

users = ['A', 'B']

and then toggle whose turn it is by just flipping between users[0] and users[1].

Now a nice trick is that False == 0 and True == 1, so users[False] is equivalent to users[0] which will be A (and users[True] will be B)

So your code could look something like:

turn = 0
while True:
    player = players[turn % 2 == 0]  # Odd turns False, even turns True
    turn += 1

(If you keep the class, you could store the User instances in a list and get the same effect).

Your match strings (OOOO and XXXX) - it might be better to build these by doing:

win_count = 4
WINNERX = "X" * 4
WINNERO = "O" * 4

That way you can easily configure the game later to alter the win condition by changing the variable.

Alternatively... you can not worry about maintaining WINNERX and WINNERO at all - and just test if the string contains the same character n (4) times:

# Replace
if WINNERX in rowStr or WINNERO in rowStr:
# with
if rowStr == rowStr[0] * win_count:

The same string multiplier could be used in other places for neatness - such as the `print(".....") lines.

You might also want to set board size variables and use them in the range calls that set up the board, colNum etc, to allow a different board size easily.

Your use of winFlag/break could be removed - since you only use it to then return winFlag. Why not just do return True or return False in place of setting/breaking/returning?

if colNum > 6 and colNum < 0 - this should be or not and.

imports - you're importing several libraries you're not using - re, string and `sys.

You might want to consider using format for some of the print statements joining strings. If nothing else, this would remove the need to cast int to str in print statements.

str = "" - str is a builtin method so shouldn't be overridden - choose a different variable name.

Really minor, but turn >= 20 could be turn == 20 - there's no way to get to 21 without first carrying out that test.

Finally, consider running the code through pylint and pycodestyle - there are a number of minor layout and formatting issues that would benefit from fixing.

Hopefully that's enough ideas to be getting started with!

\$\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.