oberon/oberon

346 lines
11 KiB
Plaintext
Raw Normal View History

#!/usr/bin/env python3
import sys
import sqlite3 as sql
import os
from os.path import isfile as fileexists
import subprocess
import json
from gomoku import Gomoku
from isola import Isola
2019-04-26 03:11:47 +00:00
from brandubh import Brandubh
version = '0.8.1'
home_folder = os.path.expanduser('~')
username = os.path.split(home_folder)[-1]
database = '/var/lib/oberon/oberon.sqlite'
2019-04-30 06:03:12 +00:00
basefile = '/var/lib/oberon/'
2018-12-30 00:47:24 +00:00
def print_header():
print('\nO B E R O N v{}\n'.format(version))
##############################
######------------------#######
###### Top Lvl Cmds ########
######------------------#######
##############################
2018-12-30 00:47:24 +00:00
# Binds to the HISTORY command
def show_game_record():
q = "SELECT rowid, p1, p2, winner, game_type 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} {:^12}'.format('ID', 'Player 1', 'Player 2', 'Winner', 'Game Type'))
print('-------- ---------- ---------- ---------- ------------')
for x in res:
print('{:^8} {:^10} {:^10} {:^10} {:^12}'.format(x[0], x[1], x[2], x[3], x[4]))
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)
2019-04-26 03:11:47 +00:00
elif state['game_type'] == 'brandubh':
game = Brandubh(state)
2018-12-30 00:47:24 +00:00
print_header()
game.print_challenge_text()
game.print_board()
2018-12-30 00:47:24 +00:00
if not state['current_ps_turn'] == username:
print('\nIt is your opponents turn.\n')
return True
2018-12-30 00:47:24 +00:00
if game.winner:
print('You are viewing a game that has already finished')
return True
play = game.get_input()
if not play:
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 play['winner']:
enemy = state['p1'] if state['p1'] != username else state['p2']
2019-04-30 06:03:12 +00:00
msg_path = basefile + '{}'.format(enemy)
writemode = 'a' if fileexists(msg_path) else 'w'
with open(msg_path, writemode) as f:
f.write('{} defeated you in {} game {}\n'.format(username, state['game_type'], gid))
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):
2018-12-30 00:47:24 +00:00
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')
2018-12-30 00:47:24 +00:00
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('')
print('if you do not want to play games simply add a file named ".killoberon" to your home directory and users will not be able to create games with you')
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
if fileexists('/home/{}/.killoberon'.format(enemy)):
print('{} does not wish to play games in oberon. Please try creating a game with a different user.'.format(enemy))
return False
print_header()
2019-04-26 03:11:47 +00:00
print('Which game would you like to play?\n\n(1) Gomoku/Five In a Row\n(2) Isola\n(3) Brandubh\n\nor (Q)uit')
while True:
game = input('> ')
if game.lower() == 'q':
sys.exit(0)
2019-04-26 03:11:47 +00:00
elif not game in ['1', '2', '3']:
continue
break
if game == '1':
game_board = [[' · ' for y in range(15)] for x in range(15)]
game_choice = 'gomoku'
2019-04-26 03:11:47 +00:00
elif game == '2':
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'
2019-04-26 03:11:47 +00:00
elif game == '3':
game_board = [[ ' - ' for y in range(7)] for x in range(7)]
game_board[0][0] = ' * '
game_board[0][6] = ' * '
game_board[6][0] = ' * '
game_board[6][6] = ' * '
for x in [0,1,5,6]:
game_board[3][x] = ' a '
game_board[x][3] = ' a '
for x in [2,4]:
game_board[3][x] = ' d '
game_board[x][3] = ' d '
game_board[3][3] = ' D '
game_choice = 'brandubh'
player = '0'
print('')
while not player in ['1','2']:
print('Play as player 1 or player 2 (enter the number)')
player = input('> ')
if player == '2':
temp = enemy
enemy = username
player = temp
else:
player = username
q = "INSERT INTO games VALUES (?, ?, ?, ?, ?, ?, ?)"
v = (player, 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 rowid, p1, p2, turn FROM games WHERE winner is null and (p1 = ? or p2 = ?)"
v = (username, username)
res = db_do(q, v)
p1 = [x[0] for x in res if x[1] == username and x[3] % 2 != 0]
p2 = [x[0] for x in res if x[2] == username and x[3] % 2 == 0]
print('- - - -')
if len(p1) + len(p2) > 0:
p1 = ', '.join(str(x) for x in p1)
p2 = ', '.join(str(x) for x in p2)
spacer = ', ' if p1 and p2 else ''
print('\033[1;32mIt is your turn in the following game(s): {}{}{}\033[0m'.format(p1, spacer, p2))
else:
print('It is not your turn in any games...\n')
##############################
######------------------#######
###### Sys Utilities ########
######------------------#######
##############################
def parse_args():
args = sys.argv
arg_len = len(args)
if arg_len == 1:
display_help()
available_moves()
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()