Advertisement
Guest User

Untitled

a guest
Aug 19th, 2017
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.61 KB | None | 0 0
  1. """Connect Four
  2. Written for Python 3.6 and discord.py 1.0.0a"""
  3.  
  4. import discord
  5. from discord.ext import commands
  6. from .utils import checks
  7.  
  8.  
  9. class Session:
  10. """Active Session of Connect Four"""
  11. def __init__(self, p1, p2, chan):
  12. self.p1 = p1 # These will be discord.Member objects of players
  13. self.p2 = p2 # `p1` being ctx.author and `p2 being the ping
  14. self.chan = chan
  15. self.board = [[0 for x in range(7)] for y in range(7)]
  16. self.turn = 0
  17. self.msg = None
  18. self.emojis = {
  19. 0: "⚪", # :white_circle:
  20. self.p1.id: "🔴", # :red_circle:
  21. self.p2.id: "🔵", # :large_blue_circle:
  22. }
  23.  
  24. @property
  25. def current_player(self):
  26. if self.turn % 2 == 1:
  27. return self.p1
  28. else:
  29. return self.p2
  30.  
  31. @property
  32. def current_player_chip(self):
  33. return self.player_chip(self.current_player)
  34.  
  35. def player_chip(self, player: discord.Member):
  36. return self.emojis.get(player.id, 0)
  37.  
  38. @property
  39. def color(self):
  40. name = self.current_player.default_avatar.name
  41. if name == "grey":
  42. name = "light_grey"
  43. return getattr(discord.Colour, name)()
  44.  
  45. def play(self, player, row):
  46. self.board[row][self.board[row][-1]] = player
  47. self.board[row][-1] += 1
  48. self.turn += 1
  49. return self.check([self.board[x][:-1] for x in range(7)])
  50.  
  51. @property
  52. def get_board(self):
  53. board = []
  54. for row in self.board:
  55. board.append([self.emojis[i] for i in row[:-1]][::-1])
  56.  
  57. return board
  58.  
  59. def check(self, board):
  60. for x in range(7):
  61. for y in range(3):
  62. if board[x][y] != 0 and \
  63. board[x][y] == board[x][y + 1] and \
  64. board[x][y] == board[x][y + 2] and \
  65. board[x][y] == board[x][y + 3]:
  66. return self.p1 if board[x][y] == self.p1.id else self.p2
  67.  
  68. for x in range(4):
  69. for y in range(6):
  70. if board[x][y] != 0 and \
  71. board[x][y] == board[x + 1][y] and \
  72. board[x][y] == board[x + 2][y] and \
  73. board[x][y] == board[x + 3][y]:
  74. return self.p1 if board[x][y] == self.p1.id else self.p2
  75.  
  76. for x in range(4):
  77. for y in range(3):
  78. if board[x][y] != 0 and \
  79. board[x][y] == board[x + 1][y + 1] and \
  80. board[x][y] == board[x + 2][y + 2] and \
  81. board[x][y] == board[x + 3][y + 3]:
  82. return self.p1 if board[x][y] == self.p1.id else self.p2
  83.  
  84. for x in range(3, 7):
  85. for y in range(3):
  86. if board[x][y] != 0 and \
  87. board[x][y] == board[x - 1][y + 1] and \
  88. board[x][y] == board[x - 2][y + 2] and \
  89. board[x][y] == board[x - 3][y + 3]:
  90. return self.p1 if board[x][y] == self.p1.id else self.p2
  91.  
  92. if all(map(lambda x: x == 6, [r[6] for r in self.board])):
  93. return "Draw"
  94.  
  95. return False
  96.  
  97.  
  98. class ConnectFour:
  99. """Play a game of Connect Four"""
  100. def __init__(self, bot):
  101. self.bot = bot
  102. self.sessions = {}
  103.  
  104. def session(self, ctx):
  105. return self.sessions.get(ctx.channel.id, None)
  106.  
  107. async def c4_error(self, ctx, msg="Error"):
  108. em = discord.Embed(description=f"⛔ {msg}", color=discord.Colour.red())
  109. await ctx.send(embed=em)
  110.  
  111. async def send_board(self, ctx, init=False, win=False):
  112. session = self.session(ctx)
  113. if session.msg is not None:
  114. try:
  115. await session.msg.delete()
  116. except Exception as e:
  117. await ctx.send(f"{type(e)}: {e}")
  118.  
  119. board = session.get_board
  120. parsed_board = "\n".join(["{}{}{}{}{}{}{}".format(*[board[y][x] for y in range(7)]) for x in range(6)])
  121.  
  122. if win:
  123. if win == "Draw":
  124. turn = f"Game ended in a Draw."
  125. else:
  126. turn = f"Game Over!\n{win.name} wins! 🎉"
  127. else:
  128. turn = "New game!" if init else f"Turn: {(session.turn + 2) // 2}"
  129.  
  130. em = discord.Embed(title=f"{session.player_chip(session.p1)}{session.p1.name} 🆚 "
  131. f"{session.p2.name}{session.player_chip(session.p2)}",
  132. description=f"{turn}\n\n:one::two::three::four::five::six::seven:\n{parsed_board}",
  133. color=session.color)
  134.  
  135. if win:
  136. self.sessions.pop(ctx.channel.id)
  137. await ctx.send(embed=em)
  138. else:
  139. em.set_footer(text=f"{session.current_player.name}'s turn: {session.current_player_chip}")
  140. session.msg = await ctx.send(embed=em)
  141.  
  142. await ctx.message.delete()
  143.  
  144. @commands.group()
  145. async def c4(self, ctx):
  146. """Connect Four
  147.  
  148. The classic game of Connect Four.
  149. Use these commands to play a game
  150. of Connect Four with another user.
  151. You can have multiple concurrent
  152. games, one per channel."""
  153. if not ctx.invoked_subcommand:
  154. await self.bot.formatter.format_help_for(ctx, ctx.command)
  155.  
  156. @c4.command(name="start", aliases=["play"])
  157. async def _start(self, ctx, *, user: discord.Member=None):
  158. """Star a game of Connect Four
  159.  
  160. `[p]c4 start @user` will start a game
  161. with that user in the current channel."""
  162. # if user:
  163. # await ctx.send(f"Ping! Confirmed user: {user.name} (Currently not implemented)")
  164. if user:
  165. session = self.session(ctx)
  166. if session:
  167. await self.c4_error(ctx, msg="There is already an active game in this channel.")
  168. else:
  169. self.sessions[ctx.channel.id] = Session(ctx.author, user, ctx.channel)
  170. await self.send_board(ctx)
  171. else:
  172. await self.bot.formatter.format_help_for(ctx, ctx.command, "You need another player to start.")
  173.  
  174. @c4.command(name="quit", aliases=["end"])
  175. async def _quit(self, ctx):
  176. """Quits an active game of Connect Four
  177.  
  178. `[p]c4 quit` can be used by either player
  179. to quit their game in the channel."""
  180. session = self.sessions.get(ctx.channel.id, None)
  181. if session and ctx.author in [session.p1, session.p2]:
  182. self.sessions.pop(ctx.channel.id)
  183. await ctx.send("Game has ended.")
  184. else:
  185. await self.c4_error(ctx, msg="No active game in this channel.")
  186.  
  187. @c4.command(name="board")
  188. async def board(self, ctx):
  189. """Resends the current board
  190.  
  191. Can be used if the board gets lost in the chat"""
  192. session = self.sessions.get(ctx.channel.id, None)
  193. if session and ctx.author in [session.p1, session.p2]:
  194. await self.send_board(ctx)
  195. else:
  196. await self.c4_error(ctx, msg="No active game in this channel.")
  197.  
  198. @checks.sudo()
  199. @c4.command(name="kill", aliases=["killall"])
  200. async def _kill(self, ctx):
  201. """Aministrative kill command
  202.  
  203. This will kill all running games of
  204. Connect Four in all channels."""
  205. em = discord.Embed(description=f"All running games have been terminated. (Total: {len(self.sessions.keys())})",
  206. color=discord.Colour.dark_grey())
  207. self.sessions = {}
  208. await ctx.send(embed=em)
  209.  
  210. @checks.sudo()
  211. @c4.command(name="games")
  212. async def games(self, ctx):
  213. em = discord.Embed(description=f"Total running games: {len(self.sessions.keys())}",
  214. color=discord.Colour.dark_grey())
  215. await ctx.send(embed=em)
  216.  
  217. @c4.command(name="move")
  218. async def _move(self, ctx, row: int):
  219. """Make a Move
  220.  
  221. `[p]c4 move <row>` will place a chip
  222. in that row. Only the current player
  223. can use this command."""
  224. row -= 1
  225. session = self.session(ctx)
  226. if session:
  227. if ctx.author == session.current_player:
  228. if row in range(7):
  229. if session.board[row][-1] < 6:
  230. check = session.play(ctx.author.id, row)
  231. await self.send_board(ctx, win=check)
  232. else:
  233. await self.c4_error(ctx, "That row is full. Select another.")
  234. else:
  235. await self.c4_error(ctx, "Invalid row number. Select another.")
  236. else:
  237. await self.c4_error(ctx, msg="No active game in this channel.")
  238.  
  239.  
  240. def setup(bot):
  241. bot.add_cog(ConnectFour(bot))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement