# Make a simple IRC bot.

Make a simple IRC bot which does simple task like greeting user.

## Detail

(You may see this RFC document.)

Write a complete program that perform these:

1. The program inputs nickname and realname from the user.

• All nickname and realname which form is [A-Za-z0-9]+ should be allowed, but it isn't important whether other forms are allowed. For example, if the user wants 1234qwerty as nickname and 5319009 as realname, the program should use those names, but it isn't important whether the program can use ^^☆Rick Astley☆^^ (which includes non-alphabet&decimals) as (nickname or realname) or not, even thought this name may be rejected by the server.
2. The program inputs serverAddress from the user.

• The form of serverAddress is serverIP:serverPort, where serverIP is the IP address of the server and serverPort is the port num of the server.
3. The program connects to port serverPort at IRC server serverIP, and it should set it's nickname as nickname and realname as realname by sending USER realname 0 * :realname and NICK nickname.

4. The program inputs a single channelName which doesn't include #, and join to the channel #channelName.

5. Send a private message Hello, world! to the #channelName channel like this: PRIVMSG #channelName :Hello, world!

6. Then, the program does these:

A. If someone joins, greeting him by saying Hello, @! to #channelName, where @ is the nickname of him/her.

B. If the program is kicked, try re-joining.

C. If a person is kicked or banned, say POW HAHA.

D. If a person leaves (PART or QUIT), say Goodbye, @!, where @ is the nickname of him/her.

E. If someone says some text including Turing test or turing test, say I'm a human!.

F. If someone says some text including 6*9, quit by sending QUIT :42 to the server.

G. If someone says some text including all your base are belong to us(case-insensitive), quit by sending QUIT :What you say! to the server.

H. If someone says some text preceding with a space and above acts aren't performed by the text, say the sum of charcode of all (except the first space) chars in the text.

## If an error is occurred

If an error (such as connection error or invalid nickname) is occurred, you can do what you want to do. For example, if the nickname is already in use, the program may stop, gets a new nickname from the user, or automatically change the nickname and retry.

## Restriction

The program

