diff --git a/latest/tictactoe-latest.py b/latest/tictactoe-latest.py index 7542464..3ab5356 100644 --- a/latest/tictactoe-latest.py +++ b/latest/tictactoe-latest.py @@ -61,10 +61,11 @@ def init(): clearScreen() print("Size of the playfield (n*n):", size) F_printOneMoreTime = 0 - if size <= 2: + if size < 3: clearScreen() print("Size of the playfield (n*n):", size, "(changed to 3*3)") size = 3 + _size = size # 03 -> allow a user to enter names of two players @@ -84,8 +85,19 @@ def init(): continue if F_printOneMoreTime == 1: clearScreen() + print("Size of the playfield (n*n):", size, "(changed to 3*3)") + print("Name of the first player:", name1) + print("Name of the second player:", name2) print("Number of symbols inline needed to win:", symbolCount) F_printOneMoreTime = 0 + if symbolCount > _size >= 0: + clearScreen() + print("Size of the playfield (n*n):", _size) + print("Name of the first player:", name1) + print("Name of the second player:", name2) + print("Number of symbols inline needed to win:", symbolCount, f"(changed to {_size}*{_size})") + symbolCount = _size + time.sleep(2) # creating the playfield pf = [] # pf is shor for PlayField diff --git a/tictactoe-v2.2.1-new.py b/tictactoe-v2.2.1-new.py index 6abf830..3ab5356 100644 --- a/tictactoe-v2.2.1-new.py +++ b/tictactoe-v2.2.1-new.py @@ -1,7 +1,7 @@ # TODO - # add: -# fix: +# fix: general bugfixes # update: # algorithm steps @@ -61,10 +61,11 @@ def init(): clearScreen() print("Size of the playfield (n*n):", size) F_printOneMoreTime = 0 - if size <= 2: + if size < 3: clearScreen() print("Size of the playfield (n*n):", size, "(changed to 3*3)") size = 3 + _size = size # 03 -> allow a user to enter names of two players @@ -84,8 +85,19 @@ def init(): continue if F_printOneMoreTime == 1: clearScreen() + print("Size of the playfield (n*n):", size, "(changed to 3*3)") + print("Name of the first player:", name1) + print("Name of the second player:", name2) print("Number of symbols inline needed to win:", symbolCount) F_printOneMoreTime = 0 + if symbolCount > _size >= 0: + clearScreen() + print("Size of the playfield (n*n):", _size) + print("Name of the first player:", name1) + print("Name of the second player:", name2) + print("Number of symbols inline needed to win:", symbolCount, f"(changed to {_size}*{_size})") + symbolCount = _size + time.sleep(2) # creating the playfield pf = [] # pf is shor for PlayField diff --git a/tictactoe-v2.2.py b/tictactoe-v2.2.py new file mode 100644 index 0000000..6abf830 --- /dev/null +++ b/tictactoe-v2.2.py @@ -0,0 +1,440 @@ +# TODO - + +# add: +# fix: +# update: + +# algorithm steps +# +# prerequisites +# 01 clear the screen +# 02 allow a user to determine the size of the playfield +# 03 allow a user to enter names of two players +# 04 allow a user to determine the symbol count needed to win +# +# 1 clear the screen +# 2 print the current state of the game +# 3 allow for one player or the other to insert coords by moving with arrow keys and to put the symbol to the selected place by pressing space +# 5 check if the game should end (if someone won) +# 5.1 if yes -> end the game +# 5.2 if no -> jump to step 1 + +import os, time +from pynput import keyboard +from pynput.keyboard import Key, Listener, KeyCode + +# these global variables are flags +end = 0 +turn = 0 +error = 0 + +# misc. global vars +_size = 0 +winLine = [] +cursorX = cursorY = 0 # setting the default cursor position to the left top corner + +# error codes +# +# 1 - invalid value +# 2 - invalid index/position +# 3 - index/position occupied + +def init(): + global end, turn, pf, name1, name2, symbolCount, cursorX, cursorY, size, _size + + # 01 -> clear the screen + clearScreen() + + # 02 -> allow a user to determine the size of the playfield + size = None + F_printOneMoreTime = 0 # variables starting with 'F_' are flags + while size == None: + try: + size = int(input("Size of the playfield (n*n): ")) + _size = size + except ValueError: + clearScreen() + print("Enter a number") + F_printOneMoreTime = 1 + continue + if F_printOneMoreTime == 1: + clearScreen() + print("Size of the playfield (n*n):", size) + F_printOneMoreTime = 0 + if size <= 2: + clearScreen() + print("Size of the playfield (n*n):", size, "(changed to 3*3)") + size = 3 + + + # 03 -> allow a user to enter names of two players + name1 = input("Name of the first player: ") + name2 = input("Name of the second player: ") + + # 04 -> allow a user to determine the symbol count needed to win + symbolCount = None + F_printOneMoreTime = 0 + while symbolCount == None: + try: + symbolCount = int(input("Number of symbols inline needed to win: ")) + except ValueError: + clearScreen() + print("Enter a number") + F_printOneMoreTime = 1 + continue + if F_printOneMoreTime == 1: + clearScreen() + print("Number of symbols inline needed to win:", symbolCount) + F_printOneMoreTime = 0 + + # creating the playfield + pf = [] # pf is shor for PlayField + temp = [] + for i in range(size): + for j in range(size): + temp.append(' ') + pf.append(temp) + temp = [] + + # setting the hotkeys for moving with the cursor and putting down symbols + + while end == 0: + gameRound(pf, name1, name2) + +# clears the screen +def clearScreen(): + if os.name == "posix": + os.system("clear") + if os.name == "nt": + os.system("cls") + +# detects if a position is inside the playfield +def inBound(x): + global _size + + if 0 <= x < _size: + return 1 + else: + return 0 + +def blinkPrint(pf, name1, name2): + clearScreen() + print(name1, "(o) vs", name2, "(x)") + for i in range(_size): + for j in range(_size): + if [i, j] in winLine: + print("[ ]", end=" ") + continue + print(f"[{pf[i][j]}]", end=" ") + print("") + time.sleep(0.5) + +def _print(pf, name1, name2, blink = 0): + clearScreen() + if blink == 2: + print("o won!") + elif blink == 3: + print("x won!") + elif blink == 4: + print("Draw!") + + print(name1, "(o) vs", name2, "(x)") + for i in range(len(pf)): + for j in range(len(pf)): + if cursorX == j and cursorY == i and blink == 0: + print(f"#{pf[i][j]}#", end=" ") + continue + print(f"[{pf[i][j]}]", end=" ") + print("") + if blink == 1: + time.sleep(0.5) + +# prints the current state of the game +def gameState(pf, name1, name2, blink = 0): + global error, cursorX, cursorY + + if error == 1: + print("Invalid value") + error = 0 + if error == 2: + print("Invalid position") + error = 0 + if error == 3: + print("Position occupied") + error = 0 + + if blink == 1: + for i in range(6): + if i % 2 == 0: + blinkPrint(pf, name1, name2) + if i % 2 == 1: + _print(pf, name1, name2, 1) + elif blink == 0: + _print(pf, name1, name2) + elif blink == 2: + _print(pf, name1, name2, 2) + elif blink == 3: + _print(pf, name1, name2, 3) + elif blink == 4: + _print(pf, name1, name2, 4) + +# checks whether someone has won +def check(pf): + global symbolCount, winLine + + winLine = [] + + # horizontal checking + # 0 is for when 'o's win and 1 is for when 'x's win + temp = [] + o = x = 0 + for i in range(_size): + for j in range(_size): + if pf[i][j] == 'o': + temp.append([i, j]) + o += 1 + if o == symbolCount: + winLine = temp + return 0 + if pf[i][j] == ' ' or pf[i][j] == 'x': + temp = [] + o = 0 + if o < symbolCount: + temp = [] + o = 0 + + for i in range(_size): + for j in range(_size): + if pf[i][j] == 'x': + temp.append([i, j]) + x += 1 + if x == symbolCount: + winLine = temp + return 1 + if pf[i][j] == ' ' or pf[i][j] == 'o': + temp = [] + x = 0 + if x < symbolCount: + temp = [] + x = 0 + + # vertical checking + temp = [] + o = x = 0 + for j in range(_size): + for i in range(_size): + if pf[i][j] == 'o': + temp.append([i, j]) + o += 1 + if o == symbolCount: + winLine = temp + return 0 + if pf[i][j] == ' ' or pf[i][j] == 'x': + temp = [] + o = 0 + if o < symbolCount: + temp = [] + o = 0 + + for j in range(_size): + for i in range(_size): + if pf[i][j] == 'x': + temp.append([i, j]) + x += 1 + if x == symbolCount: + winLine = temp + return 1 + if pf[i][j] == ' ' or pf[i][j] == 'o': + temp = [] + x = 0 + if x < symbolCount: + temp = [] + x = 0 + + # diagonal checking + temp = [] + o = x = 0 + for i in range(len(pf)): + for j in range(len(pf)): + if pf[i][j] == 'o': + try: + if pf[i+1][j-1] == 'o': + for k in range(symbolCount): + if pf[i+k][j-k] == 'o' and 0 <= i+k < _size and 0 <= j-k < _size: + temp.append([i+k, j-k]) + o += 1 + else: + winLine = [] + temp = [] + o = 0 + except IndexError: + pass + try: + if pf[i+1][j+1] == 'o': + for k in range(symbolCount): + if pf[i+k][j+k] == 'o' and 0 <= i+k < _size and 0 <= j+k < _size: + temp.append([i+k, j+k]) + o += 1 + else: + winLine = [] + temp = [] + o = 0 + except IndexError: + pass + if o == symbolCount: + winLine = temp + return 0 + elif o < symbolCount: + winLine = [] + temp = [] + o = 0 + + if pf[i][j] == 'x': + try: + if pf[i+1][j-1] == 'x': + for k in range(symbolCount): + if pf[i+k][j-k] == 'x' and 0 <= i+k < _size and 0 <= j-k < _size: + temp.append([i+k, j-k]) + x += 1 + else: + winLine = [] + temp = [] + x = 0 + except IndexError: + pass + try: + if pf[i+1][j+1] == 'x': + for k in range(symbolCount): + if pf[i+k][j+k] == 'x' and 0 <= i+k < _size and 0 <= j+k < _size: + temp.append([i+k, j+k]) + x += 1 + else: + winLine = [] + temp = [] + x = 0 + except IndexError: + pass + if x == symbolCount: + winLine = temp + return 1 + elif x < symbolCount: + winLine = [] + temp = [] + x = 0 + + # draw checking + # 2 is for when a draw occurs + count = 0 + for i in range(len(pf)): + for j in range(len(pf)): + if pf[i][j] == 'o' or pf[i][j] == 'x': + count += 1 + if count == len(pf)*len(pf): + return 2 + +def cursorLeft(): + global cursorX, cursorY, pf, name1, name2, error + + if inBound(cursorX-1) == 1 and inBound(cursorY): + cursorX -= 1 + + gameState(pf, name1, name2) + +def cursorRight(): + global cursorX, cursorY, pf, name1, name2, error + + if inBound(cursorX+1) == 1 and inBound(cursorY) == 1: + cursorX += 1 + + gameState(pf, name1, name2) + +def cursorUp(): + global cursorX, cursorY, pf, name1, name2, error + + if inBound(cursorX) == 1 and inBound(cursorY-1) == 1: + cursorY -= 1 + + gameState(pf, name1, name2) + +def cursorDown(): + global cursorX, cursorY, pf, name1, name2, error + + if inBound(cursorX) == 1 and inBound(cursorY+1) == 1: + cursorY += 1 + + gameState(pf, name1, name2) + +def putSymbol(): + global cursorX, cursorY, turn, pf, name1, name2 + + if turn == 0 and pf[cursorY][cursorX] == ' ': + pf[cursorY][cursorX] = 'o' + turn = 1 + elif turn == 1 and pf[cursorY][cursorX] == ' ': + pf[cursorY][cursorX] = 'x' + turn = 0 + clearScreen() + gameState(pf, name1, name2) + +def keys(key): + global listener + + if key == keyboard.Key.left: + cursorLeft() + if key == keyboard.Key.right: + cursorRight() + if key == keyboard.Key.up: + cursorUp() + if key == keyboard.Key.down: + cursorDown() + if key == keyboard.Key.space: + listener.stop() + putSymbol() + +# logic for a round of the game +def gameRound(pf, name1, name2): + global end, turn, error, listener + + # 1 -> clear the screen + # + # cross-platform (Windows, Unix-like OSs) + clearScreen() + + # 2 -> print the current state of the game + gameState(pf, name1, name2) + + # 3 -> allow for one player or the other to move with arrow keys and to put the symbol to the selected place by pressing space + # + # only if there isn't another symbol present and the coords are valid + # the 'o' or 'x' is determined by the turn variable + # - if it is 0, then an 'o' is placed, if it is 1, an 'x' is placed instead + # the rows and columns are marked 1, 2 and 3, not 0, 1 and 2 as the indexes + # for better user experience + with keyboard.Listener( + on_press=keys, + supress=True + ) as listener: + listener.join() + + # 5 -> check if the game should end (if someone won) + won = check(pf) + + if won == 0: + # 5.1 -> if yes -> end the game + gameState(pf, name1, name2, 1) + gameState(pf, name1, name2, 2) + end = 1 + # 5.2 -> if no -> jump to step 1 + + if won == 1: + gameState(pf, name1, name2, 1) + gameState(pf, name1, name2, 3) + end = 1 + + if won == 2: + gameState(pf, name1, name2, 4) + end = 1 + +# driver code +if __name__ == "__main__": + init() \ No newline at end of file