#!/usr/bin/env python # coding: utf-8 """ Server part of the connect4 plugin for chatwisted """ from chatwisted.server import GroupPlugin class Grid(object): """ Represents a (connect4-)grid You can put chips (as strings) into a number of cols and they will batch """ height = 7 width = 6 row_length = 4 def __init__(self): """ Define a internal list in right size to simulate the grid """ self._list = [None for dummy in xrange(self.height * self.width)] def put(self, col, item): """ Put a chip `item` into a `col` """ row = 0 while row < self.height and self.get(col, row) is None: row += 1 row -= 1 self._list[row * self.width+col] = item return row def get(self, col, row): """ return item at (col|row) """ return self._list[row * self.width + col] def count_row(self, col, row, direction, item): """ Calculate the length of a row from a given position in a given direction recursively """ if self.get(col, row) == item: return self.count_row(col+direction[0], row+direction[1], direction, item) + 1 else: return 1 def search_row(self, col, row): """ Check whether the chip at (row|col) is part of a row (that is long enough to win) """ dirs = [(-1, 1), (0, -1), (1, -1), (1, 0)] item = self.get(col, row) for x_dir, y_dir in dirs: part1 = self.count_row(col, row, (x_dir, y_dir), item) part2 = self.count_row(col, row, (-x_dir, -y_dir), item) if part1 + part2 - 1 >= self.row_length: print "win" def __str__(self): """ Print the grid in a (human) readable way :rtype: string """ out = "|" col = 0 for value in self._list: col += 1 out += {None:"_", 0:"O", 1:"X"}[value] if col >= self.width: out += "|\n|" col = 0 return out[:-1] class Connect4Plugin(GroupPlugin): """ Connect4Plugin Simple game PluginGroup as an example for a game server part. """ name = "connect4" max_members = 2 def __init__(self, factory, name, admin, *args): """ Connect4Plugin constructor Create a grid and define some variables. """ GroupPlugin.__init__(self, factory, name, admin, *args) #super(GroupPlugin).__init__(self, factory, name, admin, *args) self.players = [] self.grid = Grid() # index of player who has a turn (-1 = game not running) self.cur_player = -1 def cmd_leave(self, client): """ When a client leaves, check whether the game can continue """ GroupPlugin.cmd_leave(self, client) if len(self.members) < 2: #self.quit_game() self.grid = Grid() def cmd_start(self, client): """ Start a game. """ if len(self.members) >1: self.players = self.members.values()[:2] self.cur_player = 0 self.send_cmd("all", "write", "GAME STARTED") self.send_cmd("all", "write", "") self.next() else: self.send_cmd(client, "write", "you need a partner") def next(self): """ Finnish this round and tell the players the current field and who's next. """ if self.cur_player != -1: self.send_cmd("all", "field", str(self.grid).replace("\n", "-")) self.send_cmd("all", "write", "Your turn, %s!" % self.players[self.cur_player].name) def cmd_put(self, client, col): """ `client` wants to put a chip into `col` """ err = "" if client == self.players[self.cur_player]: try: col = int(col) except ValueError: err = "argument must be an integer, not %s" % col if 0 <= col < self.grid.width: self.grid.put(col, self.cur_player) self.send_cmd("all", "write", "%s puts a chip into col %i" % (client.name, col)) self.cur_player = [1, 0][self.cur_player] self.next() else: err = "not your turn!" if err: self.send_cmd(client, "error", err)