• Should not use any internal functions or libraries which is for IRC client/bot making. i.e. something like IRC client libraries
• Should prompt what it'll input, before it gets an input. For example, before inputs serverAddress, it should prompt Write the address of server:, serverIP:serverPort > , serverAddress >, or some text that the user can recognize.
• Should work on several IRC servers using UTF-8. (i.e. not for single server)
• 's messages send to server shouldn't be NOTICE. (RFC 2812, 3.3.2 Notice : The difference between NOTICE and PRIVMSG is that automatic replies MUST NEVER be sent in response to a NOTICE message.)
• Should send a message where the request came from (#channelName or nickname).
• Should PONG when PINGed, of course.

## PS

Well, I just made this, because there was no puzzle about IRC bot.

## Edit

After reading @dmckee's comment, I changed the rule for choosing winner.

1. Default bonus = +0

2. If somehow the program can connect to a channel (even if it's not #channelName), bonus = 1

3. If the program can perform step 1~5, bonus *= 2.

4. For each tasks A~H in step 6, if the program implements, bonus *= 1.2.

5. For each six restrictions, if the program follows that, bonus *= 1.05.

and score = int(codelength/bonus).

Program with lowest score is winner. If two answers have same score, then the answer with highest votes wins.

EDIT Edit : I think 1.2 and 1.05 in step 4 and 5 should be adjusted slightly bigger.. What do you think about this?

The winner is decided, however, I think there was too few entries.

Anyone still may submit the code.. :P

• Frankly we have not been very accepting of "There is no metric, just vote.". There are things for you to work with here in terms of setting up an objective metric for this task. See Fake error message for a possible example. – dmckee --- ex-moderator kitten Jun 11 '11 at 16:18
• @dmckee : Sorry, I didn't know that votes was quite subjective.. :( – JiminP Jun 12 '11 at 0:36
• @JiminP: Nice save. – dmckee --- ex-moderator kitten Jun 12 '11 at 0:38
• irc bot sounds like a longer golf - I'm in though :) – lunixbochs Jun 12 '11 at 1:01
• clarification: "If the program is kicked, try re-joining." - does this mean from the server or the channel? – lunixbochs Jun 12 '11 at 1:40

# PHP - 121 points

• 1396 characters
• Follows all steps (including extra) and restrictions

## Score

<?php
$bonus = 1; //connects to channel$bonus *= 2;                            //completes steps 1-5
for ($x=0;$x < 8;$x++)$bonus *= 1.2;   //all 8 extra steps
for ($y=0;$y < 6;$y++)$bonus *= 1.05;  //all 6 restrictions
echo (int)(1396 / $bonus); > 121  ## Code <?php function w($t){global$s;echo$t."\n";socket_write($s,$t."\r\n");}function m($c,$t){w("PRIVMSG $c :$t");}@$y=fgets;$z=STDIN;echo"nickname>";$n=trim($y($z));echo"realname>";$r=trim($y($z));echo"serverIP:Port>";$a=explode(":",trim($y($z)));$s=socket_create(2,1,6);socket_connect($s,$a[0],$a[1]);w("NICK$n");w("USER $n 0 * :$r");while(1){if((!($l=trim(socket_read($s,512,1))))||(!preg_match("/^(?:\:(\S+)[ ]+)?([^: ][^ ]*)(?:[ ]+([^:].*?))?(?:[ ]+:(.+))?$/",$l,$m)))continue;echo$l."\n";if(preg_match("/(.+)!(.+)@(.+)/",$m[1],$o))$m[1]=$o;if(!empty($m[3]))$p=explode(" ",$m[3]);else$p=array();if(isset($m[4]))$p[]=$m[4];$p=array($m[1],$m[2],$p);$b=$p[2][0];@$e=$p[0][1];@$f=$p[2][1];if($p[1]=="PING")w("PONG :".$b);elseif($p[1]=="376"){echo"#channel>";$c=trim($y($z));$c=(!empty($c))?$c:"#rintaun";w("JOIN $c");}elseif($p[1]=="JOIN")if($e!=$n)m($b,"Hello,$e!");else m($b,"Hello, world!");elseif($p[1]=="KICK")if($f!=$n)m($b,"POW HAHA");else w("JOIN ".$b);elseif(($p[1]=="PART")&&($e!=$n))m($b,"Goodbye, $e!");elseif(($p[1]=="QUIT")&&($e!=$n))m($c,"Goodbye,$e!");elseif($p[1]=="PRIVMSG")if(preg_match("/[Tt]uring test/",$f))m(($b==$n)?$e:$b,"I'm a human!");elseif(strstr($f,"6*9")){w("QUIT :42");break;}elseif(stristr($f,"all your base are belong to us")){w("QUIT :What you say!");break;}elseif($f[0]==" "){$q=str_split(substr($f,1));$u=0;foreach($q AS$d)$u+=ord($d);m(($b==$n)?$e:$b,$u);}}  ### Side Note My answer actually differs from the instructions very slightly; the instructions say to use the realname as the first parameter to the USER command when registering, but I used the nickname instead. This is because the realname is allowed to have spaces, while this parameter is not. It's something of a moot point, though, since switching in the variable for realname would be the exact same character count. # Python - 125 points • 304 chars • follows steps 1-5 (works for me on irc.freenode.net:6667. if you try there, remember IDENT might take a while, so give it 20+ seconds to connect and speak) • follows 4 restrictions (assuming the NOTICE restriction which is a bit unclear. the UTF restriction counts because python won't choke if it doesn't need to parse any UTF). ## score math (python): bonus = 1 # connects to channel bonus *= 2 # steps 1-5 for i in xrange(4): bonus *= 1.05 # 4 restrictions int(304.0/bonus) > 125  ## code: import socket i=raw_input u=i('user# ') n=i('nick# ') h,p=i('host:port# ').split(':',1) p=int(p) c='#'+i('chan# ') z=0 while 1: try: def s(m): z.send(m+'\r\n') z.recv(9) except: z=socket.socket();z.connect((h,p));s('USER '+n+' 0 * :'+n);s('NICK '+n);s('JOIN '+c);s('PRIVMSG '+c+' :Hello, world!')  # Perl, 66 points • 666 characters • all substeps • half of the restrictions ## Score use 5.010;$bonus = 1;              # connects to channel
$bonus *= 2; # steps 1 to 5$bonus *= 1.2 for 1..8;  # substeps A to H
$bonus *= 1.05 for 1..3; # restrictions 3, 4, 6 say int(666 /$bonus);
> 66


## Code

(newlines for presentation only, not counted let alone acceptable)

use POE"Component::IRC";$_='sub _start{Zregister,all);Z"connect")}subX001{ Zjoin=>$c);ZY"Hello, world!")}*Xquit=*Xpart=*Xjoin=sub{$g=$_[STATE]=~/t/?G
oodbye:Hello;$_=$_[ARG0];/\w+/;ZY"$g,$&!")};subXkick{$_=$_[ARG2];/\w+/;Z$&eq$n?"join":Y"POW HAHA")}subXpublic{$_=$_[ARG2];if(/turing test/i){ZY"I\'
m a human!")}elsif(/6\*9/){Zquit,42)}elsif(/all your base are belong to us
/i){Zquit,"What you say!")}elsif(/^ /){$t=-32;$t+=ord for/./g;ZY$t)}}chop( ($n,$r,$s,$c)=<>);$c="#$c";$i=POE::Component::IRC->spawn(nick,$n,ircname,$
r,server,$s)';s/Z/$i->yield(/g;s/Y/privmsg,$c,/g;S/X/ irc_/g;eval;POE::S ession->create(package_states,[main,[grep*$_{CODE},%::]]);POE::Kernel->run


