Browse Source

Added save & load config ability

master
Doug Le Tough 6 years ago
parent
commit
4d68c215a1
20 changed files with 287 additions and 161 deletions
  1. BIN
      01.png
  2. BIN
      02.png
  3. BIN
      03.png
  4. BIN
      04.png
  5. BIN
      05.png
  6. BIN
      06.png
  7. BIN
      07.png
  8. BIN
      08.png
  9. BIN
      09.png
  10. BIN
      10.png
  11. BIN
      11.png
  12. +5
    -0
      CHANGELOG.TXT
  13. +11
    -2
      README.md
  14. +0
    -2
      TODO.TXT
  15. +12
    -12
      ai.py
  16. +6
    -6
      bot.py
  17. +114
    -57
      client.py
  18. +1
    -1
      game.py
  19. +138
    -81
      ui.py
  20. BIN
      vindinium_curses_ui_menu.png

BIN
01.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 13 KiB

BIN
02.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 19 KiB

BIN
03.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 10 KiB

BIN
04.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 10 KiB

BIN
05.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 10 KiB

BIN
06.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 9.9 KiB

BIN
07.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 9.4 KiB

BIN
08.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 10 KiB

BIN
09.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 18 KiB

BIN
10.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 9.7 KiB

BIN
11.png View File

Before After
Width: 1366  |  Height: 307  |  Size: 10 KiB

+ 5
- 0
CHANGELOG.TXT View File

@ -1,3 +1,8 @@
2014-10-10:
- Added load config from file ability
- Added save config to file ability
- Massive code cleaning
2014-10-08:
- Added input checking in setup menu
- Added menu screenchots


+ 11
- 2
README.md View File

@ -86,6 +86,15 @@ http://www.vindinium.org/
![Curses U.I Setup menu](vindinium_curses_ui_menu.png)
![Main menu](01.png)
![Game mode selection](02.png)
![Number of games input (Arena mode)](03.png)
![Server URL input](04.png)
![Player key input](05.png)
![Save config screen](06.png)
![Play game screen](07.png)
![Number of turns input (Training mode)](08.png)
![Game map selection (Training mode)](09.png)
![Game file path input](10.png)
![Game file URL input](11.png)
![Curses U.I running a game](vindinium_curses_ui.png)

+ 0
- 2
TODO.TXT View File

@ -3,8 +3,6 @@ TODO
- Add ability to load game
- Add ability to save game
- Add ability to replay game
- Add ability to load default parameters via config file
- Add ability to save config in file
- Define one unique color for each player
- Add game summary at end of game
- Add currently winning player identification mark while game is running


+ 12
- 12
ai.py View File

