Stack Exchange 대화방을위한 챗봇 만들기 없지만 제목)을 출력합니다

도전

이 과제의 목표는 Stack Exchange의 대화방에서 실행할 수있는 챗봇을 만드는 것입니다. 봇은 사용자가 특정 명령을 게시 한 시점을 감지하고 이에 응답 할 수 있어야합니다. 다음은 명령 목록이며 봇이 수행해야 할 작업입니다.

  • !!newest:이 사이트에 게시 된 최신 질문의 제목 (링크는 없지만 제목)을 출력합니다 (codegolf.SE).
  • !!metanewest: 메타 사이트 (meta.codegolf.SE)에 게시 된 최신 질문의 제목을 출력합니다.
  • !!questioncount: 현재 질문 개수를 출력합니다.
  • !!metaquestioncount: 메타 사이트에서 현재 질문 수를 출력합니다.
  • !!tag tagname: 첫 번째 매개 변수로 제공된 태그의 태그 발췌 (짧은 설명)를 출력합니다.
  • !!metatag tagname: 위와 동일하지만 메타 사이트 용.
  • !!featured: 현상금이있는 질문 수를 출력합니다.
  • !!metafeatured: 메타에 [featured] 태그 가있는 질문 수를 출력합니다 .

규칙

  1. 스 니펫이나 함수가 아닌 완전한 프로그램을 작성해야합니다.
  2. 필요한 경우 사용자 이름과 비밀번호를 입력 (입력, STDIN, 명령 행 인수 프롬프트)으로 요청할 수 있습니다. 예를 들어 Python 또는 Ruby를 사용하는 경우에는 필요하지만 JavaScript를 사용하고 대화방 페이지에서 스크립트를 실행하는 경우에는 필요하지 않습니다.
  3. WebSocket과 같은 작업을 수행하기 위해 외부 라이브러리를 사용할 수 있습니다. 이 라이브러리는 문자 수를 계산할 필요가 없습니다.
  4. 당신은 수있는 문자 수에 대한 카운트가 그 다음 외부 채팅 래퍼를 사용 (하지만 당신은 자신을 작성하는 것은 권장하지 않음). 랩퍼의 코드를 변경할 수도 없습니다. 그것을 사용한다면, 그것을 수정하지 않고 사용하고 모든 문자를 세어야합니다 (자신의 래퍼를 쓰지 않는 것에 대한 페널티입니다).

    랩퍼 자체의 코드 만 계산해야합니다. 예제와 같은 다른 파일이 있으면 계산할 필요가 없습니다.

  5. URL 단축기를 사용하거나 URL을 짧게 만들 수있는 다른 방법을 사용하지 마십시오. 문제는 URL을 골프하지 않고 챗봇을 골프화하는 것입니다.
  6. 채팅 및 명령에 응답하는 데 필요한 정보를 얻는 데 필요한 웹 요청을 제외하고 웹 요청이 없습니다.
  7. 의 사용 기준 “허점”는 허용되지 않습니다.
  8. 누군가 명령을 게시하면 다음 형식의 채팅 메시지로 응답해야합니다 @user response. 따라서 명령을 작성하고 !!featured5 개의 추천 질문이 있으면 봇이 게시해야합니다 @ProgramFOX 5.
  9. 봇을 테스트하면 챗봇 계정 에서 봇을 실행 하고이 채팅방 에서 봇을 실행합니다 . 나는 항상 그 방에서 봇을 테스트 할 것이므로 방 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 공급자에 로그인하십시오. 이것은 항상 스택 교환 OpenID ( https://openid.stackexchange.com)입니다. 로그인 양식은에 있으며 https://openid.stackexchange.com/account/login사용자 이름과 비밀번호를 입력하십시오.
  • 그런 다음에 로그인하십시오 stackexchange.com. 로그인 양식은에 있습니다 https://stackexchange.com/users/login. 스택 교환을 OpenID 공급자로 선택하십시오.
  • 그런 다음 로그인하여 채팅하십시오. 로그인 양식은에 있습니다 http://stackexchange.com/users/chat-login. 스택 교환을 OpenID 공급자로 선택하십시오.
  • 그런 다음을 받아야합니다 fkey. 이를 위해, 이동 http://chat.stackexchange.com/chats/join/favorite과를 얻을 수 fkey숨겨진 입력 필드에서.
  • 메시지를 게시하려면에 요청을 보내고 메시지 텍스트를 포함 http://chat.stackexchange.com/chats/14697/messages/new하는 text매개 변수와를 포함 하는 매개 변수 라는 두 개의 POST 매개 fkey변수를 제공하십시오 fkey.
  • 새 메시지가 게시되는시기를 확인하려면 WebSocket을 사용할 수 있습니다 (단, 더 짧은 경우 다른 것을 사용할 필요는 없습니다). 이 Meta Stack Exchange 답변을 참조하십시오 .

    잡담

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

    룸 ID와 fkey를 POST하여 POST를 가져올 수 있습니다. http://chat.stackexchange.com/ws-auth

    timethingy는에 의해 반환 된 json의 시간 키입니다 /chats/<roomno>/events.

    메시지가 게시 될 때의 이벤트 ID는입니다 1.

  • DoorknobStackExchange-Chatty 및 Manishearth의 ChatExchange 와 같은 기존 대화 래퍼 를보고 그것이 어떻게 작동하는지 보는 것이 유용 합니다.


답변

자바 스크립트 + 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});
});