为Stack Exchange聊天室创建聊天机器人


39

挑战

这项挑战的目标是创建一个可以在Stack Exchange聊天室中运行的聊天机器人。您的漫游器需要能够检测用户何时发布特定命令并对其进行响应。这是命令列表,以及您的机器人应该做什么:

  • !!newest:输出在此站点(codegolf.SE)上发布的最新问题的标题(无链接,但标题)。
  • !!metanewest:输出发布在元网站(meta.codegolf.SE)上的最新问题的标题。
  • !!questioncount:输出当前的问题计数。
  • !!metaquestioncount:在meta网站上输出当前问题计数。
  • !!tag tagname:输出作为第一个参数给出的标签的标签摘录(简短描述)。
  • !!metatag tagname:与上述相同,但用于元网站。
  • !!featured:输出当前有赏金的问题计数。
  • !!metafeatured:输出在Meta上带有[featured]标签的问题计数。

规则

  1. 您应该编写完整的程序,而不是代码段或函数。
  2. 如果有必要,您可以请求用户名和密码作为输入(提示输入,STDIN,命令行参数)。如果使用(例如)Python或Ruby,这将是必需的,但是如果使用JavaScript并在聊天室页面本身上运行脚本,则不需要。
  3. 您可以使用外部库来做WebSockets之类的事情。这些库不必计入您的字符数。
  4. 可以使用外部聊天包装器(但不必这样做,建议您自己编写),然后必须计算字符数。您也不允许更改包装程序的代码。如果使用它,则无需修改即可使用它,并且必须计算所有字符(这是不编写自己的包装器的一种惩罚)。

    仅包装器本身的代码必须计数。如果还有其他文件(例如示例),则不必计数。

  5. 不使用URL缩短器或其他可以缩短URL的方式:挑战是打高尔夫,而不是打URL。
  6. 除了聊天和获取响应命令所必需的信息之外,没有任何Web请求。
  7. 不允许使用标准的“漏洞”
  8. 如果有人发布命令,则您需要使用以下格式的聊天消息进行响应:@user response。因此,如果我编写命令!!featured并有5个有特色的问题,则您的机器人应该发布@ProgramFOX 5
  9. 如果我测试了您的机器人,那么我将通过我的chatbot帐户运行它,并在此聊天室中运行它。我将始终在该房间中测试机器人,因此不必提供房间ID作为输入,它始终为14697。不会提供此ID作为输入,它应该是硬编码的。
  10. 如果未找到命令,则输出@user The command [command] does not exist。替换[command]为不存在的命令的名称。如果将参数提供给命令,则不输出参数,仅输出命令名称。
  11. 如果命令必须包含许多参数,请忽略不必要的参数。
  12. 如果命令的参数不足,则输出 @user You have not provided enough arguments
  13. 系统防止重复消息在短时间内发布。因此,在测试您的漫游器时,我永远不会运行两个连续提供相同输出的命令(这意味着您不必实现一个系统,该系统如果消息重复则通过添加一个点来使消息不同)。
  14. 系统会防止在短时间内发布太多消息,因此在测试时,我绝不会在短时间内发送太多命令,这意味着您的机器人不必为此担心(等待一段时间)例如,在发布之前)。
  15. 这是,使用最少字节数的程序获胜。

入门