@ -52,8 +52,8 @@ class AI:
actions = ['mine', 'tavern', 'fight']
decisions = {'mine': [("Mine", 30), ('Fight', 10), ('Tavern', 5)],
'tavern': [("Mine", 10), ('Fight', 10), ('Tavern', 50)],
decisions = {'mine': [("Mine", 30), ('Fight', 10), ('Tavern', 5)],
'tavern': [("Mine", 10), ('Fight', 10), ('Tavern', 50)],
'fight': [("Mine", 15), ('Fight', 30), ('Tavern', 10)]}
walkable = []
@ -63,8 +63,8 @@ class AI:
for y in range(self.game.board_size):
for x in range(self.game.board_size):
if (y, x) not in self.game.walls_locs or \
(y, x) not in self.game.taverns_locs or \
(y, x) not in self.game.mines_locs:
(y, x) not in self.game.taverns_locs or \
(y, x) not in self.game.mines_locs:
walkable.append((y, x))
@ -76,9 +76,9 @@ class AI:
for i in range(int(round(random.random()*self.game.board_size))):
for i in range(len(walkable)):
random.shuffle(walkable)
if (walkable[i][0] - first_cell[0] == 1 and
if (walkable[i][0] - first_cell[0] == 1 and
walkable[i][1] - first_cell[1] == 0) or \
(walkable[i][1] - first_cell[1] == 1 and
(walkable[i][1] - first_cell[1] == 1 and
walkable[i][0] - first_cell[0] == 0):
path_to_goal.append(walkable[i])
first_cell = walkable[i]
@ -91,12 +91,12 @@ class AI:
nearest_mine_pos = random.choice(self.game.mines_locs)
nearest_tavern_pos = random.choice(self.game.mines_locs)
return (path_to_goal,
action,
decision,
hero_move,
nearest_enemy_pos,
nearest_mine_pos,
return (path_to_goal,
action,
decision,
hero_move,
nearest_enemy_pos,
nearest_mine_pos,
nearest_tavern_pos)


+ 6
- 6
bot.py View File

@ -43,12 +43,12 @@ class Curses_ui_bot:
self.ai.process(self.game)
self.path_to_goal, \
self.action, \
self.decision, \
self.hero_move, \
self.nearest_enemy_pos, \
self.nearest_mine_pos, \
self.nearest_tavern_pos = self.ai.decide()
self.action, \
self.decision, \
self.hero_move, \
self.nearest_enemy_pos, \
self.nearest_mine_pos, \
self.nearest_tavern_pos = self.ai.decide()
################################################################
# /AI


+ 114
- 57
client.py View File

@ -7,10 +7,23 @@ import ui
import sys
import select
import time
import os
import ConfigParser
TIMEOUT = 15
class Config:
def __init__(self, game_mode="training", server_url="http://vindinium.org",
number_of_games=1, number_of_turns=300, map_name="m1", key=None):
self.game_mode = game_mode
self.number_of_games = number_of_games
self.number_of_turns = number_of_turns
self.map_name = map_name
self.server_url = server_url
self.key = key
class Client:
def __init__(self):
self.start_time = None
@ -18,6 +31,8 @@ class Client:
self.session = None
self.state = None
self.running = True
self.game_url = None
self.config = Config()
self.bot = Curses_ui_bot() # Our bot
def _print(self, *args, **kwargs):
@ -45,84 +60,127 @@ class Client:
else:
print printable
def load_config(self):
"""Load saved config from file ~/.vindinium/config"""
config_parser = ConfigParser.ConfigParser()
user_home_dir = os.path.expanduser("~")
config_file_name = os.path.join(user_home_dir, ".vindinium", "config")
try:
if os.path.isfile(config_file_name):
config_parser.read(config_file_name)
self.config.server_url = config_parser.get("game", "server_url")
self.config.game_mode = config_parser.get("game", "game_mode")
self.config.map_name = config_parser.get("game", "map_name")
self.config.key = config_parser.get("game", "key")
self.config.number_of_games = config_parser.getint("game", "number_of_games")
self.config.number_of_turns = config_parser.getint("game", "number_of_turns")
except Exception as e:
self.gui.quit_ui()
print "Error while loading config file", config_file_name, ":", e
quit(1)
def save_config(self):
"""Save config to file in ~/.vindinium/config"""
config_parser = ConfigParser.ConfigParser()
user_home_dir = os.path.expanduser("~")
config_file_name = os.path.join(user_home_dir, ".vindinium", "config")
try:
if not os.path.isdir(os.path.join(user_home_dir, ".vindinium")):
os.makedirs(os.path.join(user_home_dir, ".vindinium"))
config_parser.add_section("game")
with open(config_file_name, "w") as config_file:
for key, value in self.config.__dict__.items():
config_parser.set("game", key, value)
config_parser.write(config_file)
except Exception as e:
self.gui.quit_ui()
print "Error while saving config file", config_file_name, ":", e
quit(1)
def start_ui(self):
""" Start the curses UI"""
self.gui = ui.tui()
choice = self.gui.ask_main_menu()
number_of_games = 1
number_of_turns = 300
map_name = ""
if choice == '1':
# Load config then play game
self.load_config()
self.gui.draw_game_windows()
self.play()
elif choice == '2':
# Setup game
choice = self.gui.ask_game_mode()
if choice == '1':
# Arena mode
game_mode = "arena"
number_of_games = self.gui.ask_number_games()
# Arena mode config
self.config.game_mode = "arena"
self.config.number_of_games = self.gui.ask_number_games()
elif choice == '2':
# Training mode
game_mode = "training"
number_of_turns = self.gui.ask_number_turns()
map_name = self.gui.ask_map()
server_url = self.gui.ask_server_url(game_mode)
key = self.gui.ask_key(game_mode)
# Start game U.I
self.gui.draw_game_windows()
# Launch game
self.play(number_of_games, number_of_turns, server_url, key, game_mode, map_name)
elif choice == '2':
# Training mode config
self.config.game_mode = "training"
self.config.number_of_turns = self.gui.ask_number_turns()
self.config.map_name = "m"+str(self.gui.ask_map())
self.config.server_url = self.gui.ask_server_url(self.config.game_mode)
self.config.key = self.gui.ask_key(self.config.game_mode)
if self.gui.ask_save_config():
self.save_config()
if self.gui.ask_play_game():
# Start game U.I
self.gui.draw_game_windows()
# Launch game
self.play()
else:
self.start_ui()
elif choice == '3':
# Load game from file
game_file_path = self.gui.ask_game_file_path()
self.gui.quit_ui()
print game_file_path, len(game_file_path)
exit(0)
elif choice == '3':
elif choice == '4':
# Load game from URL
game_file_url = self.gui.ask_game_file_url()
self.gui.quit_ui()
print game_file_url, len(game_file_url)
exit(0)
elif choice == '4':
elif choice == '5':
# quit
self.gui.quit_ui()
exit(0)
def play(self, number_of_games, number_of_turns, server_url, key, game_mode, game_map=""):
def play(self):
""" Play all games """
for i in range(number_of_games):
for i in range(self.config.number_of_games):
# start a new game
if self.bot.running:
self.start_game(server_url, key, game_mode, number_of_turns, game_map)
self._print("Game finished: "+str(i+1)+"/"+str(number_of_games))
self.start_game()
self._print("Game finished: "+str(i+1)+"/"+str(self.config.number_of_games))
if self.gui.running and self.gui.help_win:
self.gui.ask_quit()
def start_game(self, server_url, key, game_mode, turns, game_map):
def start_game(self):
"""Starts a game with all the required parameters"""
self.running = True
# Default move is no move !
direction = "Stay"
# Create a requests session that will be used throughout the game
self.session = requests.session()
if game_mode == 'arena':
if self.config.game_mode == 'arena':
self._print('Connecting and waiting for other players to join...')
try:
# Get the initial state
self.state = self.get_new_game_state(self.session, server_url, key, game_mode, turns, game_map)
self.state = self.get_new_game_state()
self._print("Playing at: " + self.state['viewUrl'])
except Exception as e:
self._print("Error: Please verify your settings.")
self._print("Settings:", server_url, key, game_mode, turns)
self._print("Settings:", len(server_url), len(key), len(game_mode), type(turns))
self._print("Settings:", self.config.__dict__)
self._print("Game state:", self.state)
self.running = False
self.gui.ask_quit()
quit(0)
for i in range(turns + 1):
for i in range(self.config.number_of_turns + 1):
if self.running:
# Choose a move
self.start = time.time()
self.start_time = time.time()
try:
while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
line = sys.stdin.read(1)
@ -147,25 +205,25 @@ class Client:
self.gui.ask_quit()
if not self.is_game_over(self.state):
# Send the move and receive the updated game state
self.url = self.state['playUrl']
self.state = self.send_move(self.session, self.url, direction)
self.game_url = self.state['playUrl']
self.state = self.send_move(direction)
# Clean up the session
self.session.close()
def get_new_game_state(self, session, server_url, key, game_mode, number_of_turns, game_map):
def get_new_game_state(self):
"""Get a JSON from the server containing the current state of the game"""
if game_mode == 'training':
if self.config.game_mode == 'training':
# Don't pass the 'map' parameter if no map has been selected
if len(game_map) > 0:
params = {'key': key, 'turns': number_of_turns, 'map': game_map}
if len(self.config.map_name) > 0:
params = {'key': self.config.key, 'turns': self.config.number_of_turns, 'map': self.config.map_name}
else:
params = {'key': key, 'turns': number_of_turns}
params = {'key': self.config.key, 'turns': self.config.number_of_turns}
api_endpoint = '/api/training'
elif game_mode == 'arena':
params = {'key': key}
elif self.config.game_mode == 'arena':
params = {'key': self.config.key}
api_endpoint = '/api/arena'
# Wait for 10 minutes
r = session.post(server_url + api_endpoint, params, timeout=10*60)
r = self.session.post(self.config.server_url + api_endpoint, params, timeout=10*60)
if r.status_code == 200:
return r.json()
else:
@ -177,14 +235,14 @@ class Client:
"""Return True if game defined by state is over"""
try:
return state['game']['finished']
except Exception as e:
except Exception:
return True
def send_move(self, session, url, direction):
def send_move(self, direction):
"""Send a move to the server
Moves can be one of: 'Stay', 'North', 'South', 'East', 'West'"""
try:
r = session.post(url, {'dir': direction}, timeout=TIMEOUT)
r = self.session.post(self.game_url, {'dir': direction}, timeout=TIMEOUT)
if r.status_code == 200:
return r.json()
else:
@ -244,15 +302,14 @@ class Client:
self.gui.display_action(self.bot.action)
# Add whathever you want to log using self.gui.append_log()
# self.gui.append_log("Whatever")
elapsed = round(time.time() - self.start, 3)
elapsed = round(time.time() - self.start_time, 3)
self.gui.display_elapsed(elapsed)
self.gui.refresh()
if __name__ == "__main__":
server_url = "http://vindinium.org"
client = Client()
if len(sys.argv) == 1:
# Go for interactive setup
client = Client()
client.start_ui()
elif len(sys.argv) < 3 or sys.argv[1] == "--help":
print "Usage: %s <key> <[training|arena]> <number-of-games|number-of-turns> [server-url]" % (sys.argv[0])
@ -260,19 +317,19 @@ if __name__ == "__main__":
print 'Example: %s mySecretKey training 20' % (sys.argv[0])
exit(0)
elif len(sys.argv) > 3:
key = sys.argv[1]
mode = sys.argv[2]
if mode == "training":
number_of_games = 1
number_of_turns = int(sys.argv[3])
client.config.key = sys.argv[1]
client.config.game_mode = sys.argv[2]
if client.config.game_mode == "training":
client.config.number_of_games = 1
client.config.number_of_turns = int(sys.argv[3])
else:
number_of_games = int(sys.argv[3])
number_of_turns = 300 # Ignored in arena mode
client.config.number_of_games = int(sys.argv[3])
client.config.number_of_turns = 300 # Ignored in arena mode
if len(sys.argv) == 5:
server_url = sys.argv[4]
client.config.server_url = sys.argv[4]
# Go for playing according to sys.argv
# Do not use interactive setup
client = Client()
client.gui = ui.tui()
client.start_ui()
client.gui.draw_game_windows()
client.play(number_of_games, number_of_turns, server_url, key, mode)
client.play()

+ 1
- 1
game.py View File

@ -9,7 +9,7 @@ class Hero:
# Training bots have no elo or userId
self.elo = hero['elo']
self.user_id = hero['userId']
except:
except KeyError:
self.elo = 0
self.user_id = 0


+ 138
- 81
ui.py View File

@ -56,7 +56,7 @@ class tui:
self.MENU_Y = 0
self.MENU_X = 0
self.MENU_H = 20
self.MENU_H = 24
self.MENU_W = 0
self.data_win = None
@ -99,10 +99,10 @@ class tui:
curses.cbreak()
curses.curs_set(0)
self.stdscr.keypad(1)
#- /screen init ----
# - /screen init ----
#- /init ---------------------------------------------------------------
# - /init ---------------------------------------------------------------
def refresh(self):
"""Refresh all windows"""
@ -127,7 +127,7 @@ class tui:
curses.doupdate()
#- Draw game windows ---------------------------------------------------
# - Draw game windows --------------------------------------------------
def draw_game_windows(self):
"""Draw the windows needed for the game"""
@ -149,19 +149,19 @@ class tui:
self.data_pan = curses.panel.new_panel(self.data_win)
self.stdscr.addstr(self.DATA_Y - 1, self.DATA_X + 1, "Game", curses.A_BOLD)
data_lines = ["Playing",
"Bot name",
"Elo", \
"Elapsed time",
"Turn",
"Position",
"Life",
"Mine count",
"Gold",
"Move",
"Action",
"Nearest hero",
"Nearest bar",
data_lines = ["Playing",
"Bot name",
"Elo",
"Elapsed time",
"Turn",
"Position",
"Life",
"Mine count",
"Gold",
"Move",
"Action",
"Nearest hero",
"Nearest bar",
"Nearest mine"]
self.data_win.vline(1, 13, curses.ACS_VLINE, self.DATA_H)
@ -223,16 +223,16 @@ class tui:
self.players_win = curses.newwin(self.PLAYERS_H, self.PLAYERS_W, self.PLAYERS_Y, self.PLAYERS_X)
self.players_win.box()
self.players_pan = curses.panel.new_panel(self.players_win)
players_lines = ["Name",
"User ID",
"Bot ID",
"Elo",
"Position",
"Life",
"Mine count",
"Gold",
"Spawn pos",
"Crashed"]
players_lines = ["Name",
"User ID",
"Bot ID",
"Elo",
"Position",
"Life",
"Mine count",
"Gold",
"Spawn pos",
"Crashed"]
self.players_win.vline(1, 11, curses.ACS_VLINE, self.PLAYERS_H-2)
self.players_win.vline(1, 29, curses.ACS_VLINE, self.PLAYERS_H-2)
@ -248,7 +248,7 @@ class tui:
for line in players_lines:
self.players_win.addstr(y+1, 1, line, curses.A_BOLD)
if y < len(players_lines)*2 - 2:
self.players_win.hline(y + 2, 1, curses.ACS_HLINE, self.PLAYERS_W-2)
self.players_win.hline(y + 2, 1, curses.ACS_HLINE, self.PLAYERS_W-2)
self.players_win.addch(y + 2, 0, curses.ACS_LTEE)
self.players_win.addch(y + 2, 11, curses.ACS_PLUS)
self.players_win.addch(y + 2, 29, curses.ACS_PLUS)
@ -257,6 +257,7 @@ class tui:
y += 2
def draw_time_win(self):
"""Draw time line"""
self.TIME_W = self.LOG_W + self.MAP_W + 4
self.stdscr.addstr(self.TIME_Y - 1, self.TIME_X + 1, "Time line", curses.A_BOLD)
self.time_win = curses.newwin(3, self.TIME_W, self.TIME_Y, self.TIME_X)
@ -310,8 +311,8 @@ class tui:
attr = curses.A_BOLD + curses.color_pair(7)
if not (char == " " and (y, x in path)):
self.map_win.addch(y + 1, x + 1, char, attr)
x = x +1
y = y +1
x = x + 1
y = y + 1
# / Draw window --------------------------------------------------------
@ -449,37 +450,37 @@ class tui:
self.data_win.addstr(23, 23, str(hero))
def display_decision(self, decision):
self.path_win.hline(1, 14, " ", 51)
self.path_win.hline(1, 14, " ", 51)
d = ""
for h in decision:
d += str(h[0])+": "+str(h[1])+" | "
self.path_win.addstr(1, 14, d)
def display_path(self, path):
self.path_win.hline(3, 14, " ", 51)
self.path_win.hline(3, 14, " ", 51)
path = str(path).strip('[').strip(']')[0:48]+"..."
self.path_win.addstr(3, 14, path)
def clear_data_cell(self, pos, length):
self.data_win.hline(pos[0], pos[1], " ", length)
self.data_win.hline(pos[0], pos[1], " ", length)
# TIME CURSOR ----------------------------------------------------------
def move_time_cursor(self, pos):
self.time_win.box()
self.time_win.hline(1, 1, curses.ACS_BLOCK, self.TIME_W - 2)
self.time_win.hline(1, 1, curses.ACS_BLOCK, self.TIME_W - 2)
if pos < 1:
pos = 1
if pos > self.TIME_W - 2:
pos = self.TIME_W - 2
if pos > 1:
self.time_win.addch(0, pos - 1, curses.ACS_TTEE)
self.time_win.addch(1, pos - 1 , curses.ACS_VLINE)
self.time_win.addch(2, pos - 1 , curses.ACS_BTEE)
self.time_win.addch(1, pos - 1, curses.ACS_VLINE)
self.time_win.addch(2, pos - 1, curses.ACS_BTEE)
if pos < self.TIME_W - 2:
self.time_win.addch(0, pos + 1, curses.ACS_TTEE)
self.time_win.addch(1, pos + 1 , curses.ACS_VLINE)
self.time_win.addch(2, pos + 1 , curses.ACS_BTEE)
self.time_win.addch(1, pos + 1, curses.ACS_VLINE)
self.time_win.addch(2, pos + 1, curses.ACS_BTEE)
self.time_win.addstr(1, pos, " ", curses.color_pair(4) + curses.A_REVERSE)
@ -496,12 +497,11 @@ class tui:
def purge_log(self):
"""Purge log of oldest entries"""
diff = len(self.log_entries) - (self.LOG_H - self.HELP_H -2)
diff = len(self.log_entries) - (self.LOG_H - self.HELP_H - 2)
if diff > 0:
for i in range(diff):
self.log_entries.remove(self.log_entries[i])
def display_log(self):
"""Display log entries"""
if self.log_win:
@ -527,12 +527,12 @@ class tui:
Print error message and return false otherwise"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
if num != None:
if num is not None:
try:
num = int(str(num).strip(chr(0)))
if num > 0:
return True
except:
except (ValueError, TypeError):
self.menu_win.addstr(15, offset + 7, "Please, input a integer greater than 0.", curses.color_pair(3))
self.menu_win.refresh()
return False
@ -556,25 +556,27 @@ class tui:
def check_url(self, url):
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
if len(url.strip(chr(0))) > 0:
url = url.strip(chr(0)).strip()
if len(url) > 0:
# text_box.edit return a null char at start:(
check = urlparse.urlparse(url)
if len(check.scheme.strip(chr(0)).strip()) > 0 and len(check.netloc.strip(chr(0)).strip()) > 0:
if len(check.scheme) > 0 and len(check.netloc) > 0:
return True
self.menu_win.addstr(15, offset + 12, "Please, input a valid URL.", curses.color_pair(3))
self.menu_win.refresh()
return False
def check_file_url(self, url):
"""Return True if url is a valid url with 'file path'"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
if len(url.strip(chr(0))) > 0:
url = url.strip(chr(0)).strip()
if len(url) > 0:
# text_box.edit return a null char at start:(
check = urlparse.urlparse(url)
if len(check.scheme.strip(chr(0)).strip()) > 0 and \
len(check.netloc.strip(chr(0)).strip()) > 0 and \
len(check.path.strip(chr(0)).strip()) > 0:
if len(check.scheme) > 0 and \
len(check.netloc) > 0 and \
len(check.path) > 0:
return True
self.menu_win.addstr(15, offset + 12, "Please, input a valid URL.", curses.color_pair(3))
self.menu_win.refresh()
@ -583,7 +585,8 @@ class tui:
def check_file_path(self, path):
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
if len(path.strip(chr(0))) > 0:
path = path.strip(chr(0)).strip()
if len(path) > 0:
# text_box.edit return a null char at start:(
if os.path.exists(path):
return True
@ -592,16 +595,17 @@ class tui:
return False
def check_key(self, player_key):
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
"""Check the player key format"""
if len(player_key.strip(chr(0)).strip()) > 0:
pattern="^([0-9]|[a-z]){8}"
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x / 2 - 25
player_key = player_key.strip(chr(0)).strip()
if len(player_key) > 0:
pattern = "^([0-9]|[a-z]){8}"
f = re.search(pattern, player_key)
try:
if len(f.group(0)) == 8 and len(player_key.strip(chr(0)).strip()) == 8:
if len(f.group(0)) == 8 and len(player_key) == 8:
return True
except:
except (TypeError, AttributeError):
pass
self.menu_win.addstr(15, offset + 12, "Please, input a a valid key.", curses.color_pair(3))
self.menu_win.refresh()
@ -624,30 +628,31 @@ class tui:
self.menu_win.addstr(3, offset, title3, curses.A_BOLD + curses.color_pair(4))
self.menu_win.addstr(4, offset, title4, curses.A_BOLD + curses.color_pair(4))
self.menu_win.addstr(5, offset, title5, curses.A_BOLD + curses.color_pair(4))
self.menu_win.addstr(7, offset + 8, "Welcome to the Vindinium curses client", curses.A_BOLD + curses.A_UNDERLINE )
self.menu_win.addstr(7, offset + 8, "Welcome to the Vindinium curses client", curses.A_BOLD + curses.A_UNDERLINE)
def ask_main_menu(self):
"""Display main menu window and ask for choice"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
choice = "0"
options = ["1", "2", "3", "4"]
options = ["1", "2", "3", "4", "5"]
self.menu_win = curses.newwin(self.MENU_H, self.MENU_W, self.MENU_Y, self.MENU_X)
self.draw_banner()
self.menu_win.addstr(9, offset + 8, "Please, choose an option:", curses.A_BOLD)
self.menu_win.addstr(11, offset + 10, "1", curses.A_BOLD)
self.menu_win.addstr(11, offset + 12, "- Setup & play game")
self.menu_win.addstr(11, offset + 12, "- Play game")
self.menu_win.addstr(13, offset + 10, "2", curses.A_BOLD)
self.menu_win.addstr(13, offset + 12, "- Load game from file")
self.menu_win.addstr(13, offset + 12, "- Setup game")
self.menu_win.addstr(15, offset + 10, "3", curses.A_BOLD)
self.menu_win.addstr(15, offset + 12, "- Load game from URL")
self.menu_win.addstr(15, offset + 12, "- Load game from file")
self.menu_win.addstr(17, offset + 10, "4", curses.A_BOLD)
self.menu_win.addstr(17, offset + 12, "- Quit")
self.menu_win.addstr(17, offset + 12, "- Load game from URL")
self.menu_win.addstr(19, offset + 10, "5", curses.A_BOLD)
self.menu_win.addstr(19, offset + 12, "- Quit")
while choice not in options:
choice = self.ask_action()
return choice
def ask_game_mode(self):
"""Display game mode menu and ask for choice"""
screen_y, screen_x = self.stdscr.getmaxyx()
@ -690,7 +695,6 @@ class tui:
curses.curs_set(0)
return int(str(num_game).strip(chr(0)).strip())
def ask_number_turns(self):
"""Ask for number_of_turns"""
screen_y, screen_x = self.stdscr.getmaxyx()
@ -735,7 +739,6 @@ class tui:
curses.panel.update_panels()
self.input_win.refresh()
while not self.check_url(server_url):
# TODO: Better url check
curses.curs_set(1)
server_url = text_box.edit(self.check_input)
curses.curs_set(0)
@ -771,12 +774,11 @@ class tui:
"""Ask for game file url"""
file_url = ""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
offset_2 = 19
offset = screen_x / 2 - 25
self.draw_banner()
self.menu_win.addstr(13, offset + 6, "File URL:", curses.A_BOLD)
text_box = curses.textpad.rectangle(self.menu_win, 12, offset + 18, 14, offset + 48)
self.input_win = self.menu_win.subwin(1, 29, 13, offset + 19)
self.menu_win.addstr(13, offset - 6, "File URL:", curses.A_BOLD)
text_box = curses.textpad.rectangle(self.menu_win, 12, offset + 5, 14, offset + 55)
self.input_win = self.menu_win.subwin(1, 49, 13, offset + 6)
self.input_win.bkgd(curses.color_pair(4) + curses.A_REVERSE)
self.input_win.addstr(0, 0, file_url)
input_pan = curses.panel.new_panel(self.input_win)
@ -785,7 +787,6 @@ class tui:
curses.panel.update_panels()
self.input_win.refresh()
while not self.check_file_url(file_url):
# TODO: Better url check
curses.curs_set(1)
file_url = text_box.edit(self.check_input)
curses.curs_set(0)
@ -795,12 +796,11 @@ class tui:
"""Ask for game file path"""
file_path = ""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
offset_2 = 19
offset = screen_x / 2 - 25
self.draw_banner()
self.menu_win.addstr(13, offset + 6, "File path:", curses.A_BOLD)
text_box = curses.textpad.rectangle(self.menu_win, 12, offset + 18, 14, offset + 48)
self.input_win = self.menu_win.subwin(1, 29, 13, offset + 19)
self.menu_win.addstr(13, offset - 6, "File path:", curses.A_BOLD)
text_box = curses.textpad.rectangle(self.menu_win, 12, offset + 5, 14, offset + 55)
self.input_win = self.menu_win.subwin(1, 49, 13, offset + 6)
self.input_win.bkgd(curses.color_pair(4) + curses.A_REVERSE)
self.input_win.addstr(0, 0, file_path)
input_pan = curses.panel.new_panel(self.input_win)
@ -809,14 +809,73 @@ class tui:
curses.panel.update_panels()
self.input_win.refresh()
while not self.check_file_path(file_path):
# TODO: Better url check
curses.curs_set(1)
file_path = text_box.edit(self.check_input)
curses.curs_set(0)
return str(file_path).strip(chr(0)).strip()
def ask_save_config(self):
"""Ask for config save"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
choice = "0"
options = ["1", "2"]
self.menu_win = curses.newwin(self.MENU_H, self.MENU_W, self.MENU_Y, self.MENU_X)
self.draw_banner()
self.menu_win.addstr(11, offset + 8, "Save configuration ?", curses.A_BOLD)
self.menu_win.addstr(13, offset + 10, "1", curses.A_BOLD)
self.menu_win.addstr(13, offset + 12, "- Yes")
self.menu_win.addstr(15, offset + 10, "2", curses.A_BOLD)
self.menu_win.addstr(15, offset + 12, "- No")
while choice not in options:
choice = self.ask_action()
if choice == "1":
return True
return False
def ask_play_game(self):
"""Ask for playing game"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
choice = "0"
options = ["1", "2"]
self.menu_win = curses.newwin(self.MENU_H, self.MENU_W, self.MENU_Y, self.MENU_X)
self.draw_banner()
self.menu_win.addstr(11, offset + 8, "Play game ?", curses.A_BOLD)
self.menu_win.addstr(13, offset + 10, "1", curses.A_BOLD)
self.menu_win.addstr(13, offset + 12, "- Yes")
self.menu_win.addstr(15, offset + 10, "2", curses.A_BOLD)
self.menu_win.addstr(15, offset + 12, "- No")
while choice not in options:
choice = self.ask_action()
if choice == "1":
return True
return False
def ask_map(self):
return "m5"
"""Display main menu window and ask for choice"""
screen_y, screen_x = self.stdscr.getmaxyx()
offset = screen_x/2 - 25
choice = "0"
options = ["1", "2", "3", "4", "5", "6"]
self.menu_win = curses.newwin(self.MENU_H, self.MENU_W, self.MENU_Y, self.MENU_X)
self.draw_banner()
self.menu_win.addstr(9, offset + 8, "Please, choose a map:", curses.A_BOLD)
self.menu_win.addstr(11, offset + 10, "1", curses.A_BOLD)
self.menu_win.addstr(11, offset + 12, "- M1 : A 10X10 symetrical map")
self.menu_win.addstr(13, offset + 10, "2", curses.A_BOLD)
self.menu_win.addstr(13, offset + 12, "- M2 : A 12X12 symetrical map")
self.menu_win.addstr(15, offset + 10, "3", curses.A_BOLD)
self.menu_win.addstr(15, offset + 12, "- M3 : A 20X20 asymetrical map")
self.menu_win.addstr(17, offset + 10, "4", curses.A_BOLD)
self.menu_win.addstr(17, offset + 12, "- M4 : A 18X18 symetrical map")
self.menu_win.addstr(19, offset + 10, "5", curses.A_BOLD)
self.menu_win.addstr(19, offset + 12, "- M5 : A 18X18 symetrical map")
self.menu_win.addstr(19, offset + 10, "6", curses.A_BOLD)
self.menu_win.addstr(19, offset + 12, "- M6 : A 16X16 symetrical map")
while choice not in options:
choice = self.ask_action()
return choice
# QUIT -----------------------------------------------------------------
@ -847,5 +906,3 @@ class tui:
def pause(self):
self.paused = not self.paused

BIN
vindinium_curses_ui_menu.png View File

Before After
Width: 1024  |  Height: 969  |  Size: 109 KiB

Loading…
Cancel
Save