if you enter an invalid ip, it doesnt crash lmao

This commit is contained in:
Vincent Rodley 2025-08-03 20:49:55 +12:00
parent b9d6812bf7
commit 2904e1406d
5 changed files with 136 additions and 294 deletions

View File

@ -7,4 +7,4 @@ I will make and train the AI myself.
I might make a GUI in Pygame, depends if i cbs I might make a GUI in Pygame, depends if i cbs
todo list: todo list:
3 gamemodes total. ~~player vs player on the same device~~, player vs player lan, and player vs computer 3 gamemodes total. ~~player vs player on the same device~~, ~~player vs player lan~~, and player vs computer

View File

@ -1,11 +0,0 @@
import socket
HOST = "127.0.0.1" # The server's hostname or IP address
PORT = 65432 # The port used by the server
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
s.sendall(b"Hello, world")
data = s.recv(1024)
print(f"Received {data!r}")

218
main.py
View File

@ -1,12 +1,25 @@
import os import os
import sys import sys
import socket
from colours import Colours from colours import Colours
# ===========================
# | Helper functions |
# ===========================
def clear(): def clear():
if sys.platform.startswith('win'): os.system('cls' if sys.platform.startswith('win') else 'clear')
os.system('cls')
def colourTile(tile):
if tile == 'R':
return f"{Colours.BOLD}{Colours.RED}R{Colours.END}"
elif tile == 'Y':
return f"{Colours.BOLD}{Colours.YELLOW}Y{Colours.END}"
elif tile == 'r':
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}R{Colours.END}"
elif tile == 'y':
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}Y{Colours.END}"
else: else:
os.system('clear') return "O"
def printBoard(board): def printBoard(board):
rows = [] rows = []
@ -16,122 +29,161 @@ def printBoard(board):
row += f"{Colours.BOLD}| {Colours.END}" + colourTile(column[i]) + " " row += f"{Colours.BOLD}| {Colours.END}" + colourTile(column[i]) + " "
row += f"{Colours.BOLD}|{Colours.END}" row += f"{Colours.BOLD}|{Colours.END}"
rows.append(row) rows.append(row)
rows.reverse()
rows = rows[::-1]
toPrint = ""
for row in rows:
toPrint += (row + "\n")
print(f""" {Colours.BOLD}CONNECT FOUR print(f""" {Colours.BOLD}CONNECT FOUR
============================={Colours.END} ============================={Colours.END}
{toPrint[:-1]} {'\n'.join(rows)}
{Colours.BOLD}==1===2===3===4===5===6===7=={Colours.END}""") {Colours.BOLD}==1===2===3===4===5===6===7=={Colours.END}""")
def getIntInput(prompt): def getIntInput(prompt, board=None):
inp = ""
while True: while True:
inp = input(prompt) inp = input(prompt)
try: try:
inp = int(inp) inp = int(inp)
break if not 1 <= inp <= 7:
except: raise ValueError
return inp
except ValueError:
clear() clear()
printBoard(board) if board:
print("Only positive integers 1-7 allowed") printBoard(board)
print("Only integers 1-7 allowed")
return inp
def colourTile(tile):
if tile == 'R':
return f"{Colours.BOLD}{Colours.RED}R{Colours.END}"
elif tile == 'Y':
return f"{Colours.BOLD}{Colours.YELLOW}Y{Colours.END}"
elif tile == 'r': # winning red
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}R{Colours.END}"
elif tile == 'y': # winning yellow
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}Y{Colours.END}"
else:
return "O"
def checkWin(board, player): def checkWin(board, player):
rows, cols = (6, 7) rows, cols = (6, 7)
winCount = 4 winCount = 4
# hoz check
for row in range(rows): for row in range(rows):
for col in range(cols - winCount + 1): for col in range(cols - winCount + 1):
if all(board[col + i][row] == player for i in range(winCount)): if all(board[col + i][row] == player for i in range(winCount)):
return [(col + i, row) for i in range(winCount)] return [(col + i, row) for i in range(winCount)]
# vert check
for col in range(cols): for col in range(cols):
for row in range(rows - winCount + 1): for row in range(rows - winCount + 1):
if all(board[col][row + i] == player for i in range(winCount)): if all(board[col][row + i] == player for i in range(winCount)):
return [(col, row + i) for i in range(winCount)] return [(col, row + i) for i in range(winCount)]
# diag / check
for col in range(cols - winCount + 1): for col in range(cols - winCount + 1):
for row in range(rows - winCount + 1): for row in range(rows - winCount + 1):
if all(board[col + i][row + i] == player for i in range(winCount)): if all(board[col + i][row + i] == player for i in range(winCount)):
return [(col + i, row + i) for i in range(winCount)] return [(col + i, row + i) for i in range(winCount)]
# diag \ check
for col in range(cols - winCount + 1): for col in range(cols - winCount + 1):
for row in range(winCount - 1, rows): for row in range(winCount - 1, rows):
if all(board[col + i][row - i] == player for i in range(winCount)): if all(board[col + i][row - i] == player for i in range(winCount)):
return [(col + i, row - i) for i in range(winCount)] return [(col + i, row - i) for i in range(winCount)]
# This is defined as columns, not rows. So tile 0 on column 0 is the bottom left tile of the board # ===========================
# you index like board[column][row] # | Player move providers |
board = [ # ===========================
['O', 'O', 'O', 'O', 'O', 'O'], def local_move_provider(player, board):
['O', 'O', 'O', 'O', 'O', 'O'], col = getIntInput(f"{colourTile(player)} where do you want to drop your tile? 1-7.\n>>> ", board) - 1
['O', 'O', 'O', 'O', 'O', 'O'], return col
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
['O', 'O', 'O', 'O', 'O', 'O'],
]
playing = True def socket_receive_move(sock):
player = 'R' return int(sock.recv(1024).decode())
while playing: def socket_send_move(sock, col):
clear() sock.sendall(str(col).encode())
printBoard(board)
# ===========================
# | Main game loop |
# ===========================
def play_game(player1_get_move, player2_get_move):
board = [['O'] * 6 for _ in range(7)]
player = 'R'
while True: while True:
try:
chosenColumn = getIntInput(f"{colourTile(player)} where do you want to drop your tile? 1-7.\n>>> ") - 1
if chosenColumn < 0:
raise IndexError
tile = board[chosenColumn].index("O")
break
except ValueError:
clear()
printBoard(board)
print(f"{Colours.BOLD}You chose a column that is full. Try again{Colours.END}")
tile = ""
except IndexError:
clear()
printBoard(board)
print(f"{Colours.BOLD}You chose a column outside of the board. Try again{Colours.END}")
tile = ""
board[chosenColumn][tile] = player
winPositions = checkWin(board, player)
if winPositions:
for x, y in winPositions:
board[x][y] = board[x][y].lower()
clear() clear()
printBoard(board) printBoard(board)
print(f"{colourTile(player)} won!")
break
if player == 'R': # Get column from correct player
player = 'Y' if player == 'R':
col = player1_get_move(player, board)
else:
col = player2_get_move(player, board)
try:
tile = board[col].index("O")
except ValueError:
continue # column full, skip turn (could add retry logic)
board[col][tile] = player
winPositions = checkWin(board, player)
if winPositions:
for x, y in winPositions:
board[x][y] = board[x][y].lower()
clear()
printBoard(board)
print(f"{colourTile(player)} won!")
input("Press ENTER to return to the menu.")
break
player = 'Y' if player == 'R' else 'R'
# ===========================
# | Modes |
# ===========================
def play_local_pvp():
play_game(local_move_provider, local_move_provider)
def play_lan_server():
HOST, PORT = "0.0.0.0", 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print("Waiting for player 2...")
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
play_game(
lambda p, b: send_and_return_local_move(p, b, conn),
lambda p, b: socket_receive_move(conn)
)
def play_lan_client():
while True:
HOST, PORT = input("Enter server IP: "), 65432
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
print("Connected to server.")
play_game(
lambda p, b: socket_receive_move(s),
lambda p, b: send_and_return_local_move(p, b, s)
)
break
except:
print("No game found on that IP. Try again.")
def send_and_return_local_move(player, board, sock):
col = local_move_provider(player, board)
socket_send_move(sock, col)
return col
def play_vs_computer():
print("PvC mode coming soon!")
input("Press Enter to return to menu...")
# ===========================
# | Menu |
# ===========================
while True:
clear()
print("How do you want to play?")
print("1. PvP (same device)")
print("2. PvP (LAN)")
print("3. PvC (vs computer)")
print("4. Quit")
choice = input("Choose 1-4: ").strip()
if choice == "1":
play_local_pvp()
elif choice == "2":
if input("Are you hosting? (y/n): ").lower() == "y":
play_lan_server()
else:
play_lan_client()
elif choice == "3":
play_vs_computer()
elif choice == "4":
break
else: else:
player = 'R' input("Invalid choice. Press Enter to try again...")