这是一些有关编写机器人的入门信息。您不必使用它,但是它可以作为指导。

  • 要登录,请首先登录到OpenID提供程序。这将始终是Stack Exchange OpenID(https://openid.stackexchange.com)。登录表单位于https://openid.stackexchange.com/account/login,并在此处提供用户名和密码。
  • 然后,登录到stackexchange.com。登录表单位于https://stackexchange.com/users/login。选择Stack Exchange作为OpenID提供程序。
  • 完成后,登录聊天。的登录表单位于http://stackexchange.com/users/chat-login。选择Stack Exchange作为OpenID提供程序。
  • 然后,您需要拿到您的fkey。为此,请转到隐藏的输入字段http://chat.stackexchange.com/chats/join/favorite并从中获取fkey
  • 要发布消息,请向发送请求http://chat.stackexchange.com/chats/14697/messages/new,并提供两个POST参数:一个text包含消息文本的fkey参数,一个包含的参数fkey
  • 要查看何时发布新消息,可以使用WebSockets(但不必一定要使用,如果较短则可以使用其他方法)。请查看此Meta Stack Exchange答案

    聊天室

    (wss://chat.sockets.stackexchange.com/events/<roomnumber>/<somehash>?l=<timethingy>)

    可以通过发布房间ID和fkey到 http://chat.stackexchange.com/ws-auth

    timethingy是所返回的json的时间键/chats/<roomno>/events

    发布消息时的事件ID为1

  • 查看现有的聊天包装器(如Doorknob的StackExchange -Chatty和Manishearth的ChatExchange)很有用,以了解其工作原理。

3
看到标题的那一刻,我立即想到了“啊,ProgramFOX”。
seequ 2014年

我希望metafeatured对元数据有很多疑问,但是...谢谢:-)
John Dvorak

@JanDvorak每个站点的meta没有赏金,所以我不能使用它。当我写这个挑战时,我忘记了Meta带有[featured]标签,所以谢谢您的建议!
ProgramFOX 2014年

我要查看是否发布了新消息,是每隔2秒钟通过JS检查一次,如果最后一条消息不是我(班上的最后一项)不是由我检查的
Cilan

我们已经有一个在这里
Alien先生

Answers:


14

JavaScript + jQuery,1362 1258字节

打高尔夫球的人

$(function(){function e(){function e(e,t){$("#input").val("@"+$(e).parents(".user-container").find(".username").eq(0).text()+" "+t),$("#sayit-button").click()}var i,a=$(t),s=a.map(function(e,t){return t.id}),r=s.slice(-1)[0]
n!=r&&(i=a.slice($.inArray(n,s)+1),n=r,i.map(function(t,n){var i,a,s,r,o,u,c,f=n.textContent.match(/!!(\S+)(?:\s+(\S+))?/)
if(f){switch(i=f[1],a=f[2],s="codegolf",0==i.indexOf("meta")&&(s="meta."+s,i=i.slice(4)),r="?site="+s,c=0,i){case"newest":o=["questions","&order=desc&sort=creation"],u=function(e){return e.items[0].title}
break
case"questioncount":o=["info",""],u=function(e){return e.items[0].total_questions}
break
case"tag":if(!a){c=1
break}o=["tags/"+a+"/wikis",""],u=function(e){return 0==e.items.length?"Tag not found":e.items[0].excerpt}
break
case"featured":o=0==s.indexOf("meta.")?["questions","&tagged=featured"]:["questions/featured",""],u=function(e){var t=e.items.length
return(e.items.has_more?"more than ":"")+t}}c?e(n,"You have not provided enough arguments"):o?$.get("http://api.stackexchange.com/2.2/"+o[0]+r+o[1],function(t){e(n,u(t))}):e(n,"The command "+i+" does not exist")}}))}var t="[id^=message-]",n=$(t).eq(-1).attr("id")
new MutationObserver(e).observe($("#chat").get(0),{childList:!0,subtree:!0})})

您必须直接在浏览器中运行脚本(使用Stack Exchange的jQuery作品):

  1. 打开http://chat.stackexchange.com/rooms/14697/chatbot-challenge-on-programming-puzzles-code-golf
  2. 将上面的代码粘贴到控制台中
  3. 在聊天中输入一些命令

它可以打更多的高尔夫球,但不能打扰。


未打高尔夫球:

$(function() {
    var sel = '[id^=message-]';
    var latestMessage = $(sel).eq(-1).attr('id');
    function update() {
        var messages = $(sel);
        var ids = messages.map(function(i, x) { return x.id; });
        var newest = ids.slice(-1)[0];
        if(latestMessage == newest) {
            return;
        }
        var newMessages = messages.slice($.inArray(latestMessage, ids) + 1);
        latestMessage = newest;
        newMessages.map(function(i, x) {
            var m = x.textContent.match(/!!(\S+)(?:\s+(\S+))?/);
            if(!m) {
                return;
            }
            var c = m[1];
            var a = m[2];
            var s = 'codegolf';
            if(c.indexOf('meta') == 0) {
                s = 'meta.' + s;
                c = c.slice(4);
            }
            var site = '?site=' + s;
            var url;
            var extractor;
            var too_few_args = 0;
            switch(c) {
                case 'newest':
                    var url = ['questions', '&order=desc&sort=creation'];
                    extractor = function(data) {
                        return data.items[0].title;
                    };
                    break;
                case 'questioncount':
                    url = ['info', ''];
                    extractor = function(data) {
                        return data.items[0].total_questions;
                    };
                    break;
                case 'tag':
                    if(!a) {
                        too_few_args = 1;
                        break;
                    }
                    url = ['tags/' + a + '/wikis', ''];
                    extractor = function(data) {
                        if(data.items.length == 0) {
                            return 'Tag not found';
                        }
                        return data.items[0].excerpt;
                    };
                    break;
                case 'featured':
                    url = s.indexOf('meta.') == 0? ['questions', '&tagged=featured']: ['questions/featured', ''];
                    extractor = function(data) {
                        var l = data.items.length;
                        return (data.items.has_more? 'more than ': '') + l;
                    }
                    break;
            }
            if(too_few_args) {
                write(x, 'You have not provided enough arguments');
            } else if(!url) {
                write(x, 'The command ' + c + ' does not exist');
            } else {
                $.get('http://api.stackexchange.com/2.2/' + url[0] + site + url[1], function(data) {
                    write(x, extractor(data));
                });
            }
        });

        function write(x, m) {
            $('#input').val('@' + $(x).parents('.user-container').find('.username').eq(0).text() + ' ' + m);
            $('#sayit-button').click();
        }
    }
    new MutationObserver(update).observe($('#chat').get(0), {childList: true, subtree: true});
});

很好,谢谢您在这里发布答案!我现在要在房间里运行测试。无论如何,我认为您可以通过使用更多的一个字母变量并避免使用update和来保存一些字符latestMessage
ProgramFOX 2014年

大!您通过了所有测试。我注意到的唯一奇怪的事情是您的机器人返回的问题计数与首页上的计数不同,但是我看到API返回了该数字,因此我在Meta上报告了此问题,并将测试用例标记为正确。做得好!+1
ProgramFOX

我看到你把机器人缩短了。真好!:)我重新测试了它,您仍然通过了所有测试。
ProgramFOX 2014年

有点晚了,但我发现一个单字符改进:您可以替换为0==e.items.length1>e.items.length因为长度永远不会低于零。
ProgramFOX
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.