game stuff

This commit is contained in:
NikolajDanger
2021-09-30 14:05:50 +02:00
parent 5330a51fe0
commit cbf2ca765e
12 changed files with 538 additions and 551 deletions

View File

@ -22,12 +22,46 @@ create_actionrow)
from discord_slash.model import ButtonStyle
from gwendolyn.utils import encode_id
from .game_base import BoardGame
ROWCOUNT = 6
COLUMNCOUNT = 7
def _encode_board_string(board: list):
string = [str(i) for row in board for i in row]
class ConnectFour():
while len(string) > 0 and string[0] == "0":
string = string[1:]
if string == "":
string = "0"
dec = 0
for i, digit in enumerate(string[::-1]):
dec += (3**i)*int(digit)
return str(dec)
def _decode_board_string(board_string: str):
dec = int(board_string)
string = []
while dec:
string.append(str(dec % 3))
dec = dec // 3
while len(string) < ROWCOUNT * COLUMNCOUNT:
string.append("0")
string = string[::-1]
board = [
[int(x) for x in string[i*COLUMNCOUNT:i*COLUMNCOUNT+COLUMNCOUNT]]
for i in range(ROWCOUNT)]
return board
class ConnectFour(BoardGame):
"""
Deals with connect four commands and logic.
@ -41,8 +75,7 @@ class ConnectFour():
def __init__(self, bot):
"""Initialize the class."""
self.bot = bot
self.draw = DrawConnectFour(bot)
super().__init__(bot, "connectfour", DrawConnectFour(bot))
self.get_name = self.bot.database_funcs.get_name
# pylint: disable=invalid-name
self.AISCORES = {
@ -57,39 +90,6 @@ class ConnectFour():
}
# pylint: enable=invalid-name
def _encode_board_string(self, board: list):
string = [str(i) for row in board for i in row]
while len(string) > 0 and string[0] == "0":
string = string[1:]
if string == "":
string = "0"
dec = 0
for i, digit in enumerate(string[::-1]):
dec += (3**i)*int(digit)
return str(dec)
def _decode_board_string(self, board_string: str):
dec = int(board_string)
string = []
while dec:
string.append(str(dec % 3))
dec = dec // 3
while len(string) < ROWCOUNT * COLUMNCOUNT:
string.append("0")
string = string[::-1]
board = [
[int(x) for x in string[i*COLUMNCOUNT:i*COLUMNCOUNT+COLUMNCOUNT]]
for i in range(ROWCOUNT)]
return board
async def start(self, ctx: SlashContext,
opponent: Union[int, discord.User]):
"""
@ -106,128 +106,90 @@ class ConnectFour():
searches when minimaxing.
"""
await self.bot.defer(ctx)
user = ctx.author.id
channel = str(ctx.channel_id)
started_game = False
can_start = True
opponent_info = self._test_opponent(ctx, opponent)
if not opponent_info:
return
if isinstance(opponent, int):
# Opponent is Gwendolyn
if opponent in range(1, 6):
difficulty = int(opponent)
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
send_message = "Difficulty doesn't exist"
log_message = "They challenged a difficulty that doesn't exist"
can_start = False
elif isinstance(opponent, discord.User):
if opponent.bot:
# User has challenged a bot
if opponent == self.bot.user:
# It was Gwendolyn
difficulty = 3
difficulty_text = f" with difficulty {difficulty}"
opponent = self.bot.user.id
else:
send_message = "You can't challenge a bot!"
log_message = "They tried to challenge a bot"
can_start = False
else:
# Opponent is another player
if ctx.author != opponent:
opponent = opponent.id
difficulty = 5
difficulty_text = ""
else:
send_message = "You can't play against yourself"
log_message = "They tried to play against themself"
can_start = False
difficulty = opponent_info[0]
difficulty_text = opponent_info[1]
if can_start:
board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)]
players = [user, opponent]
random.shuffle(players)
board = [[0 for _ in range(COLUMNCOUNT)] for _ in range(ROWCOUNT)]
players = [ctx.author.id, opponent]
random.shuffle(players)
self.draw.draw_image(channel, board, 0, [0,0], "", players)
self.draw.draw_image(channel, board, players, [0, [0,0], ""], players)
gwendolyn_turn = (players[0] == self.bot.user.id)
started_game = True
opponent_name = self.get_name(f"#{opponent}")
turn_name = self.get_name(f"#{players[0]}")
opponent_name = self.get_name(f"#{opponent}")
turn_name = self.get_name(f"#{players[0]}")
started_text = "Started game against {}{}.".format(
opponent_name,
difficulty_text
)
turn_text = f"It's {turn_name}'s turn"
send_message = f"{started_text} {turn_text}"
log_message = "They started a game"
self.bot.log(log_message)
await ctx.send(send_message)
started_text = "Started game against {}{}.".format(
opponent_name,
difficulty_text
)
turn_text = f"It's {turn_name}'s turn"
await ctx.send(f"{started_text} {turn_text}")
self.bot.log("They started a game")
# Sets the whole game in motion
if started_game:
boards_path = "gwendolyn/resources/games/connect_four_boards/"
file_path = f"{boards_path}board{ctx.channel_id}.png"
image_message = await ctx.send(file=discord.File(file_path))
board_string = self._encode_board_string(board)
if gwendolyn_turn:
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
)
else:
buttons = []
for i in range(7):
custom_id = encode_id(
[
"connectfour",
"place",
str(players[0]),
board_string,
str(i),
str(players[0]),
str(players[1]),
str(difficulty),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.blue,
label=str(i+1),
custom_id=custom_id,
disabled=(board[0][i] != 0)
))
boards_path = "gwendolyn/resources/games/connect_four_boards/"
file_path = f"{boards_path}board{ctx.channel_id}.png"
image_message = await ctx.send(file=discord.File(file_path))
board_string = _encode_board_string(board)
if (players[0] == self.bot.user.id):
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
)
else:
buttons = []
for i in range(7):
custom_id = encode_id(
[
"connectfour",
"end",
"place",
str(players[0]),
board_string,
str(i),
str(players[0]),
str(players[1]),
str(difficulty),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.red,
label="Surrender",
custom_id=custom_id
style=ButtonStyle.blue,
label=str(i+1),
custom_id=custom_id,
disabled=(board[0][i] != 0)
))
action_rows = []
for x in range(((len(buttons)-1)//4)+1):
row_buttons = buttons[
(x*4):(min(len(buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
custom_id = encode_id(
[
"connectfour",
"end",
str(players[0]),
str(players[1]),
str(image_message.id)
]
)
buttons.append(create_button(
style=ButtonStyle.red,
label="Surrender",
custom_id=custom_id
))
await image_message.edit(
components=action_rows
)
action_rows = []
for x in range(((len(buttons)-1)//4)+1):
row_buttons = buttons[
(x*4):(min(len(buttons),x*4+4))
]
action_rows.append(create_actionrow(*row_buttons))
await image_message.edit(
components=action_rows
)
async def place_piece(self, ctx: ComponentContext, board_string: str,
column: int, players: list[int], difficulty: int,
@ -246,7 +208,7 @@ class ConnectFour():
user_name = self.get_name(f"#{placer}")
placed_piece = False
board = self._decode_board_string(board_string)
board = _decode_board_string(board_string)
board = self._place_on_board(board, player_number, column)
if board is None:
@ -300,7 +262,7 @@ class ConnectFour():
if game_won:
self._end_game(winner, players, difficulty)
else:
board_string = self._encode_board_string(board)
board_string = _encode_board_string(board)
if gwendolyn_turn:
await self._connect_four_ai(
ctx, board_string, players, difficulty, image_message.id
@ -513,7 +475,7 @@ class ConnectFour():
self.bot.log("Figuring out best move")
board = self._decode_board_string(board_string)
board = _decode_board_string(board_string)
player = players.index(self.bot.user.id)+1
scores = [-math.inf for _ in range(COLUMNCOUNT)]
@ -797,8 +759,8 @@ class DrawConnectFour():
# pylint: enable=invalid-name
# Draws the whole thing
def draw_image(self, channel: str, board: list, winner: int,
win_coordinates: list, win_direction: str, players: list):
def draw_image(self, channel: str, board: list, players: list,
win_info: list):
"""
Draw an image of the connect four board.
@ -815,8 +777,8 @@ class DrawConnectFour():
self._draw_pieces(drawer, board)
if winner != 0:
self._draw_win(background, win_coordinates, win_direction)
if win_info[0] != 0:
self._draw_win(background, win_info[1], win_info[2])
self._draw_footer(drawer, players)