mirror of
https://github.com/solero/houdini.git
synced 2024-11-25 15:07:24 +00:00
Fix potential cyclic import issue & move minigame logic into handler module
This commit is contained in:
parent
4b88edbc4d
commit
dd291ab5b3
@ -36,6 +36,56 @@ class _AbstractManager(dict):
|
|||||||
"""Loads entries from module"""
|
"""Loads entries from module"""
|
||||||
|
|
||||||
|
|
||||||
|
class ITable(ABC):
|
||||||
|
"""
|
||||||
|
All table game logic classes must implement this interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def make_move(self, *args):
|
||||||
|
"""Tells logic a move has been made."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def is_valid_move(self, *args):
|
||||||
|
"""Returns true if the move is valid."""
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def get_string(self):
|
||||||
|
"""Returns string representation of the game."""
|
||||||
|
|
||||||
|
|
||||||
|
class IWaddle(ABC):
|
||||||
|
"""
|
||||||
|
All waddle game logic classes must implement this interface.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@property
|
||||||
|
@abstractmethod
|
||||||
|
def room_id(self):
|
||||||
|
"""External ID of waddle game room."""
|
||||||
|
|
||||||
|
def __init__(self, waddle):
|
||||||
|
self.penguins = list(waddle.penguins)
|
||||||
|
self.seats = waddle.seats
|
||||||
|
|
||||||
|
async def start(self):
|
||||||
|
room_id = type(self).room_id
|
||||||
|
for penguin in self.penguins:
|
||||||
|
penguin.waddle = self
|
||||||
|
await penguin.join_room(penguin.server.rooms[room_id])
|
||||||
|
|
||||||
|
async def remove_penguin(self, p):
|
||||||
|
self.penguins.remove(p)
|
||||||
|
p.waddle = None
|
||||||
|
|
||||||
|
async def send_xt(self, *data):
|
||||||
|
for penguin in self.penguins:
|
||||||
|
await penguin.send_xt(*data)
|
||||||
|
|
||||||
|
def get_seat_id(self, p):
|
||||||
|
return self.penguins.index(p)
|
||||||
|
|
||||||
|
|
||||||
class PenguinStringCompiler(OrderedDict):
|
class PenguinStringCompiler(OrderedDict):
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -194,12 +194,6 @@ class RoomTable(db.Model):
|
|||||||
nullable=False)
|
nullable=False)
|
||||||
game = db.Column(db.String(20), nullable=False)
|
game = db.Column(db.String(20), nullable=False)
|
||||||
|
|
||||||
GameClassMapping = {
|
|
||||||
'four': ConnectFourLogic,
|
|
||||||
'mancala': MancalaLogic,
|
|
||||||
'treasure': TreasureHuntLogic
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.penguins = []
|
self.penguins = []
|
||||||
@ -267,9 +261,8 @@ class RoomWaddle(db.Model):
|
|||||||
seats = db.Column(db.SmallInteger, nullable=False, server_default=db.text("2"))
|
seats = db.Column(db.SmallInteger, nullable=False, server_default=db.text("2"))
|
||||||
game = db.Column(db.String(20), nullable=False)
|
game = db.Column(db.String(20), nullable=False)
|
||||||
|
|
||||||
GameClassMapping = {
|
def __init__(self, *args, **kwargs):
|
||||||
self.temporary = kwargs.pop('temporary', False)
|
self.temporary = kwargs.pop('temporary', False)
|
||||||
}
|
|
||||||
self.penguins = []
|
self.penguins = []
|
||||||
self.logic = None
|
self.logic = None
|
||||||
self.room = None
|
self.room = None
|
||||||
@ -288,7 +281,7 @@ class RoomWaddle(db.Model):
|
|||||||
p.waddle = self
|
p.waddle = self
|
||||||
|
|
||||||
if self.penguins.count(None) == 0:
|
if self.penguins.count(None) == 0:
|
||||||
game_instance = RoomWaddle.GameClassMapping[self.game](self)
|
game_instance = self.logic(self)
|
||||||
await game_instance.start()
|
await game_instance.start()
|
||||||
|
|
||||||
await self.reset()
|
await self.reset()
|
||||||
@ -330,16 +323,3 @@ class RoomCollection(AbstractDataCollection):
|
|||||||
@property
|
@property
|
||||||
def spawn_rooms(self):
|
def spawn_rooms(self):
|
||||||
return [room for room in self.values() if room.spawn]
|
return [room for room in self.values() if room.spawn]
|
||||||
|
|
||||||
async def setup_tables(self):
|
|
||||||
async with db.transaction():
|
|
||||||
async for table in RoomTable.query.gino.iterate():
|
|
||||||
self[table.room_id].tables[table.id] = table
|
|
||||||
table.room = self[table.room_id]
|
|
||||||
table.logic = RoomTable.GameClassMapping[table.game]()
|
|
||||||
|
|
||||||
async def setup_waddles(self):
|
|
||||||
async with db.transaction():
|
|
||||||
async for waddle in RoomWaddle.query.gino.iterate():
|
|
||||||
self[waddle.room_id].waddles[waddle.id] = waddle
|
|
||||||
waddle.room = self[waddle.room_id]
|
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
from abc import ABC
|
|
||||||
from abc import abstractmethod
|
|
||||||
|
|
||||||
|
|
||||||
class ITable(ABC):
|
|
||||||
"""
|
|
||||||
All table game logic classes must implement this interface.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def make_move(self, *args):
|
|
||||||
"""Tells logic a move has been made."""
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def is_valid_move(self, *args):
|
|
||||||
"""Returns true if the move is valid."""
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_string(self):
|
|
||||||
"""Returns string representation of the game."""
|
|
||||||
|
|
||||||
|
|
||||||
class IWaddle(ABC):
|
|
||||||
"""
|
|
||||||
All waddle game logic classes must implement this interface.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@property
|
|
||||||
@abstractmethod
|
|
||||||
def __room_id__(self):
|
|
||||||
"""External ID of waddle game room."""
|
|
||||||
|
|
||||||
def __init__(self, waddle):
|
|
||||||
self.penguins = list(waddle.penguins)
|
|
||||||
self.seats = waddle.seats
|
|
||||||
|
|
||||||
async def start(self):
|
|
||||||
room_id = type(self).__room_id__
|
|
||||||
for penguin in self.penguins:
|
|
||||||
penguin.waddle = self
|
|
||||||
await penguin.join_room(penguin.server.rooms[room_id])
|
|
||||||
|
|
||||||
async def remove_penguin(self, p):
|
|
||||||
self.penguins.remove(p)
|
|
||||||
p.waddle = None
|
|
||||||
|
|
||||||
async def send_xt(self, *data):
|
|
||||||
for penguin in self.penguins:
|
|
||||||
await penguin.send_xt(*data)
|
|
@ -1,45 +0,0 @@
|
|||||||
from houdini.games import ITable
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectFourLogic(ITable):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.current_player = 1
|
|
||||||
self.board = [[0 for _ in range(6)] for _ in range(7)]
|
|
||||||
|
|
||||||
def make_move(self, col, row):
|
|
||||||
self.board[col][row] = self.current_player
|
|
||||||
|
|
||||||
def is_valid_move(self, col, row):
|
|
||||||
if 0 <= row <= 5 and 0 <= col <= 6:
|
|
||||||
if row == 5 or (self.board[col][row] == 0 and self.board[col][row + 1]):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_string(self):
|
|
||||||
return ','.join(str(item) for row in self.board for item in row)
|
|
||||||
|
|
||||||
def is_position_win(self, col, row):
|
|
||||||
for delta_row, delta_col in [(1, 0), (0, 1), (1, 1), (1, -1)]:
|
|
||||||
streak = 1
|
|
||||||
for delta in (1, -1):
|
|
||||||
delta_row *= delta
|
|
||||||
delta_col *= delta
|
|
||||||
next_row = row + delta_row
|
|
||||||
next_col = col + delta_col
|
|
||||||
while 0 <= next_row < 6 and 0 <= next_col < 7:
|
|
||||||
if self.board[next_col][next_row] == self.current_player:
|
|
||||||
streak += 1
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
if streak == 4:
|
|
||||||
return True
|
|
||||||
next_row += delta_row
|
|
||||||
next_col += delta_col
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_board_full(self):
|
|
||||||
for col in self.board:
|
|
||||||
if not col[0]:
|
|
||||||
return False
|
|
||||||
return True
|
|
@ -1,63 +0,0 @@
|
|||||||
from houdini.games import ITable
|
|
||||||
|
|
||||||
|
|
||||||
class MancalaLogic(ITable):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.current_player = 1
|
|
||||||
self.board = [
|
|
||||||
4, 4, 4, 4, 4, 4, 0,
|
|
||||||
4, 4, 4, 4, 4, 4, 0
|
|
||||||
]
|
|
||||||
|
|
||||||
def make_move(self, hollow):
|
|
||||||
capture = False
|
|
||||||
hand = self.board[hollow]
|
|
||||||
self.board[hollow] = 0
|
|
||||||
|
|
||||||
while hand > 0:
|
|
||||||
hollow = (hollow + 1) % len(self.board)
|
|
||||||
my_mancala, opponent_mancala = (6, 13) if self.current_player == 1 else (13, 6)
|
|
||||||
|
|
||||||
if hollow == opponent_mancala:
|
|
||||||
continue
|
|
||||||
opposite_hollow = 12 - hollow
|
|
||||||
|
|
||||||
if hand == 1 and self.board[hollow] == 0:
|
|
||||||
if (self.current_player == 1 and hollow in range(0, 6)) or (self.current_player == 2 and hollow in range(7, 13)):
|
|
||||||
self.board[my_mancala] += self.board[opposite_hollow] + 1
|
|
||||||
self.board[opposite_hollow] = 0
|
|
||||||
capture = True
|
|
||||||
break
|
|
||||||
|
|
||||||
self.board[hollow] += 1
|
|
||||||
hand -= 1
|
|
||||||
|
|
||||||
if (self.current_player == 1 and hollow != 6) or (self.current_player == 2 and hollow != 13):
|
|
||||||
return 'c' if capture else str()
|
|
||||||
else:
|
|
||||||
self.current_player = 2 if self.current_player == 1 else 1
|
|
||||||
return 'f'
|
|
||||||
|
|
||||||
def is_valid_move(self, hollow):
|
|
||||||
if self.current_player == 1 and hollow not in range(0, 6):
|
|
||||||
return False
|
|
||||||
elif self.current_player == 2 and hollow not in range(7, 13):
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def get_string(self):
|
|
||||||
return ','.join(map(str, self.board))
|
|
||||||
|
|
||||||
def is_position_win(self):
|
|
||||||
if sum(self.board[0:6]) == 0 or sum(self.board[7:-1]) == 0:
|
|
||||||
if sum(self.board[0:6]) > sum(self.board[7:-1]):
|
|
||||||
return self.current_player == 1
|
|
||||||
return self.current_player == 2
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_position_tie(self):
|
|
||||||
if sum(self.board[0:6]) == 0 or sum(self.board[7:-1]) == 0:
|
|
||||||
if sum(self.board[0:6]) == sum(self.board[7:-1]):
|
|
||||||
return True
|
|
||||||
return False
|
|
@ -1,19 +0,0 @@
|
|||||||
from houdini.games import IWaddle
|
|
||||||
|
|
||||||
|
|
||||||
class SledRacingLogic(IWaddle):
|
|
||||||
|
|
||||||
__room_id__ = 999
|
|
||||||
|
|
||||||
def __init__(self, waddle):
|
|
||||||
super().__init__(waddle)
|
|
||||||
|
|
||||||
self.payouts = [20, 10, 5, 5]
|
|
||||||
|
|
||||||
async def remove_penguin(self, p):
|
|
||||||
await super().remove_penguin(p)
|
|
||||||
await self.send_xt('uz', self.seats, *(f'{penguin.safe_name}|{penguin.color}|'
|
|
||||||
f'{penguin.hand}|{penguin.safe_name}' for penguin in self.penguins))
|
|
||||||
|
|
||||||
def get_payout(self):
|
|
||||||
return self.payouts.pop(0)
|
|
@ -1,129 +0,0 @@
|
|||||||
from houdini.games import ITable
|
|
||||||
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
class TreasureHuntLogic(ITable):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.map_width = 10
|
|
||||||
self.map_height = 10
|
|
||||||
self.coins_hidden = 0
|
|
||||||
self.gems_hidden = 0
|
|
||||||
self.turns = 12
|
|
||||||
self.gem_value = 25
|
|
||||||
self.coin_value = 1
|
|
||||||
self.gem_locations = []
|
|
||||||
self.treasure_map = []
|
|
||||||
self.coins_found = 0
|
|
||||||
self.gems_found = 0
|
|
||||||
self.emerald_found = 0
|
|
||||||
self.dig_record_names = []
|
|
||||||
self.dig_record_directions = []
|
|
||||||
self.dig_record_numbers = []
|
|
||||||
self.emerald = 0
|
|
||||||
self.current_player = 1
|
|
||||||
self.generate_map()
|
|
||||||
|
|
||||||
def make_move(self, movie, direction, spade):
|
|
||||||
if direction == 'right':
|
|
||||||
row = self.treasure_map[spade]
|
|
||||||
for column, tiles in enumerate(row):
|
|
||||||
self.dig(spade, column)
|
|
||||||
elif direction == 'down':
|
|
||||||
for row, columns in enumerate(self.treasure_map):
|
|
||||||
self.dig(row, spade)
|
|
||||||
self.turns -= 1
|
|
||||||
self.dig_record_names.append(movie)
|
|
||||||
self.dig_record_directions.append(direction)
|
|
||||||
self.dig_record_numbers.append(spade)
|
|
||||||
|
|
||||||
def is_valid_move(self, movie, direction, spade):
|
|
||||||
test_movie = direction + 'button' + str(spade) + '_mc'
|
|
||||||
if test_movie == movie and direction in ['down', 'right'] and 0 <= spade <= 9:
|
|
||||||
if direction == 'right':
|
|
||||||
row = self.treasure_map[spade]
|
|
||||||
for column, tiles in enumerate(row):
|
|
||||||
treasure, digs = self.treasure_map[spade][column]
|
|
||||||
if digs == 2:
|
|
||||||
return False
|
|
||||||
elif direction == 'down':
|
|
||||||
for row, columns in enumerate(self.treasure_map):
|
|
||||||
treasure, digs = self.treasure_map[row][spade]
|
|
||||||
if digs == 2:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def get_string(self):
|
|
||||||
treasure_map = ','.join(str(item) for row in self.treasure_map for item, digs in row)
|
|
||||||
gem_locations = ','.join(self.gem_locations)
|
|
||||||
game_array = [self.map_width, self.map_height, self.coins_hidden, self.gems_hidden, self.turns,
|
|
||||||
self.gem_value, self.coin_value, gem_locations, treasure_map]
|
|
||||||
if self.dig_record_numbers:
|
|
||||||
game_array += [self.coins_found, self.gems_found, self.emerald_found]
|
|
||||||
game_array += [','.join(self.dig_record_names), ','.join(self.dig_record_directions),
|
|
||||||
','.join(map(str, self.dig_record_numbers))]
|
|
||||||
return '%'.join(map(str, game_array))
|
|
||||||
|
|
||||||
def generate_map(self):
|
|
||||||
for row in range(self.map_height):
|
|
||||||
self.treasure_map.append([])
|
|
||||||
for column in range(self.map_width):
|
|
||||||
self.treasure_map[row].append([self.generate_treasure(row, column), 0])
|
|
||||||
|
|
||||||
def generate_treasure(self, row, column):
|
|
||||||
treasure_type = [('None', 0), ('Coin', 1), ('Gem', 2), ('Emerald', 4)]
|
|
||||||
if self.get_gem_by_piece(row, column):
|
|
||||||
return 3
|
|
||||||
if row + 1 == self.map_height or column + 1 == self.map_width:
|
|
||||||
treasure_type = treasure_type[:2]
|
|
||||||
name, value = random.choices(treasure_type, weights=[60, 40, 1, 0.5][:len(treasure_type)])[0]
|
|
||||||
self.coins_hidden += 1 if value == 1 else self.coins_hidden
|
|
||||||
if value > 1:
|
|
||||||
self.gems_hidden += 1
|
|
||||||
self.gem_locations.append(str(row) + ',' + str(column))
|
|
||||||
if self.emerald:
|
|
||||||
return 2
|
|
||||||
if value == 4 and not self.emerald:
|
|
||||||
self.emerald = 1
|
|
||||||
return value
|
|
||||||
|
|
||||||
def get_gem_by_piece(self, row, column):
|
|
||||||
for delta_row, delta_col in [(0, -1), (-1, -1), (-1, 0)]:
|
|
||||||
if row > 0 and column > 0:
|
|
||||||
treasure, digs = self.treasure_map[row + delta_row][column + delta_col]
|
|
||||||
if treasure == 2 or treasure == 4:
|
|
||||||
return row + delta_row, column + delta_col
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_gem_uncovered(self, row, column):
|
|
||||||
for delta_row, delta_col in [(0, 1), (1, 1), (1, 0)]:
|
|
||||||
treasure, digs = self.treasure_map[row + delta_row][column + delta_col]
|
|
||||||
if digs != 2:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def dig(self, row, column):
|
|
||||||
self.treasure_map[row][column][1] += 1
|
|
||||||
treasure, digs = self.treasure_map[row][column]
|
|
||||||
if digs == 2:
|
|
||||||
if treasure == 1:
|
|
||||||
self.coins_found += 1
|
|
||||||
elif treasure == 2 or treasure == 4:
|
|
||||||
if not self.is_gem_uncovered(row, column):
|
|
||||||
return
|
|
||||||
self.gems_found += 1
|
|
||||||
elif treasure == 3:
|
|
||||||
treasure_row, treasure_col = self.get_gem_by_piece(row, column)
|
|
||||||
if not self.is_gem_uncovered(treasure_row, treasure_col):
|
|
||||||
return
|
|
||||||
self.gems_found += 1
|
|
||||||
if treasure == 4:
|
|
||||||
self.emerald_found = 1
|
|
||||||
|
|
||||||
def determine_winnings(self):
|
|
||||||
total = self.coins_found * self.coin_value
|
|
||||||
total += self.gems_found * self.gem_value
|
|
||||||
total += self.emerald_found * self.gem_value * 3
|
|
||||||
return total
|
|
@ -2,16 +2,58 @@ from houdini import ITable, handlers
|
|||||||
from houdini.handlers import XTPacket
|
from houdini.handlers import XTPacket
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectFourLogic(ITable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.current_player = 1
|
||||||
|
self.board = [[0 for _ in range(6)] for _ in range(7)]
|
||||||
|
|
||||||
|
def make_move(self, col, row):
|
||||||
|
self.board[col][row] = self.current_player
|
||||||
|
|
||||||
|
def is_valid_move(self, col, row):
|
||||||
|
if 0 <= row <= 5 and 0 <= col <= 6:
|
||||||
|
if row == 5 or (self.board[col][row] == 0 and self.board[col][row + 1]):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_string(self):
|
||||||
|
return ','.join(str(item) for row in self.board for item in row)
|
||||||
|
|
||||||
|
def is_position_win(self, col, row):
|
||||||
|
for delta_row, delta_col in [(1, 0), (0, 1), (1, 1), (1, -1)]:
|
||||||
|
streak = 1
|
||||||
|
for delta in (1, -1):
|
||||||
|
delta_row *= delta
|
||||||
|
delta_col *= delta
|
||||||
|
next_row = row + delta_row
|
||||||
|
next_col = col + delta_col
|
||||||
|
while 0 <= next_row < 6 and 0 <= next_col < 7:
|
||||||
|
if self.board[next_col][next_row] == self.current_player:
|
||||||
|
streak += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if streak == 4:
|
||||||
|
return True
|
||||||
|
next_row += delta_row
|
||||||
|
next_col += delta_col
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_board_full(self):
|
||||||
|
for col in self.board:
|
||||||
|
if not col[0]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('gz', ext='z'))
|
@handlers.handler(XTPacket('gz', ext='z'))
|
||||||
@table_handler(ConnectFourLogic)
|
@handlers.table(ConnectFourLogic)
|
||||||
async def handle_get_game(p):
|
async def handle_get_game(p):
|
||||||
await p.send_xt('gz', p.table.get_string())
|
await p.send_xt('gz', p.table.get_string())
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('jz', ext='z'))
|
@handlers.handler(XTPacket('jz', ext='z'))
|
||||||
@table_handler(ConnectFourLogic)
|
@handlers.table(ConnectFourLogic)
|
||||||
async def handle_join_game(p):
|
async def handle_join_game(p):
|
||||||
game_full = len(p.table.penguins) > 2
|
game_full = len(p.table.penguins) > 2
|
||||||
if not game_full:
|
if not game_full:
|
||||||
@ -24,7 +66,7 @@ async def handle_join_game(p):
|
|||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('zm', ext='z'))
|
@handlers.handler(XTPacket('zm', ext='z'))
|
||||||
@table_handler(ConnectFourLogic)
|
@handlers.table(ConnectFourLogic)
|
||||||
async def handle_send_move(p, col: int, row: int):
|
async def handle_send_move(p, col: int, row: int):
|
||||||
try:
|
try:
|
||||||
seat_id = p.table.get_seat_id(p)
|
seat_id = p.table.get_seat_id(p)
|
||||||
|
@ -2,16 +2,76 @@ from houdini import ITable, handlers
|
|||||||
from houdini.handlers import XTPacket
|
from houdini.handlers import XTPacket
|
||||||
|
|
||||||
|
|
||||||
|
class MancalaLogic(ITable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.current_player = 1
|
||||||
|
self.board = [
|
||||||
|
4, 4, 4, 4, 4, 4, 0,
|
||||||
|
4, 4, 4, 4, 4, 4, 0
|
||||||
|
]
|
||||||
|
|
||||||
|
def make_move(self, hollow):
|
||||||
|
capture = False
|
||||||
|
hand = self.board[hollow]
|
||||||
|
self.board[hollow] = 0
|
||||||
|
|
||||||
|
while hand > 0:
|
||||||
|
hollow = (hollow + 1) % len(self.board)
|
||||||
|
my_mancala, opponent_mancala = (6, 13) if self.current_player == 1 else (13, 6)
|
||||||
|
|
||||||
|
if hollow == opponent_mancala:
|
||||||
|
continue
|
||||||
|
opposite_hollow = 12 - hollow
|
||||||
|
|
||||||
|
if hand == 1 and self.board[hollow] == 0:
|
||||||
|
if (self.current_player == 1 and hollow in range(0, 6)) or (self.current_player == 2 and hollow in range(7, 13)):
|
||||||
|
self.board[my_mancala] += self.board[opposite_hollow] + 1
|
||||||
|
self.board[opposite_hollow] = 0
|
||||||
|
capture = True
|
||||||
|
break
|
||||||
|
|
||||||
|
self.board[hollow] += 1
|
||||||
|
hand -= 1
|
||||||
|
|
||||||
|
if (self.current_player == 1 and hollow != 6) or (self.current_player == 2 and hollow != 13):
|
||||||
|
return 'c' if capture else str()
|
||||||
|
else:
|
||||||
|
self.current_player = 2 if self.current_player == 1 else 1
|
||||||
|
return 'f'
|
||||||
|
|
||||||
|
def is_valid_move(self, hollow):
|
||||||
|
if self.current_player == 1 and hollow not in range(0, 6):
|
||||||
|
return False
|
||||||
|
elif self.current_player == 2 and hollow not in range(7, 13):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_string(self):
|
||||||
|
return ','.join(map(str, self.board))
|
||||||
|
|
||||||
|
def is_position_win(self):
|
||||||
|
if sum(self.board[0:6]) == 0 or sum(self.board[7:-1]) == 0:
|
||||||
|
if sum(self.board[0:6]) > sum(self.board[7:-1]):
|
||||||
|
return self.current_player == 1
|
||||||
|
return self.current_player == 2
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_position_tie(self):
|
||||||
|
if sum(self.board[0:6]) == 0 or sum(self.board[7:-1]) == 0:
|
||||||
|
if sum(self.board[0:6]) == sum(self.board[7:-1]):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('gz', ext='z'))
|
@handlers.handler(XTPacket('gz', ext='z'))
|
||||||
@table_handler(MancalaLogic)
|
@handlers.table(MancalaLogic)
|
||||||
async def handle_get_game(p):
|
async def handle_get_game(p):
|
||||||
await p.send_xt('gz', p.table.get_string())
|
await p.send_xt('gz', p.table.get_string())
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('jz', ext='z'))
|
@handlers.handler(XTPacket('jz', ext='z'))
|
||||||
@table_handler(MancalaLogic)
|
@handlers.table(MancalaLogic)
|
||||||
async def handle_join_game(p):
|
async def handle_join_game(p):
|
||||||
game_full = len(p.table.penguins) > 2
|
game_full = len(p.table.penguins) > 2
|
||||||
if not game_full:
|
if not game_full:
|
||||||
@ -24,7 +84,7 @@ async def handle_join_game(p):
|
|||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('zm', ext='z'))
|
@handlers.handler(XTPacket('zm', ext='z'))
|
||||||
@table_handler(MancalaLogic)
|
@handlers.table(MancalaLogic)
|
||||||
async def handle_send_move(p, hollow: int):
|
async def handle_send_move(p, hollow: int):
|
||||||
try:
|
try:
|
||||||
seat_id = p.table.get_seat_id(p)
|
seat_id = p.table.get_seat_id(p)
|
||||||
|
@ -2,23 +2,39 @@ from houdini import IWaddle, handlers
|
|||||||
from houdini.handlers import XTPacket
|
from houdini.handlers import XTPacket
|
||||||
|
|
||||||
|
|
||||||
|
class SledRacingLogic(IWaddle):
|
||||||
|
|
||||||
|
room_id = 999
|
||||||
|
|
||||||
|
def __init__(self, waddle):
|
||||||
|
super().__init__(waddle)
|
||||||
|
|
||||||
|
self.payouts = [20, 10, 5, 5]
|
||||||
|
|
||||||
|
async def remove_penguin(self, p):
|
||||||
|
await super().remove_penguin(p)
|
||||||
|
await self.send_xt('uz', self.seats, *(f'{penguin.safe_name}|{penguin.color}|'
|
||||||
|
f'{penguin.hand}|{penguin.safe_name}' for penguin in self.penguins))
|
||||||
|
|
||||||
|
def get_payout(self):
|
||||||
|
return self.payouts.pop(0)
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('jz', ext='z'))
|
@handlers.handler(XTPacket('jz', ext='z'))
|
||||||
@waddle_handler(SledRacingLogic)
|
@handlers.waddle(SledRacingLogic)
|
||||||
async def handle_join_game(p):
|
async def handle_join_game(p):
|
||||||
await p.send_xt('uz', p.waddle.seats, *(f'{penguin.safe_name}|{penguin.color}|'
|
await p.send_xt('uz', p.waddle.seats, *(f'{penguin.safe_name}|{penguin.color}|'
|
||||||
f'{penguin.hand or 0}|{penguin.nickname}' for penguin in p.waddle.penguins))
|
f'{penguin.hand or 0}|{penguin.nickname}' for penguin in p.waddle.penguins))
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('zm', ext='z'))
|
@handlers.handler(XTPacket('zm', ext='z'))
|
||||||
@waddle_handler(SledRacingLogic)
|
@handlers.waddle(SledRacingLogic)
|
||||||
async def handle_send_move(p, player_id: int, x: float, y: float, time: float):
|
async def handle_send_move(p, player_id: int, x: float, y: float, time: float):
|
||||||
await p.waddle.send_xt('zm', player_id, x, y, time)
|
await p.waddle.send_xt('zm', player_id, x, y, time)
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('zo', ext='z'))
|
@handlers.handler(XTPacket('zo', ext='z'))
|
||||||
@waddle_handler(SledRacingLogic)
|
@handlers.waddle(SledRacingLogic)
|
||||||
async def handle_game_over(p):
|
async def handle_game_over(p):
|
||||||
coins = p.waddle.get_payout()
|
coins = p.waddle.get_payout()
|
||||||
await p.add_coins(coins)
|
await p.add_coins(coins)
|
||||||
|
@ -4,10 +4,134 @@ from houdini import ITable, handlers
|
|||||||
from houdini.handlers import XTPacket
|
from houdini.handlers import XTPacket
|
||||||
|
|
||||||
|
|
||||||
|
class TreasureHuntLogic(ITable):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.map_width = 10
|
||||||
|
self.map_height = 10
|
||||||
|
self.coins_hidden = 0
|
||||||
|
self.gems_hidden = 0
|
||||||
|
self.turns = 12
|
||||||
|
self.gem_value = 25
|
||||||
|
self.coin_value = 1
|
||||||
|
self.gem_locations = []
|
||||||
|
self.treasure_map = []
|
||||||
|
self.coins_found = 0
|
||||||
|
self.gems_found = 0
|
||||||
|
self.emerald_found = 0
|
||||||
|
self.dig_record_names = []
|
||||||
|
self.dig_record_directions = []
|
||||||
|
self.dig_record_numbers = []
|
||||||
|
self.emerald = 0
|
||||||
|
self.current_player = 1
|
||||||
|
self.generate_map()
|
||||||
|
|
||||||
|
def make_move(self, movie, direction, spade):
|
||||||
|
if direction == 'right':
|
||||||
|
row = self.treasure_map[spade]
|
||||||
|
for column, tiles in enumerate(row):
|
||||||
|
self.dig(spade, column)
|
||||||
|
elif direction == 'down':
|
||||||
|
for row, columns in enumerate(self.treasure_map):
|
||||||
|
self.dig(row, spade)
|
||||||
|
self.turns -= 1
|
||||||
|
self.dig_record_names.append(movie)
|
||||||
|
self.dig_record_directions.append(direction)
|
||||||
|
self.dig_record_numbers.append(spade)
|
||||||
|
|
||||||
|
def is_valid_move(self, movie, direction, spade):
|
||||||
|
test_movie = direction + 'button' + str(spade) + '_mc'
|
||||||
|
if test_movie == movie and direction in ['down', 'right'] and 0 <= spade <= 9:
|
||||||
|
if direction == 'right':
|
||||||
|
row = self.treasure_map[spade]
|
||||||
|
for column, tiles in enumerate(row):
|
||||||
|
treasure, digs = self.treasure_map[spade][column]
|
||||||
|
if digs == 2:
|
||||||
|
return False
|
||||||
|
elif direction == 'down':
|
||||||
|
for row, columns in enumerate(self.treasure_map):
|
||||||
|
treasure, digs = self.treasure_map[row][spade]
|
||||||
|
if digs == 2:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def get_string(self):
|
||||||
|
treasure_map = ','.join(str(item) for row in self.treasure_map for item, digs in row)
|
||||||
|
gem_locations = ','.join(self.gem_locations)
|
||||||
|
game_array = [self.map_width, self.map_height, self.coins_hidden, self.gems_hidden, self.turns,
|
||||||
|
self.gem_value, self.coin_value, gem_locations, treasure_map]
|
||||||
|
if self.dig_record_numbers:
|
||||||
|
game_array += [self.coins_found, self.gems_found, self.emerald_found]
|
||||||
|
game_array += [','.join(self.dig_record_names), ','.join(self.dig_record_directions),
|
||||||
|
','.join(map(str, self.dig_record_numbers))]
|
||||||
|
return '%'.join(map(str, game_array))
|
||||||
|
|
||||||
|
def generate_map(self):
|
||||||
|
for row in range(self.map_height):
|
||||||
|
self.treasure_map.append([])
|
||||||
|
for column in range(self.map_width):
|
||||||
|
self.treasure_map[row].append([self.generate_treasure(row, column), 0])
|
||||||
|
|
||||||
|
def generate_treasure(self, row, column):
|
||||||
|
treasure_type = [('None', 0), ('Coin', 1), ('Gem', 2), ('Emerald', 4)]
|
||||||
|
if self.get_gem_by_piece(row, column):
|
||||||
|
return 3
|
||||||
|
if row + 1 == self.map_height or column + 1 == self.map_width:
|
||||||
|
treasure_type = treasure_type[:2]
|
||||||
|
name, value = random.choices(treasure_type, weights=[60, 40, 1, 0.5][:len(treasure_type)])[0]
|
||||||
|
self.coins_hidden += 1 if value == 1 else self.coins_hidden
|
||||||
|
if value > 1:
|
||||||
|
self.gems_hidden += 1
|
||||||
|
self.gem_locations.append(str(row) + ',' + str(column))
|
||||||
|
if self.emerald:
|
||||||
|
return 2
|
||||||
|
if value == 4 and not self.emerald:
|
||||||
|
self.emerald = 1
|
||||||
|
return value
|
||||||
|
|
||||||
|
def get_gem_by_piece(self, row, column):
|
||||||
|
for delta_row, delta_col in [(0, -1), (-1, -1), (-1, 0)]:
|
||||||
|
if row > 0 and column > 0:
|
||||||
|
treasure, digs = self.treasure_map[row + delta_row][column + delta_col]
|
||||||
|
if treasure == 2 or treasure == 4:
|
||||||
|
return row + delta_row, column + delta_col
|
||||||
|
return False
|
||||||
|
|
||||||
|
def is_gem_uncovered(self, row, column):
|
||||||
|
for delta_row, delta_col in [(0, 1), (1, 1), (1, 0)]:
|
||||||
|
treasure, digs = self.treasure_map[row + delta_row][column + delta_col]
|
||||||
|
if digs != 2:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def dig(self, row, column):
|
||||||
|
self.treasure_map[row][column][1] += 1
|
||||||
|
treasure, digs = self.treasure_map[row][column]
|
||||||
|
if digs == 2:
|
||||||
|
if treasure == 1:
|
||||||
|
self.coins_found += 1
|
||||||
|
elif treasure == 2 or treasure == 4:
|
||||||
|
if not self.is_gem_uncovered(row, column):
|
||||||
|
return
|
||||||
|
self.gems_found += 1
|
||||||
|
elif treasure == 3:
|
||||||
|
treasure_row, treasure_col = self.get_gem_by_piece(row, column)
|
||||||
|
if not self.is_gem_uncovered(treasure_row, treasure_col):
|
||||||
|
return
|
||||||
|
self.gems_found += 1
|
||||||
|
if treasure == 4:
|
||||||
|
self.emerald_found = 1
|
||||||
|
|
||||||
|
def determine_winnings(self):
|
||||||
|
total = self.coins_found * self.coin_value
|
||||||
|
total += self.gems_found * self.gem_value
|
||||||
|
total += self.emerald_found * self.gem_value * 3
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('gz', ext='z'))
|
@handlers.handler(XTPacket('gz', ext='z'))
|
||||||
@table_handler(TreasureHuntLogic)
|
@handlers.table(TreasureHuntLogic)
|
||||||
async def handle_get_game(p):
|
async def handle_get_game(p):
|
||||||
if len(p.table.penguins) == 2:
|
if len(p.table.penguins) == 2:
|
||||||
player_one = p.table.penguins[0]
|
player_one = p.table.penguins[0]
|
||||||
@ -17,7 +141,7 @@ async def handle_get_game(p):
|
|||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('jz', ext='z'))
|
@handlers.handler(XTPacket('jz', ext='z'))
|
||||||
@table_handler(TreasureHuntLogic)
|
@handlers.table(TreasureHuntLogic)
|
||||||
async def handle_join_game(p):
|
async def handle_join_game(p):
|
||||||
game_full = len(p.table.penguins) > 2
|
game_full = len(p.table.penguins) > 2
|
||||||
if not game_full:
|
if not game_full:
|
||||||
@ -29,7 +153,7 @@ async def handle_join_game(p):
|
|||||||
|
|
||||||
|
|
||||||
@handlers.handler(XTPacket('zm', ext='z'))
|
@handlers.handler(XTPacket('zm', ext='z'))
|
||||||
@table_handler(TreasureHuntLogic)
|
@handlers.table(TreasureHuntLogic)
|
||||||
async def handle_send_move(p, movie: str, direction: str, spade: int):
|
async def handle_send_move(p, movie: str, direction: str, spade: int):
|
||||||
try:
|
try:
|
||||||
seat_id = p.table.get_seat_id(p)
|
seat_id = p.table.get_seat_id(p)
|
||||||
|
@ -19,18 +19,48 @@ from houdini.handlers.games.ninja.water import CardJitsuWaterLogic, WaterSenseiL
|
|||||||
from houdini.handlers.games.sled import SledRacingLogic
|
from houdini.handlers.games.sled import SledRacingLogic
|
||||||
from houdini.handlers.games.treasure import TreasureHuntLogic
|
from houdini.handlers.games.treasure import TreasureHuntLogic
|
||||||
|
|
||||||
import random
|
TableLogicMapping = {
|
||||||
import time
|
'four': ConnectFourLogic,
|
||||||
import pytz
|
'mancala': MancalaLogic,
|
||||||
import hashlib
|
'treasure': TreasureHuntLogic
|
||||||
from datetime import date, datetime
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WaddleLogicMapping = {
|
||||||
|
'sled': SledRacingLogic,
|
||||||
|
|
||||||
|
'card': CardJitsuLogic,
|
||||||
|
'sensei': SenseiLogic,
|
||||||
|
|
||||||
|
'water': CardJitsuWaterLogic,
|
||||||
|
'watersensei': WaterSenseiLogic,
|
||||||
|
|
||||||
|
'fire': CardJitsuFireLogic,
|
||||||
|
'firesensei': FireSenseiLogic
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_tables(room_collection):
|
||||||
|
async with db.transaction():
|
||||||
|
async for table in RoomTable.query.gino.iterate():
|
||||||
|
room_collection[table.room_id].tables[table.id] = table
|
||||||
|
table.room = room_collection[table.room_id]
|
||||||
|
table.logic = TableLogicMapping[table.game]()
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_waddles(room_collection):
|
||||||
|
async with db.transaction():
|
||||||
|
async for waddle in RoomWaddle.query.gino.iterate():
|
||||||
|
room_collection[waddle.room_id].waddles[waddle.id] = waddle
|
||||||
|
waddle.room = room_collection[waddle.room_id]
|
||||||
|
waddle.logic = WaddleLogicMapping[waddle.game]
|
||||||
|
|
||||||
|
|
||||||
@handlers.boot
|
@handlers.boot
|
||||||
async def rooms_load(server):
|
async def rooms_load(server):
|
||||||
server.rooms = await RoomCollection.get_collection()
|
server.rooms = await RoomCollection.get_collection()
|
||||||
await server.rooms.setup_tables()
|
await setup_tables(server.rooms)
|
||||||
await server.rooms.setup_waddles()
|
await setup_waddles(server.rooms)
|
||||||
server.logger.info(f'Loaded {len(server.rooms)} rooms ({len(server.rooms.spawn_rooms)} spawn)')
|
server.logger.info(f'Loaded {len(server.rooms)} rooms ({len(server.rooms.spawn_rooms)} spawn)')
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user