oberon/oberon

295 lines
9.0 KiB
Python
Executable File

#!/usr/bin/env python3
import sys
import sqlite3 as sql
import os
import subprocess
import json
from gomoku import Gomoku
from isola import Isola
version = '0.7.1'
home_folder = os.path.expanduser('~')
username = os.path.split(home_folder)[-1]
database = '/var/lib/oberon/oberon.sqlite'
def print_header():
print('\nO B E R O N v{}\n'.format(version))
##############################
######------------------#######
###### Top Lvl Cmds ########
######------------------#######
##############################
# Binds to the HISTORY command
def show_game_record():
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('\nTo view a historical game, run "oberon play [game_id]"')
return True
# Binds to the PLAY command
def play_game(gid):
q = "SELECT rowid, p1, p2, game_board, turn, game_type, winner FROM games WHERE rowid = ?"
v = (gid,)
res = db_do(q,v)
if not res:
print('Invalid game id')
return False
elif res[0][1] != username and res[0][2] != username:
print('Invalid selection. You are not playing game {}'.format(gid))
return False
state = {
'id': res[0][0],
'p1': res[0][1],
'p2': res[0][2],
'board': json.loads(res[0][3]),
'turn_number': res[0][4],
'game_type': res[0][5],
'winner': res[0][6],
'current_ps_turn': res[0][2] if res[0][4] % 2 == 0 else res[0][1],
'piece_index': 1 if res[0][4] % 2 == 0 else 0
}
if state['game_type'] == 'gomoku':
game = Gomoku(state)
elif state['game_type'] == 'isola':
game = Isola(state)
print_header()
game.print_challenge_text()
game.print_board()
if not state['current_ps_turn'] == username:
print('\nIt is your opponents turn.\n')
return True
if game.winner:
print('You are viewing a game that has already finished')
return True
play = game.get_input()
if not play:
# A false value for play would occur from a forfeit
sys.exit(0)
else:
q2 = "UPDATE games SET game_board = ?, turn = ?, winner = ? WHERE rowid = ?"
v2 = (json.dumps(play['board']), state['turn_number'] + 1, play['winner'], gid)
res2 = db_do(q2, v2, True)
if not res2:
print('Error updating database, sorry.\nTry again later?\n...or contact the sysadmin.')
return False
print(play['message'])
# Binds to the LIST command
def list_games():
q = "SELECT rowid, p1, p2, game_type, game_status, turn FROM games WHERE winner is 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.')
return False
print_header()
print('{:^8} {:^10} {:^10} {:^22} {:^12}'.format('ID', 'Player 1', 'Player 2', 'Game Status', 'Game Type'))
print('-------- ---------- ---------- ---------------------- ------------')
for x in res:
pturn = x[2] if x[5] % 2 == 0 else x[1]
print("{:^8} {:^10} {:^10} {:^22} {:^12}".format(x[0], x[1], x[2], pturn +"'s turn", x[3]))
if not len(res):
print('You are not currently playing any games...')
print('')
return True
# Binds to the HELP command
def display_help():
print_header()
print('syntax: oberon [command [option]]\n')
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('')
# Binds to the CREATE command
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()
# if not enemy in enemies:
# print('There is no avialable player with the name {}.\nGame not created.'.format(enemy))
# return False
print_header()
print('Which game would you like to play?\n\n(1) Gomoku/Five In a Row\n(2) Isola\n\nor (Q)uit')
while True:
game = input('> ')
if game.lower() == 'q':
sys.exit(0)
elif not game in ['1', '2']:
continue
break
if game == '1':
game_board = [[' · ' for y in range(15)] for x in range(15)]
game_choice = 'gomoku'
else:
board = [[ ' - ' for y in range(7)] for x in range(7)]
board[0][3] = ' X '
board[6][3] = ' O '
game_board = {'board': board, 'p1': [0,3], 'p2': [6,3]}
game_choice = 'isola'
q = "INSERT INTO games VALUES (?, ?, ?, ?, ?, ?, ?)"
v = (username, enemy, game_choice, 'playing', json.dumps(game_board), 1, None)
res = db_do(q, v, True)
if res:
print('Game between {} and {} created!'.format(username, enemy))
return True
return False
# Binds to the AVAILABLE command
def available_moves():
q = "SELECT p1, p2, turn FROM games WHERE winner is null and (p1 = ? or p2 = ?)"
v = (username, username)
res = db_do(q, v)
p1 = len([x for x in res if x[0] == username and x[2] % 2 != 0])
p2 = len([x for x in res if x[1] == username and x[2] % 2 == 0])
if p1 + p2 > 0:
print('It is your turn in oberon!\n')
##############################
######------------------#######
###### Sys Utilities ########
######------------------#######
##############################
def parse_args():
args = sys.argv
arg_len = len(args)
if arg_len == 1:
display_help()
sys.exit(0)
if arg_len == 2:
if args[1] == 'list':
l = list_games()
if l:
sys.exit(0)
sys.exit(1)
elif args[1] == 'history':
h = show_game_record()
if h:
sys.exit(0)
sys.exit(1)
elif args[1] == 'available':
available_moves()
sys.exit(0)
elif args[1] == 'create':
print('Must include an opponent name.\nFind one in chat or cspc!')
sys.exit(1)
elif args[1] == 'play':
print('Must include a game id.\nRun "oberon list" to view your open games.')
sys.exit(1)
elif args[1] == 'help':
display_help()
sys.exit(0)
else:
print('Invalid arguments. Run "oberon help".')
sys.exit(1)
elif arg_len == 3:
if args[1] == 'create':
if create_game(args[2]):
sys.exit(0)
sys.exit(1)
elif args[1] == 'play':
try:
game_id = int(args[2])
except:
print('Invalid game id.')
sys.exit(1)
play_game(game_id)
sys.exit(0)
else:
print('Invalid arguments. Run "oberon help".')
sys.exit(1)
else:
print('Unknown paramaters: {}'.format(' '.join(args[3:])))
sys.exit(1)
def get_user_list():
res = subprocess.run(['awk', '-F', ':', '{if ($7 == "/usr/local/bin/colorsh") print $1}', '/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
##############################
######------------------#######
###### DB Utilities ########
######------------------#######
##############################
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 = database
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:
return False
if __name__ == '__main__':
check_and_build_db(database)
parse_args()