diff --git a/oberon2.py b/oberon old mode 100644 new mode 100755 similarity index 59% rename from oberon2.py rename to oberon index db36c3e..eb0c3ff --- a/oberon2.py +++ b/oberon @@ -6,18 +6,25 @@ import os import subprocess import json -version = '0.2.2' + +version = '0.3.2' home_folder = os.path.expanduser('~') username = os.path.split(home_folder)[-1] database = '/var/lib/oberon/oberon.sqlite' +directions = [[1,0],[1,-1],[0,-1],[-1,-1]] +pieces = [' ◍ ', ' ○ '] + def print_header(): print('\nO B E R O N v{}\n'.format(version)) def create_game(enemy): + if enemy == username: + print('This system is designed for multiuser games. You cannot create a game against yourself.') + return False enemies = get_user_list() - enemies = ['test', 'sloum'] #delete this test data + # create guard clause to prevent play against self and refer to single player game if not enemy in enemies: print('There is no avialable player with the name {}.\nGame not created.'.format(enemy)) @@ -33,8 +40,59 @@ def create_game(enemy): return False -def update_board(): - pass +def validate_input(r,c, board): + if r < 0 or r > 14 or c < 0 or c > 14: + return False + + if board[r][c] != ' · ': + return False + return True + + +def check_win_state(point, piece, board): + ends = [ + walk_to_ends(point, 0, piece, board), + walk_to_ends(point, 1, piece, board), + walk_to_ends(point, 2, piece, board), + walk_to_ends(point, 3, piece, board) + ] + + game_over = False + + for x in range(4): + if count_to_five(ends[x], x, piece, board): + game_over = True + break + + return game_over + + +def count_to_five(start,direction, piece, board, count=1): + look_toward = [directions[direction][0] * -1, directions[direction][1] * -1] + new_point = [start[0] + look_toward[0], start[1] + look_toward[1]] + + if count == 5: + return True + + if new_point[0] < 0 or new_point[0] > 14 or new_point[1] < 0 or new_point[1] > 14 or board[new_point[0]][new_point[1]] != pieces[piece]: + return False + + return count_to_five(new_point, direction, piece, board, count + 1) + + + +def walk_to_ends(point, direction, piece, board): + look_toward = directions[direction] + new_point = [point[0] + look_toward[0], point[1] + look_toward[1]] + if new_point[0] < 0 or new_point[0] > 14 or new_point[1] < 0 or new_point[1] > 14 or board[new_point[0]][new_point[1]] != pieces[piece]: + return point + return walk_to_ends(new_point, direction, piece, board) + + +def set_winner(game, winner): + q = "UPDATE games SET winner = ? WHERE rowid = ?" + v = (winner, game) + return db_do(q, v, True) def play_game(gid): @@ -46,13 +104,18 @@ def play_game(gid): return False board = json.loads(res[0][3]) pturn = res[0][2] if res[0][4] % 2 == 0 else res[0][1] + ppiece = 1 if res[0][4] % 2 == 0 else 0 + print_header() print('{} vs. {}: {}\'s turn'.format(res[0][1], res[0][2], pturn)) print_board(board) + if not pturn == username: print('\nIt is your opponents turn.\n') return True - print('Enter your move as row-column.\nFor example: 4-10\nType "q" to cancel and play another time.\nType "f" to forfeit.') + + print('Enter your move as row-column (ex. 4-10)\n\nType "q" to cancel and play another time.\nType "f" to forfeit.') + while True: move = input('> ') if move in ['q', 'quit', 'exit']: @@ -72,24 +135,40 @@ def play_game(gid): print('Invalid entry!') continue try: - row = int(move[0]) - col = int(move[1]) + row = int(move[0]) - 1 + col = int(move[1]) - 1 except ValueError: print('Invalid entry!') continue - valid_move = update_board(row, col, board) - if not valid_move: + if not validate_input(row, col, board): print('Invalid entry!') continue - update_board(row, col, board) + board[row][col] = pieces[ppiece] - if check_win_state(row, col): - print('You have won!') + q2 = "UPDATE games SET game_board = ?, turn = ? WHERE rowid = ?" + v2 = (json.dumps(board), res[0][4] + 1, gid) + res2 = db_do(q2, v2, True) + if not res2: + print('Error updating database') + return False + + if check_win_state([row, col], ppiece, board): + if not set_winner(gid, pturn): + print('Error updating database') + return False + print('{} has won the game!'.format(pturn)) break - - print('Your move has been placed.') - return True + elif res[0][4] > 225: + if not set_winner(gid, 'tie'): + print('Error updating database') + return False + print('There is no winner. Tie game.') + # update game in db + break + else: + print('Your move has been placed.') + return True def print_board(gb): @@ -101,7 +180,20 @@ def print_board(gb): def show_game_record(): - pass + q = "SELECT rowid, p1, p2, winner FROM games WHERE winner is not NULL and (p1 = ? or p2 = ?)" + v = (username, username) + res = db_do(q, v) + if res == False: + print('Database error. Contact the sysadmin or try another time') + print_header() + print('{:^8} {:^10} {:^10} {:^10}'.format('ID', 'Player 1', 'Player 2', 'Winner')) + print('-------- ---------- ---------- ----------') + for x in res: + print('{:^8} {:^10} {:^10} {:^10}'.format(x[0], x[1], x[2], x[3])) + if not len(res): + print('You have not completed any games yet...') + print('') + return True def list_games(): @@ -115,9 +207,9 @@ def list_games(): print('{:^8} {:^10} {:^10} {:^12}'.format('ID', 'Player 1', 'Player 2', 'Game Status')) print('-------- ---------- ---------- ------------') for x in res: - print("{:^8} {:^10} {:^10} {:^12}".format(x[0], x[1], x[2] or '-', x[4])) + print("{:^8} {:^10} {:^10} {:^12}".format(x[0], x[1], x[2], x[4])) if not len(res): - print('There are no open games') + print('You are not currently playing any games...') print('') return True @@ -125,11 +217,11 @@ def list_games(): def display_help(): print_header() print('syntax: oberon [command [option]]\n') - print('{:25} {}'.format('help','display this message')) - print('{:25} {}'.format('list', 'display your currently open games')) - print('{:25} {}'.format('history', 'display your win/loss record')) - print('{:25} {}'.format('create [user]', 'create a game against the user provided')) - print('{:25} {}'.format('play [game_id]', 'make a move or view the board for the game id provided')) + print('{:20} {}'.format('help','display this message')) + print('{:20} {}'.format('list', 'display your currently open games')) + print('{:20} {}'.format('history', 'display your win/loss record')) + print('{:20} {}'.format('create [user]', 'create a game against the user provided')) + print('{:20} {}'.format('play [game_id]', 'make a move or view the board for the game id provided')) print('') diff --git a/oberon.py b/oberon.py deleted file mode 100644 index 78a20c1..0000000 --- a/oberon.py +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env python3 -# -# Oberon: an application for managing correspondance gameplay -# for board style games -# by Brian Evans -#_ - -import sys -import os -import sqlite3 as sql -import re -import subprocess -import json - -class c: - black = '' - red = '\033[0;31m' - b_red = '\033[1;31m' - yellow = '\033[1;33m' - green = '\033[0;32m' - b_green = '\033[1;32m' - cyan = '\033[0;36m' - b_cyan = '\033[1;36m' - purple = '\033[1;35m' - blue = '\033[0;34m' - b_blue = '\033[1;34m' - white = '\033[1;37m' - end = '\033[0m' - -#---------> - -class User: - def __init__(self): - self.home_folder = os.path.expanduser('~') - self.name = os.path.split(self.home_folder)[-1] - self.current_games = self.get_games() - self.history = self.get_history() - - - def get_games(self): - db_data = False # do db query - # Retrieve current games - return db_data - - - def get_history(self): - db_data = False # do db query - # Retrieve history for this user - return db_data - -#--------> - -class Interface: - def __init__(self): - self.user = User() - self.screen = 'menu' - self.userlist = self.get_user_list() - self.db_path = '/home/sloum/oberon.sqlite' - self.game = Game() - self.mainloop() - - - def main_menu(self): - menu = [ - '{:^80}'.format('1) Create Game'), - '{:^80}'.format('2) List Games'), - '{:^80}'.format('3) View history'), - '{:^80}'.format('4) Quit/Exit') - ] - - print('\n{:^80}'.format('O B E R O N')) - print('{:^80}\n'.format('Correspondence gaming system')) - for x in menu: - print('{:^80}'.format(x)) - selection = '' - while selection not in ['1', '2', '3', '4', 'q', 'quit', 'exit']: - selection = input(' oberon > ') - if selection == '1': - self.screen = 'create' - elif selection == '2': - self.screen = 'list' - elif selection == '3': - self.screen = 'history' - elif selection in ['4','q','quit','exit']: - sys.exit(0) - - - def get_user_list(self): - res = subprocess.run(['awk', '-F', ':', '{if ($7 == "/usr/local/bin/colorsh" && $1 != "brian")}', '/etc/passwd'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - res_list = res.stdout.decode('utf-8').split('\n') - if res_list[0] == '': - return [] - return res_list - - - def create_game(self): - select_player = '' - p2 = '' - game_type = 'gomoku' - game_status = '' - next_menu = 'menu' - - while True: - select_player = input('Do you want to challenge another player (y/n) > ') - if select_player in ['y', 'yes', 'no', 'n']: - break - - if select_player in ['y', 'yes']: - if not len(self.userlist): - self.screen = 'menu' - print('\n') - print('{}{:^80}{}'.format(c.white, 'There are no players available', c.end)) - print('\n') - return False - print('{:^80}'.format('The following players are available:\n')) - for x in self.userlist: - print('{:^80}'.format(x)) - print('\n') - while not p2 in self.userlist: - p2 = input('Enter the name of the user would you like to challenge > ') - if not p2 in self.userlist: - print('{}Invalid entry{}'.format(c.red, c.end)) - continue - game_status = 'playing' - next_menu = 'play' - else: - p2 = None - game_status = 'Open' - next_menu = 'menu' - q = "INSERT INTO games VALUES (?, ?, ?, ?, ?, ?, ?)" - v = (self.user.name, p2, game_type, game_status, json.dumps(self.game.game_board), 1, None) - db_do(q, v, True) - self.screen = next_menu - - - def list_games(self): - game_id = '' - q = "SELECT rowid, p1, p2, game_type, game_status FROM games WHERE winner is NULL" - res = db_do(q) - print('{:^8} {:^10} {:^10} {:^12}'.format('ID', 'Player 1', 'Player 2', 'Game Status')) - print('-------- ---------- ---------- ------------\n') - for x in res: - print("{:^8} {:^10} {:^10} {:^12}".format(x[0], x[1], x[2] or '-', x[4])) - if not len(res): - print('There are no open games') - print('') - print('To join an open game, enter the game ID\nTo go back type "back"\n') - while True: - game_id = input('Choice > ') - if game_id == 'back': - self.screen = 'menu' - return - else: - try: - gid = int(game_id) - if gid in [x[0] for x in res]: - break - except: - print('{}Invalid entry{}'.format(c.red, c.end)) - q2 = "UPDATE games SET p2 = ?, game_status = 'playing' WHERE rowid = ?" - v2 = (self.user.name, gid) - db_do(q2, v2, True) - - - def get_game_list(): - # query for available open games and current games for player - print('\nComing soon...\n') - self.screen = 'menu' - - - def show_history(self): - # query for this palyers win records - # display them - # options for back or quit - print('\nComing soon...\n') - self.screen = 'menu' - pass - - - def play_game(self): - # acts as a router to game logic functions - # based on which game is selected - pass - - - def mainloop(self): - while True: - if self.screen == 'menu': - self.main_menu() - elif self.screen == 'create': - self.create_game() - elif self.screen == 'list': - self.list_games() - elif self.screen == 'history': - self.show_history() - elif self.screen == 'play': - self.play_game() - - -class Game: - def __init__(self): - self.game_id = None - self.game_board = None - self.turn = None - self.create_game_board() - - def create_game_board(self): - self.game_board = [[' · ' for y in range(15)] for x in range(15)] - - def get_game_board(self): - pass - - - def validate_turn(self): - pass - - - def make_move(self): - pass - - - def validate_move(self): - pass - - - def check_win_state(self): - pass - - -def check_and_build_db(db_path): - if not os.path.isfile(db_path): - conn = sql.connect(db_path) - c = conn.cursor() - - c.execute("CREATE TABLE games (p1 text NOT NULL, p2 text DEFAULT NULL, game_type text NOT NULL, game_status text DEFAULT NULL, game_board text, turn INTEGER, winner text DEFAULT NULL)") - - conn.commit() - conn.close() - - -def db_do(query, var=False, noresval=False): - global messages - db_path = '/home/sloum/oberon.sqlite' - if os.path.isfile(db_path): - conn = sql.connect(db_path) - c = conn.cursor() - if var: - c.execute(query, var) - else: - c.execute(query) - if noresval: - out = c.rowcount - else: - out = [] - for row in c: - out.append(row) - conn.commit() - conn.close() - return out - else: - messages.append("{}ERROR:{} Database cannot be found or is corrupt".format(c.red, c.end)) - return False - - -if __name__ == '__main__': - check_and_build_db('/home/sloum/oberon.sqlite') - game = Interface() -