Untitled
unknown
plain_text
2 years ago
20 kB
5
Indexable
#Known bugs: #After first round of playing, some of the shapes will always start higher #ROTATING SHAPE WHEN AT TOP OF GAME BOARD #ROTATING SHAPES TOO QUICK MAKES THEM DO WALL BOUNCE #PRESSING DOWN AND LEFT/RIGHT AT SAME TIME DOESNT MOVE IT LEFT/RIGHT import discord from discord.ext import commands import random import asyncio board = [] num_of_rows = 18 num_of_cols = 10 empty_square = ':black_large_square:' blue_square = ':blue_square:' brown_square = ':brown_square:' orange_square = ':orange_square:' yellow_square = ':yellow_square:' green_square = ':green_square:' purple_square = ':purple_square:' red_square = ':red_square:' embed_colour = 0x077ff7 #colour of line on embeds points = 0 lines = 0 #how many lines cleared down_pressed = False #if down button has been pressed rotate_clockwise = False rotation_pos = 0 h_movement = 0 #amount to move left or right is_new_shape = False start_higher = False #for when near top of board game_over = False index = 0 class Tetronimo: #Tetris pieces def __init__(self, starting_pos, colour, rotation_points): self.starting_pos = starting_pos #list self.colour = colour self.rotation_points = rotation_points #list main_wall_kicks = [ #for J, L, T, S, Z tetronimos [[0, 0], [0, -1], [-1, -1], [2, 0], [2, -1]], [[0, 0], [0, 1], [1, 1], [-2, 0], [-2, 1]], [[0, 0], [0, 1], [-1, 1], [2, 0], [2, 1]], [[0, 0], [0, -1], [1, -1], [-2, 0], [-2, -1]] ] i_wall_kicks = [ #for I tetronimo [[0, 0], [0, -2], [0, 1], [1, -2], [-2, 1]], [[0, 0], [0, -1], [0, 2], [-2, -1], [1, 2]], [[0, 0], [0, 2], [0, -1], [-1, 2], [2, -1]], [[0, 0], [0, 1], [0, -2], [2, 1], [-1, -2]] ] rot_adjustments = { #to move when rotations are slightly off #blue: not sure if needs any rn ':blue_square:': [[0, 1], [-1, -1], [0, 0], [-1, 0]], #[[0, 0], [0, 0], [0, 0], [0, 0]] #brown: left 1, right 1, right 1, left 1, ':brown_square:': [[0, 0], [0, 1], [0, 0], [0, -1]], #[[0, -1], [0, 1], [0, 1], [0, -1]]' #orange: left 1, nothing, right 1, nothing ':orange_square:': [[0, -1], [0, 0], [-1, 1], [0, 0]], #[[0, -1], [0, 0], [0, 1], [0, 0]] #none for yellow ':yellow_square:': [[0, 0], [0, 0], [0, 0], [0, 0]], #green: right 1, nothing, right 1, nothing ':green_square:': [[0, 0], [0, 0], [0, 0], [0, 0]], #[[0, 1], [0, 0], [0, 1], [0, 0]] #purple: nothing, right 1, left 1 (possibly up too), right 1 ':purple_square:': [[0, 0], [1, 1], [0, -1], [0, 1]], #[[0, 0], [0, 1], [0, -1], [0, 1]] #red: left 1, up 1, right 1, up 1 ':red_square:': [[1, -1], [-1, -1], [0, 2], [-1, -1]] #[[0, -1], [-1, 0], [0, 1], [-1, 0]] } #starting spots, right above the board ready to be lowered. Col is 3/4 to start in middle shape_I = Tetronimo([[0, 3], [0, 4], [0, 5], [0, 6]], blue_square, [1, 1, 1, 1]) shape_J = Tetronimo([[0, 3], [0, 4], [0, 5], [-1, 3]], brown_square, [1, 1, 2, 2]) shape_L = Tetronimo([[0, 3], [0, 4], [0, 5], [-1, 5]], orange_square, [1, 2, 2, 1]) shape_O = Tetronimo([[0, 4], [0, 5], [-1, 4], [-1, 5]], yellow_square, [1, 1, 1, 1]) shape_S = Tetronimo([[0, 3], [0, 4], [-1, 4], [-1, 5]], green_square, [2, 2, 2, 2]) shape_T = Tetronimo([[0, 3], [0, 4], [0, 5], [-1, 4]], purple_square, [1, 1, 3, 0]) shape_Z = Tetronimo([[0, 4], [0, 5], [-1, 3], [-1, 4]], red_square, [0, 1, 0, 2]) #fill board with empty squares def make_empty_board(): for row in range(num_of_rows): board.append([]) for col in range(num_of_cols): board[row].append(empty_square) def fill_board(emoji): for row in range(num_of_rows): for col in range(num_of_cols): if board[row][col] != emoji: board[row][col] = emoji def format_board_as_str(): board_as_str = '' for row in range(num_of_rows): for col in range(num_of_cols): board_as_str += (board[row][col]) # + " " possibly if col == num_of_cols - 1: board_as_str += "\n " return board_as_str def get_random_shape(): global index # ordered_shapes = [shape_J, shape_T, shape_L, shape_O, shape_S, shape_Z, shape_S, shape_T, shape_J, shape_Z, shape_S, shape_I, shape_Z, shape_O, shape_T, shape_J, shape_L, shape_Z, shape_I] # random_shape = ordered_shapes[index] shapes = [shape_I, shape_J, shape_L, shape_O, shape_S, shape_T, shape_Z] random_shape = shapes[random.randint(0, 6)] #0, 6 index += 1 if start_higher == True: for s in random_shape.starting_pos[:]: #for each square s[0] = s[0] - 1 #make row 1 above else: starting_pos = random_shape.starting_pos[:] random_shape = [random_shape.starting_pos[:], random_shape.colour, random_shape.rotation_points] #gets starting point of shapes and copies, doesn't change them global is_new_shape is_new_shape = True return random_shape #returns array with starting pos and colour def do_wall_kicks(shape, old_shape_pos, shape_colour, attempt_kick_num): new_shape_pos = [] if shape_colour == blue_square: kick_set = main_wall_kicks[rotation_pos] else: kick_set = i_wall_kicks[rotation_pos] print('Kick set: ' + str(kick_set)) for kick in kick_set: print('Kick: ' + str(kick)) for square in shape: square_row = square[0] square_col = square[1] new_square_row = square_row + kick[0] new_square_col = square_col + kick[1] if (0 <= new_square_col < num_of_cols) and (0 <= new_square_row < num_of_rows): #if square checking is on board square_checking = board[new_square_row][new_square_col] #get the square to check if empty if (square_checking != empty_square) and ([new_square_row, new_square_col] not in old_shape_pos): #if square is not empty / won't be when other parts of shape have moved #shape doesn't fit new_shape_pos = [] #reset new_shape break else: #shape does fit new_shape_pos.append([new_square_row, new_square_col]) #store pos print('New shape: ' + str(new_shape_pos)) if len(new_shape_pos) == 4: print('Returned new shape after doing kicks') return new_shape_pos #return shape with kicks added else: #shape doesn't fit new_shape_pos = [] #reset new_shape break print('Returned old, unrotated shape') return old_shape_pos #return shape without rotation def rotate_shape(shape, direction, rotation_point_index, shape_colour): rotation_point = shape[rotation_point_index] #coords of rotation point new_shape = [] #to store coords of rotated shape #Rotate shape for square in shape: square_row = square[0] square_col = square[1] if direction == 'clockwise': new_square_row = (square_col - rotation_point[1]) + rotation_point[0] + rot_adjustments.get(shape_colour)[rotation_pos-1][0] print('Adjustment made: ' + str(rot_adjustments.get(shape_colour)[rotation_pos-1][0])) new_square_col = -(square_row - rotation_point[0]) + rotation_point[1] + rot_adjustments.get(shape_colour)[rotation_pos-1][1] print('Adjustment made: ' + str(rot_adjustments.get(shape_colour)[rotation_pos-1][1])) elif direction == 'anticlockwise': #currently not a thing new_square_row = -(square_col - rotation_point[1]) + rotation_point[0] new_square_col = (square_row - rotation_point[0]) + rotation_point[1] new_shape.append([new_square_row, new_square_col]) #store pos of rotated square if (0 <= square_col < num_of_cols) and (0 <= square_row < num_of_rows): #if on board board[square_row][square_col] = empty_square #make empty old square pos new_shape = do_wall_kicks(new_shape, shape, shape_colour, 0) #offset shape new_shape = sorted(new_shape, key=lambda l:l[0], reverse=True) #sort so that bottom squares are first in list print('Rotated shape: ' + str(new_shape)) #Place rotated shape (in case can't move down) if new_shape != shape: #if not same as old unrotated shape (in case places at start pos) for square in new_shape: square_row = square[0] square_col = square[1] board[square_row][square_col] = shape_colour return new_shape def clear_lines(): global board global points global lines lines_to_clear = 0 for row in range(num_of_rows): row_full = True #assume line is full for col in range(num_of_cols): if board[row][col] == empty_square: row_full = False break #don't clear this row if row_full: #if line to clear lines_to_clear += 1 #bring all lines above down board2 = board[:] #clone board for r in range(row, 0, -1): #for every row above row if r == 0: #if top row for c in range(num_of_cols): board2[r][c] = empty_square #make each spot empty else: for c in range(num_of_cols): board2[r][c] = board[r - 1][c] #make each spot the one above board = board2[:] if lines_to_clear == 1: points += 100 lines += 1 elif lines_to_clear == 2: points += 300 lines += 2 elif lines_to_clear == 3: points += 500 lines += 3 elif lines_to_clear == 4: points += 800 lines += 4 def get_next_pos(cur_shape_pos): global h_movement global start_higher global game_over #Check if new pos for whole shape is available movement_amnt = 1 if down_pressed == False: amnt_to_check = 1 #check space one below else: amnt_to_check = num_of_rows #check all rows until furthest available space for i in range(amnt_to_check): square_num_in_shape = -1 for square in cur_shape_pos: next_space_free = True square_num_in_shape += 1 square_row = square[0] square_col = square[1] if (0 <= square_col < num_of_cols): #if current column spot will fit if not (0 <= square_col + h_movement < num_of_cols): #if spot with column position changed won't fit h_movement = 0 #just change row position if (0 <= square_row + movement_amnt < num_of_rows): #if new square row pos is on board square_checking = board[square_row + movement_amnt][square_col + h_movement] #get the square to check if empty if (square_checking != empty_square) and ([square_row + movement_amnt, square_col + h_movement] not in cur_shape_pos): #if square is not empty / won't be when other parts of shape have moved #check if space free if not moving horizontally (in case going into wall) but still going down h_movement = 0 square_checking = board[square_row + movement_amnt][square_col + h_movement] if (square_checking != empty_square) and ([square_row + movement_amnt, square_col + h_movement] not in cur_shape_pos): if movement_amnt == 1: next_space_free = False #can't put shape there print('Detected a space that isnt free') print('Square checking: ' + str(square_row + movement_amnt) + ', ' + str(square_col + h_movement)) if is_new_shape: #if can't place new shape if start_higher == True: game_over = True else: start_higher = True elif movement_amnt > 1: #if sending down movement_amnt -= 1 #accomodate for extra 1 added to check if its free return [movement_amnt, next_space_free] #stop checking elif down_pressed == True: if square_num_in_shape == 3: #only on last square in shape movement_amnt += 1 #increase amount to move shape by elif square_row + movement_amnt >= num_of_rows: #new square row isn't on board if movement_amnt == 1: next_space_free = False #can't put shape there print('Detected a space that isnt free') elif movement_amnt > 1: #if sending down movement_amnt -= 1 #accomodate for extra 1 added to check if its free return [movement_amnt, next_space_free] #stop checking elif down_pressed == True: if square_num_in_shape == 3: #only on last square in shape movement_amnt += 1 #increase amount to move shape by return [movement_amnt, next_space_free] async def run_game(msg, cur_shape): global is_new_shape global h_movement global rotate_clockwise global rotation_pos cur_shape_pos = cur_shape[0] cur_shape_colour = cur_shape[1] if rotate_clockwise == True and cur_shape_colour != yellow_square: cur_shape_pos = rotate_shape(cur_shape_pos, 'clockwise', cur_shape[2][rotation_pos], cur_shape_colour) #rotate shape cur_shape = [cur_shape_pos, cur_shape_colour, cur_shape[2]] #update shape next_pos = get_next_pos(cur_shape_pos)[:] movement_amnt = next_pos[0] next_space_free = next_pos[1] #move/place shape if pos is available square_num_in_shape = -1 if next_space_free: for square in cur_shape_pos: square_num_in_shape += 1 square_row = square[0] square_col = square[1] if (0 <= square_row + movement_amnt < num_of_rows): #if new square row pos is on board square_changing = board[square_row + movement_amnt][square_col + h_movement] #get square to change board[square_row + movement_amnt][square_col + h_movement] = cur_shape_colour #changes square colour to colour of shape if is_new_shape == True: is_new_shape = False #has been placed, so not new anymore if square_row > -1: #stops from wrapping around list and changing colour of bottom rows. board[square_row][square_col] = empty_square #make old square empty again cur_shape_pos[square_num_in_shape] = [square_row + movement_amnt, square_col + h_movement] #store new pos of shape square else: #if new square row pos is not on board cur_shape_pos[square_num_in_shape] = [square_row + movement_amnt, square_col + h_movement] #store new pos of shape square else: global down_pressed down_pressed = False #reset it clear_lines() #check for full lines and clear them cur_shape = get_random_shape() #change shape rotation_pos = 0 #reset rotation print('Changed shape.') if not game_over: #Update board embed = discord.Embed(description=format_board_as_str(), color=embed_colour) h_movement = 0 #reset horizontal movement rotate_clockwise = False #reset clockwise rotation await msg.edit(embed=embed) if not is_new_shape: await asyncio.sleep(1) #to keep under api rate limit await run_game(msg, cur_shape) else: print('GAME OVER') desc = 'Score: {} \n Lines: {} \n \n Press ▶ to play again.'.format(points, lines) embed = discord.Embed(title='GAME OVER', description=desc, color=embed_colour) await msg.edit(embed=embed) await msg.remove_reaction("⬅", client.user) #Left await msg.remove_reaction("⬇", client.user) #Down await msg.remove_reaction("➡", client.user) #Right await msg.remove_reaction("🔃", client.user) #Rotate await msg.add_reaction("▶") #Play async def reset_game(): global down_pressed global rotate_clockwise global rotation_pos global h_movement global is_new_shape global start_higher global game_over global points global lines fill_board(empty_square) down_pressed = False rotate_clockwise = False rotation_pos = 0 h_movement = 0 #amount to move left or right is_new_shape = False start_higher = False game_over = False next_space_free = True points = 0 lines = 0 make_empty_board() #------------------------------------------------------------------------------- client = commands.Bot(command_prefix = 't!') @client.event async def on_ready(): print("tetris bot started poggies") @client.command() async def test(ctx): await ctx.send('test working poggies pogchamp') @client.command() async def start(ctx): #Starts embed await reset_game() embed = discord.Embed(title='Tetris in Discord', description=format_board_as_str(), color=embed_colour) embed.add_field(name='How to Play:', value='Use ⬅ ⬇ ➡ to move left, down, and right respectively. \n \n Use 🔃 to rotate the shape clockwise. \n \n Press ▶ to Play.', inline=False) msg = await ctx.send(embed=embed) #Add button choices / reactions await msg.add_reaction("▶") #Play #On new reaction: #Update board and board_as_str #await msg.edit(embed=embed) @client.event async def on_reaction_add(reaction, user): global h_movement global rotation_pos if user != client.user: msg = reaction.message if str(reaction.emoji) == "▶": # Play button pressed print('User pressed play') await reset_game() await msg.remove_reaction("❌", client.user) # Remove delete embed = discord.Embed(description=format_board_as_str(), color=embed_colour) await msg.remove_reaction("▶", user) await msg.remove_reaction("▶", client.user) await msg.edit(embed=embed) await msg.add_reaction("⬅") # Left await msg.add_reaction("⬇") # Down await msg.add_reaction("➡") # Right await msg.add_reaction("🔃") # Rotate await msg.add_reaction("❌") # Stop game starting_shape = get_random_shape() await run_game(msg, starting_shape) if str(reaction.emoji) == "⬅": # Left button pressed print('Left button pressed') h_movement = -1 # move 1 left await msg.remove_reaction("⬅", user) if str(reaction.emoji) == "➡": # Right button pressed print('Right button pressed') h_movement = 1 # move +1 right await msg.remove_reaction("➡", user) if str(reaction.emoji) == "⬇": # Down button pressed print('Down button pressed') global down_pressed down_pressed = True await msg.remove_reaction("⬇", user) if str(reaction.emoji) == "🔃": # Rotate clockwise button pressed print('Rotate clockwise button pressed') global rotate_clockwise rotate_clockwise = True if rotation_pos < 3: rotation_pos += 1 else: rotation_pos = 0 # go back to the original position await msg.remove_reaction("🔃", user) if str(reaction.emoji) == "❌": # Stop game button pressed if user == client.user: # Check if the bot itself reacted with "❌" await reset_game() await msg.delete() if str(reaction.emoji) == "🔴": await message.edit(content="") client.run('Your token here')
Editor is loading...