# IRC Teams (#221)

**URL:** <https://www.ruby-forum.com/t/irc-teams-221/177415>\
**Category:** Ruby\
**Created:** [October 16, 2009, 6:34pm UTC](https://www.ruby-forum.com/t/irc-teams-221/177415 "2009-10-16T18:34:45Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [October 16, 2009, 6:34pm UTC](https://www.ruby-forum.com/t/irc-teams-221/177415/1 "2009-10-16T18:34:45Z")

</div>

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Q.:

1. Please do not post any solutions or spoiler discussion for this  
quiz until 48 hours have elapsed from the time this message was  
sent.

2. Support Ruby Q. by submitting ideas and responses  
as often as you can.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem  
helps everyone on Ruby T. follow the discussion. Please reply to  
the original quiz message, if you can.

* * *

RSS Feed: [http://rubyquiz.strd6.com/quizzes.rss](http://rubyquiz.strd6.com/quizzes.rss)

Suggestions?: [http://rubyquiz.strd6.com/suggestions](http://rubyquiz.strd6.com/suggestions)

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## IRC Teams (#221)

Tashi dele Rubyists,

This week’s quiz was suggested by [Martin DeMello](http://zem.novylen.net)

A common feature in IRC-based games is the ability to create and join  
teams. The game bot sits in the channel and watches for messages in a  
certain format, which it interprets as commands. Write a small gamebot  
that accepts the following commands:

create team   
join   
leave team  
show teams  
show team   
show my team  
delete team   
reset

Here’s a typical transcript

create team ruby  
 - created team ruby -  
 create team python  
 - created team python -  
 show teams  
 teams: ruby, python  
 show team ruby  
 team ruby: foo  
 show my team  
 bar is in team python  
 join ruby  
 baz is now in team ruby  
 show team ruby  
 team ruby: foo, baz

Think up some useful extensions, such as the ability to join a user  
rather than a team, and restricting some commands like reset to ops.  
There are plenty of IRC bot libraries out there, go explore! If one  
already does team formation, that’s cheating, though 🙂

Have fun!

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [October 19, 2009, 1:44pm UTC](https://www.ruby-forum.com/t/irc-teams-221/177415/2 "2009-10-19T13:44:40Z")

</div>

The main idea behind this quiz was to show how easy it is to get an  
irc bot up and running in ruby, especially given the number of bot  
frameworks out there. I chose to base my bot on rif  
[[http://gitorious.org/ruby-irc](http://gitorious.org/ruby-irc)], a nice lightweight library with  
everything I needed to get started immediately.

The code consists of a Teams class, which does all the actual work of  
maintaining teams, and a TeamBot, which inherits from RIF::Bot and  
handles the IRC part of it. For the sake of simplicity, the bot  
frontend does no real validation; it just unpacks an incoming message  
into a command and arguments, and blindly sends those arguments to the  
Teams object. All public methods on the Teams object accept a player  
name as a first argument, whether they need it or not, and return  
either a string or an array of strings, or raise an exception. The bot  
sends the return value to the channel; an array is sent one message at  
a time.

* * *

gem ‘rif’  
require ‘rif/bot’

class TeambotError \< Exception  
end

def TeambotError(foo)  
TeambotError.new(foo)  
end

class Teams  
attr\_accessor :teams, :members

def initialize  
@teams = {}  
@members = {}  
end

def create(player, team)  
raise TeambotError(“team #{team} already created”) if teams[team]  
teams[team] = true  
“created team #{team}”  
end

def delete(player, team)  
teams.delete(team)  
members.delete\_if {|k,v| v == team}  
“deleted team #{team}”  
end

def join(player, team)  
raise TeambotError(“no such team: #{team}”) if not teams[team]  
members[player] = team  
“#{player} has joined team #{team}”  
end

def leave(player, \*args)  
team = members.delete(player)  
“#{player} has left team #{team}”  
end

def reset(\*args)  
@members = {}  
@teams = {}  
“deleted all teams”  
end

def show(player, \*args)  
if args[0] == ‘my’  
members[player]  
elsif args[0] == ‘teams’  
teams.map {|team, \_| “#{team}: #{show\_players(team)}”}  
elsif args[0] == ‘team’  
show\_players(team)  
end  
end

private  
def players(team)  
members.select {|k,v| v == team}.keys  
end

def show\_players(team)  
players(team).join(" ")  
end  
end

class TeamBot \< RIF::Bot  
attr\_reader :teams, :channel  
def initialize(channel, nick, server, port, username)  
@teams = Teams.new  
@channel = channel  
super(nick, server, port, username)  
end

def on\_endofmotd(event)  
join(channel)  
end

def on\_message(event)  
return unless event.channel == channel  
msg, \*args = event.message.split(" ")  
player = event.nick  
begin  
\*ret = teams.send(msg, player, \*args)  
rescue NameError  
ret = nil  
rescue TeambotError =\> e  
ret = [e.message]  
end  
ret.each {|m| send\_message(channel, m)} if ret  
end  
end

if **FILE** == $0  
channel = “##{ARGV[0]}”  
bot = TeamBot.new(channel, “teambot”, “[irc.freenode.net](http://irc.freenode.net)”, 6667, “RIF  
Bot”)  
bot.connect  
end

martin

---

<div class="post-metadata">

**Author:** ![danmcb](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/13edae/32.png) [@danmcb](https://www.ruby-forum.com/u/danmcb)\
**Post date:** [November 1, 2009, 12:42am UTC](https://www.ruby-forum.com/t/irc-teams-221/177415/3 "2009-11-01T00:42:20Z")

</div>

This week’s quiz was solved by Martin DeMello.

Martin uses the [rif gem](http://gitorious.org/ruby-irc) to handle the nitty gritty details of  
IRC, like establishing a connection and sending and receiving  
messages.

The `TeamBot#on_message` method receives the messages from the users  
and dispatches them to an instance of the Teams class. This is  
accomplished by simply splitting the the message that was sent and  
using the first part as the method to invoke. The first argument is  
always the player, which is taken from the message event’s `nick`  
field. The rest of the message, if any, is passed as the remaining  
arguments.

Let’s look at a full pass through of the following sample message from  
user Bob:

```
<Bob> create ruby

```

This will land in the bot’s `on_message` method. The `event` will have  
“Bob” as the nick and “create ruby” as the message. That is parsed  
into the method to call and the arguments like so:

```
msg, *args = event.message.split(" ")

```

The `teams` object is then sent the parsed message arguments with the  
specified method as follows:

```
*ret = teams.send(msg, player, *args)

```

This takes us into the create method and the team is created (if all  
goes according to plan):

```
def create(player, team)
  raise TeambotError("team #{team} already created") if teams[team]
  teams[team] = true
  "created team #{team}"
end

```

The other actions that users may wish to perform are taken care of in  
the same way. This simple and flexible solution allows for easy  
modification and extension.

Thank you Martin for your solution (and also for the quiz suggestion)!

[IRC Teams (#221) - Solutions](http://rubyquiz.strd6.com/quizzes/221.tar.gz)