View File

@ -1,16 +0,0 @@
import socket
HOST = "0.0.0.0"
PORT = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
while True:
data = conn.recv(1024)
if not data:
break
conn.sendall(data)

183
test.py
View File

@ -1,183 +0,0 @@
import os
import sys
import socket
from colours import Colours
# ===========================
# | Helper functions |
# ===========================
def clear():
os.system('cls' if sys.platform.startswith('win') else 'clear')
def colourTile(tile):
if tile == 'R':
return f"{Colours.BOLD}{Colours.RED}R{Colours.END}"
elif tile == 'Y':
return f"{Colours.BOLD}{Colours.YELLOW}Y{Colours.END}"
elif tile == 'r':
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}R{Colours.END}"
elif tile == 'y':
return f"{Colours.BOLD}{Colours.LIGHT_GREEN}Y{Colours.END}"
else:
return "O"
def printBoard(board):
rows = []
for i in range(6):
row = ""
for column in board:
row += f"{Colours.BOLD}| {Colours.END}" + colourTile(column[i]) + " "
row += f"{Colours.BOLD}|{Colours.END}"
rows.append(row)
rows.reverse()
print(f""" {Colours.BOLD}CONNECT FOUR
============================={Colours.END}
{'\n'.join(rows)}
{Colours.BOLD}==1===2===3===4===5===6===7=={Colours.END}""")
def getIntInput(prompt, board=None):
while True:
inp = input(prompt)
try:
inp = int(inp)
if not 1 <= inp <= 7:
raise ValueError
return inp
except ValueError:
clear()
if board:
printBoard(board)
print("Only integers 1-7 allowed")
def checkWin(board, player):
rows, cols = (6, 7)
winCount = 4
for row in range(rows):
for col in range(cols - winCount + 1):
if all(board[col + i][row] == player for i in range(winCount)):
return [(col + i, row) for i in range(winCount)]
for col in range(cols):
for row in range(rows - winCount + 1):
if all(board[col][row + i] == player for i in range(winCount)):
return [(col, row + i) for i in range(winCount)]
for col in range(cols - winCount + 1):
for row in range(rows - winCount + 1):
if all(board[col + i][row + i] == player for i in range(winCount)):
return [(col + i, row + i) for i in range(winCount)]
for col in range(cols - winCount + 1):
for row in range(winCount - 1, rows):
if all(board[col + i][row - i] == player for i in range(winCount)):
return [(col + i, row - i) for i in range(winCount)]
# ===========================
# | Player move providers |
# ===========================
def local_move_provider(player, board):
col = getIntInput(f"{colourTile(player)} where do you want to drop your tile? 1-7.\n>>> ", board) - 1
return col
def socket_receive_move(sock):
return int(sock.recv(1024).decode())
def socket_send_move(sock, col):
sock.sendall(str(col).encode())
# ===========================
# | Main game loop |
# ===========================
def play_game(player1_get_move, player2_get_move):
board = [['O'] * 6 for _ in range(7)]
player = 'R'
while True:
clear()
printBoard(board)
# Get column from correct player
if player == 'R':
col = player1_get_move(player, board)
else:
col = player2_get_move(player, board)
try:
tile = board[col].index("O")
except ValueError:
continue # column full, skip turn (could add retry logic)
board[col][tile] = player
winPositions = checkWin(board, player)
if winPositions:
for x, y in winPositions:
board[x][y] = board[x][y].lower()
clear()
printBoard(board)
print(f"{colourTile(player)} won!")
break
player = 'Y' if player == 'R' else 'R'
# ===========================
# | Modes |
# ===========================
def play_local_pvp():
play_game(local_move_provider, local_move_provider)
def play_lan_server():
HOST, PORT = "0.0.0.0", 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((HOST, PORT))
s.listen()
print("Waiting for player 2...")
conn, addr = s.accept()
with conn:
print(f"Connected by {addr}")
play_game(
lambda p, b: send_and_return_local_move(p, b, conn),
lambda p, b: socket_receive_move(conn)
)
def play_lan_client():
HOST, PORT = input("Enter server IP: "), 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
print("Connected to server.")
play_game(
lambda p, b: socket_receive_move(s),
lambda p, b: send_and_return_local_move(p, b, s)
)
def send_and_return_local_move(player, board, sock):
col = local_move_provider(player, board)
socket_send_move(sock, col)
return col
def play_vs_computer():
print("PvC mode coming soon!")
input("Press Enter to return to menu...")
# ===========================
# | Menu |
# ===========================
while True:
clear()
print("How do you want to play?")
print("1. PvP (same device)")
print("2. PvP (LAN)")
print("3. PvC (vs computer)")
print("4. Quit")
choice = input("Choose 1-4: ").strip()
if choice == "1":
play_local_pvp()
elif choice == "2":
if input("Are you hosting? (y/n): ").lower() == "y":
play_lan_server()
else:
play_lan_client()
elif choice == "3":
play_vs_computer()
elif choice == "4":
break
else:
input("Invalid choice. Press Enter to try again...")