Створіть чат для кімнат обміну стеками


39

Змагання

Мета цього завдання - створити чат, який може працювати в чатах Stack Exchange. Ваш бот повинен вміти визначати, коли користувач розміщує конкретні команди та відповідати на нього. Це список команд і що ваш бот повинен робити:

  • !!newest: виведіть заголовок (не посилання, а заголовок) останнього питання, розміщеного на цьому веб-сайті (codegolf.SE).
  • !!metanewest: виведіть назву останнього питання, розміщеного на мета-сайті (meta.codegolf.SE).
  • !!questioncount: вивести поточну кількість питань.
  • !!metaquestioncount: вивести поточну кількість питань на мета-сайті.
  • !!tag tagname: виведіть уривок тегу (короткий опис) тегу, який задається як перший параметр.
  • !!metatag tagname: те саме, що вище, але для мета-сайту.
  • !!featured: виведіть кількість запитань, які наразі мають велику суму.
  • !!metafeatured: виведіть кількість запитань, які мають тег [Featured] на Meta.

Правила

  1. Ви повинні написати повну програму, а не фрагмент чи функцію.
  2. У разі необхідності ви можете запитати ім'я користувача та пароль як вхідні (запит на введення, STDIN, аргументи командного рядка). Це буде потрібно, якщо ви використовуєте, наприклад, Python або Ruby, але це не буде потрібно, якщо ви використовуєте JavaScript і запустите скрипт на самій сторінці чату.
  3. Ви можете використовувати зовнішні бібліотеки, щоб робити такі речі, як WebSockets. Ці бібліотеки не повинні вважати вашу кількість персонажів.
  4. Ви можете скористатися зовнішньою обгорткою чату (але не потрібно, рекомендується писати свою власну), і тоді це має враховувати кількість символів. Вам також заборонено змінювати код обгортки. Якщо ви користуєтесь ним, ви використовуєте його без модифікацій, і всі символи повинні рахуватися (це як штраф за не написання власної обгортки).

    Потрібно рахувати лише код самої обгортки. Якщо є інші файли, такі як приклади, їх не потрібно вважати.

  5. Не використовуйте засоби для скорочення URL-адрес чи інші способи, що дозволяють скоротити URL-адреси: завдання полягає в тому, щоб грати в чат, а не гольфувати URL.
  6. Жодних веб-запитів, крім тих, які необхідні для чату та отримання інформації, необхідної для відповіді на команди.
  7. Використання стандартних "прорізів" не дозволяється.
  8. Якщо хто - то відправляє команду, ви повинні реагувати з повідомленням чату цього формату: @user response. Отже, якщо я напишу команду !!featuredі є 5 пропонованих питань, ваш бот повинен опублікувати @ProgramFOX 5.
  9. Якщо я перевіряю вашого бота, я запускатиму його зі свого акаунта чат- ботів і запускатиму його в цій чаті . Я завжди перевіряю ботів у цій кімнаті, тому не потрібно вказувати ідентифікатор кімнати як вхід, він завжди буде 14697. Цей ідентифікатор не вводиться як вхід, він повинен бути жорстко закодований.
  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>)

    Хеш можна отримати за допомогою POSTing id номера та fkey для http://chat.stackexchange.com/ws-auth

    Тимчасовий - це часовий ключ json, що повертається /chats/<roomno>/events.

    Ідентифікатор події, коли повідомлення розміщено, є 1.

  • Корисно подивитися на існуючі обгортки чату, такі як Doorknob 's StackExchange-Chatty і Manishearth's ChatExchange , щоб побачити, як це працює.

3
Щойно я побачив назву, я вмить подумав "ах, ProgramFOX".
seequ

Я сподівався, що metafeaturedце означає надумані питання щодо мета, але ... дякую :-)
Джон Дворак

@JanDvorak Мета-файли на сайті не мають підкреслень, тому я не можу цим користуватися. Коли я написав цей виклик, я забув, що у Meta є тест [Featured], тож дякую за вашу пропозицію!
ProgramFOX

Що я зробив, щоб побачити, чи було розміщено нове повідомлення, перевіряв кожні 2 секунди через JS, якщо останнє повідомлення не було мною (останній предмет у класі)
Cilan

У нас вже є один над тут
містер Чужого

Відповіді:


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})})

Сценарій потрібно запустити безпосередньо у браузері (використовуючи jQuery роботи Stack Exchange):

  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

Чудово! Ви пройшли всі тести . Єдине дивне, що я помітив, це те, що ваш бот повернув інше число питань, ніж на домашній сторінці, але я побачив, що API повертає це число, тому я повідомив про це на Meta і позначив тестовий випадок як правильний. Молодці! +1
ProgramFOX

Я бачив, як ти зробив бота коротшим. Приємно! :) Я його повторно перевірив, і ви все-таки проходите всі тести.
ProgramFOX

Швидше пізно, але я тільки що знайшов поліпшення на один-обвуглене: ви можете замінити 0==e.items.lengthз 1>e.items.lengthтим , що довжина ніколи не опускається нижче нуля.
ProgramFOX
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.