Side Note

The "ALL YOUR BASE ARE BELONG TO US" substep is most probably not worth its character count, but if I dropped it I wouldn't have the nice character count. Bugger.

• +1 for 66 points and 666 characters. Is that intentional or did you get that by accident? – nyuszika7h Apr 28 '14 at 12:55
• @nyuszika7h I honestly don't remember. – J B Apr 28 '14 at 13:18

# Score

bonus = 0       # We've done nothing yet
bonus += 1      # Connects to channel
bonus *= 2      # Step 1 - 5

for n in 1..7
bonus *= 1.2    # A - G
end

for n in 1..4
bonus *= 1.05   # 4 constraints
end

puts (249/bonus).to_i
>  28


# Code

require 'zlib'
b=<<'E'
x�]�_o�0���)��q�-KFBcdf��߃�P�S�B�����(N�Л��s~�� ��(�_$U6��5G�)�r�BB������J�{��� nNhlO�f)QQdJ�g��'�yP�!!����K�ɫ��[Ё�Ə{0�F]ѽ�m�2���GŐP��p ��I����E�+�* z� )jrmKR�ˮ�%� #��nQaJ�H��<�ZT���虦T3.�$D('�hw��a�/'��&�_ei�}o��1���M$����H��J�$��������V"���"��'��|A�<��3L)Y��Z|� e�� ���m�é��ǚ�ڎu��J�����Vq~(ح�
E
eval Zlib::Inflate.new.inflate b


# Ruby, 65 points

• 574 Chars
• Steps 1-5, 6(A-G) and restrictions on libs, UTF-8, no NOTICE & PONG
• Takes commandline args in the form of server:6667 botnick botuser channel

# Score

bonus = 0       # We've done nothing yet
bonus += 1      # Connects to channel
bonus *= 2      # Step 1 - 5

for n in 1..7
bonus *= 1.2    # A - G
end

for n in 1..4
bonus *= 1.05   # 4 constraints
end

puts (574/bonus).to_i
> 65


# Code

require'socket'
a=ARGV
c="##{a[3]}"
h,p=a[0].split':'
s=TCPSocket.open(h,p)
m="PRIVMSG #{c} :"
s.puts"USER #{a[2]} 0 * :#{a[2]}\nNICK #{a[1]}\nJOIN #{c}\n#{m}Hello, world!"
while l=s.gets
case l
when/\:(.+?)!(.+)JOIN/
s.puts"#{m}Hello, #{$1}!" when/KICK (.+?) (.+?) \:(.+)/ if$2==a[1]
s.puts"JOIN #{c}"
else
s.puts"#{m}POW HAHA"
end
when/\:(.+?)\!(.+)(PART|QUIT)/
s.puts"#{m}Goodbye, #{$1}!" when/turing test/i s.puts"#{m}I'm a human!" when/6\*9/ s.puts"QUIT :42" when/all your base are belong to us/i s.puts"QUIT :What you say!" when/PING \:(.+)/ puts"PONG #{$1}"
end
end