Hard Code Golf: Utwórz czat

13

Cue Storyline: Jest początek XXI wieku, a większość rzeczy przeszła do przeszłości. Jednak ty i twoi koledzy-golfa-eteers dążycie do odtworzenia lat 90. W ramach tego wyzwania musisz odtworzyć minimalistyczny pokój rozmów.

Cel: Stworzenie pokoju rozmów z jak najmniejszą liczbą bajtów. Program, który piszesz, powinien działać jako prosty serwer, który obsługuje stronę internetową, która umożliwia użytkownikom publikowanie tekstu na ekranie.

Rzeczywisty cel: faktyczne prowadzenie działającego pokoju rozmów na własnym komputerze. Nie musisz tego robić, ale w ten sposób jest o wiele więcej zabawy.

Wymagania:

  • Użytkownicy powinni mieć możliwość nadania sobie nazwy użytkownika, która będzie trwała podczas sesji
  • Użytkownicy powinni mieć możliwość wielokrotnego wpisywania i przesyłania tekstu, który będzie wyświetlany innym użytkownikom
  • Każdy użytkownik powinien widzieć tekst przesłany przez wszystkich użytkowników wraz z nazwami użytkowników przesyłających, a informacje powinny być wyświetlane w kolejności chronologicznej
  • Strona powinna również wyświetlać liczbę osób online oraz listę ich nazw użytkowników
  • Twój czat powinien być dostępny dla każdego w Internecie, który wie, gdzie go znaleźć (np. Znając adres IP).
  • Powinien działać w nowoczesnych przeglądarkach internetowych.

Wszystko inne zależy od Ciebie!

Zgłoszenia:

  • Powinien zawierać kod źródłowy lub link do kodu źródłowego
  • Powinny zawierać zrzuty ekranu z funkcjonalnego pokoju rozmów
  • Powinien zawierać całkowity rozmiar wszystkich bajtów wszystkich napisanych programów / plików wymaganych do jego działania.

To wyzwanie jest już od dłuższego czasu w piaskownicy, więc mam nadzieję, że wszystkie załamania zostały opracowane.

PhiNotPi
źródło
1
czy byłoby to dopuszczalne, gdybyśmy zmusili rozmówców do wpisania każdej z odpowiedzi w ciągu dziewięciu sekund?
John Dvorak,
Myślę, że 9 sekund jest prawdopodobnie za krótkie. Prawdopodobnie coś w rodzaju 99 sekund mogłoby jednak działać. Nigdy nie myślałem o nałożeniu ograniczeń czasowych na rozmowy.
PhiNotPi
zdefiniuj „online”. Czy musimy ponownie wysłać pocztę przed zwolnieniem, wystarczy 5 sekund, czy możemy nawet twierdzić, że ludzie nigdy się nie wylogowują?
John Dvorak,
czy możemy zezwolić na wstrzykiwanie HTML i inne rzeczy, które mogłyby zepsuć pokój rozmów (o ile nie skrzywdzimy własnego komputera)?
John Dvorak,
Czy potrafisz wyjaśnić „wpisz każdą z odpowiedzi w ciągu dziewięciu sekund?” Przez „online” rozumiem listę osób, które aktualnie przeglądają czat, na przykład otwartą czat w oknie przeglądarki. Limit czasu będzie w porządku.
PhiNotPi

Odpowiedzi:

18

PHP + JQuery + HTML + CSS, 1535 bajtów

Jest to oświadczenie skłaniające się bardziej w kierunku tego, co PO uznał za „faktyczny cel”. To znaczy w pełni funkcjonalny serwer czatu, który może być hostowany na dowolnym serwerze WWW w dowolnym miejscu.

Funkcjonalność obejmuje:

  • Powiadomienia o wejściu lub wyjściu z pokoju czatu.
  • Powiadomienia o zmianie aliasu przez użytkowników.
  • Odpytywanie w czasie rzeczywistym o nowe wiadomości bez generowania nadmiernego ruchu lub obciążenia serwera.
  • Układ i użyteczność bardzo przypominają istniejących klientów czatu, takich jak X-Chat.

Aby być sesją, wpisz alias w odpowiednim polu i naciśnij Tablub, Enteraby przesłać. Jeśli alias jest już używany, zostaniesz o tym powiadomiony. Wysyłanie wiadomości odbywa się również za pośrednictwem Enter.

Dla Twojej wygody archiwum wszystkich plików można znaleźć tutaj: chat.zip (wybierz polecenie Pobierz z menu Plik). Aby zainstalować, rozpakuj do katalogu internetowego na dowolnym serwerze z PHP 5.4 lub nowszym.

Ostrzeżenia:

  • IE 8 lub niższa podczas sondowania zamieni się w nieskończoną pętlę, ponieważ z jakiegoś powodu nieznanego ludzkości wszystkie żądania Ajax są domyślnie buforowane. Zapobiega również dwukrotnemu wysłaniu tej samej wiadomości i poprawnej aktualizacji listy użytkowników. Można to naprawić, dodając cache:falsedo każdego żądania Ajax.
  • We wszystkich wersjach IE wiadomości nie będą wysyłane przez naciśnięcie Enter, ponieważ changezdarzenie nie jest wyzwalane (naciśnięcie Tab jednak działa). Można to naprawić, dodając onkeypressmoduł obsługi, sprawdzając, czy klucz to Enter, a następnie wywołując $(v).blur().focus().

Krótko mówiąc, IE nie jest obsługiwany.


Klient

Pozycjonowanie elementów może być nieco bardziej niezawodne, ale powinno wyglądać dobrze przy minimalnym rozmiarze okna około ~ 800x600.

chat.htm (190 bajtów)

<script src=jquery.min.js></script>
<script src=c.js></script>
<link rel=stylesheet href=c.css>
<select id=u multiple></select><pre id=o></pre>
<input id=n onchange=u()><input id=v onchange=s()>

c.css (136 bajtów)

i{color:#999}
#u{float:right;height:100%;width:200px;margin-left:10px}
#o{border:1px solid #999;height:93%;overflow-y:scroll}
#v{width:54%}

c.js (435 bajtów)

var l
(function p(){
  $.ajax({url:'p.php',data:{n:$('#n').val()},success:function(d){
    $('#o').html(d).scrollTop(1e4);$('#u').load('n.php');
  },complete:p,timeout:2e4})
})()
function s(){
  $.get('s.php',{n:$(n).val(),v:$(v).val()})
  $(v).val('')
}
function u(){
  $.get('u.php',{l:i=l,n:l=$(n).val()}).fail(function(){
    alert("This name is already in use!")
    $(n).val(l=i)
  })
}
$(window).on('unload',function(){$.ajax({url:'l.php',data:{l:l},async:false})})

serwer

Przepraszam, że serwer został podzielony na tak wiele małych kawałków. Alternatywą byłoby użycie odpowiedniego protokołu komunikatu (za pomocą kodowania / dekodowania JSON) lub dużego, if ... elseif ...zgodnie z obecnymi zmiennymi końcowymi. Tworzenie oddzielnych skryptów, po prostu żądanie od tego, czego potrzebujesz, jest o wiele krótsze i być może prostsze niż oba.

o.php (119 bajtów) O długopisy jako połączenie z „bazą danych”

<?$m=array_slice(unserialize(file_get_contents(m)),-300);
$u=unserialize(file_get_contents(u));$t=time();extract($_GET);

c.php (57 bajtów) C zaleca zmiany w „bazie danych”

<?foreach([u,m]as$c)file_put_contents($c,serialize($$c));

p.php (151 bajtów) P olls dla nowych wiadomości

<?for($t=time();@filemtime(m)<$t;usleep(1e3))clearstatcache();include('o.php');
foreach($m as$v)if($n&&$v[0]>=$u[$n])echo@date("[H:i]",$v[0])."$v[1]\n";

s.php (62 bajty) S kończy komunikat do serwera

<?include('o.php');$m[]=[$t,"<b>$n</b>: $v"];include('c.php');

u.php (222 bajtów) U rejestracji Ser lub zmiana ps

<?include('o.php');if(!trim($n)||$u[$n])exit(header('HTTP/1.1 418'));
$m[]=[$t,$u[$l]?
"<i><b>$l</b> is now known as <b>$n</b>.</i>":
"<i><b>$n</b> has entered the chat.</i>"];
$u[$n]=$u[$l]?:$t;unset($u[$l]);include('c.php');

n.php (65 bajtów) pobiera listę użytkowników n , ab

<?include('o.php');foreach($u as$k=>$v)echo"<option>$k</option>";

l.php (98 bajtów) Użytkownik ma l eft (zamknął przeglądarkę)

<?include('o.php');$m[]=[$t,"<i><b>$l</b> has left the chat.</i>"];
unset($u[$l]);include('c.php');
primo
źródło
Myślę, że możesz obejść się onchange=ubez nawiasów. Nie uzyskasz jednak spójnego kontekstu, ale i tak go nie potrzebujesz.
John Dvorak,
Czy możesz uczynić samouczek nieco bardziej szczegółowym? Chcę to skonfigurować na komputerze Mac.
haykam
@Peanut Napisałem kilka instrukcji: codepad.org/UKGwb4g2 . Pracuję na ślepo, ale to prawdopodobnie zadziała.
primo
13

Python, 230

Jest to dość minimalne, ale wydaje się być zgodne ze specyfikacją. Użytkownicy są liczeni jako „przeglądający stronę”, jeśli rozmawiali przez ostatnie 99 sekund.

import cherrypy as S,time
@S.quickstart
@S.expose
def _(n='',p='',l=["<form%sn value='%s'%sp%s'' type=submit>"],u={},t="><input name="):u[n]=time.time();l+=p and[n+':'+p];return'<br>'.join([k*(u[n]-99<u[k])for k in u]+l)%(t,n,t,t)

Wykorzystuje jedną z moich ulubionych sztuczek w pythonie: wartości domyślne są tylko odniesieniami do tego, co przeszedłeś. Jeśli jest to obiekt zmienny, po prostu pojawia się podczas jazdy.

Kolejny, którego nie używam często - curry!

Uruchamianie serwera:

Uruchom skrypt czatu z Pythona (na przykład python chat.py), a następnie skieruj przeglądarkę na, http://localhost:8080aby zobaczyć coś takiego

zrzut ekranu

Python, 442

Ten jest naprawdę przyjemny w użyciu. To jest golf, więc uważam to za mniej satysfakcjonujące rozwiązanie. Teraz nadużywam elementu iframe i formularza z obsługą klawiszy ... oraz metaodświeżania, aby sondować nowe treści.

import time,cherrypy as S
class C:
 c=S.expose(lambda s:"<form action=w target=t method=post><input name=n><input name=p onkeyup='if(event.keyCode==13){this.form.submit();this.value=\"\"}'><br><iframe name=t width=640>")
 @S.expose
 def w(s,n='',p='',l=[],u={}):u[n]=time.time();l+=p and[n+':'+p];return'<meta http-equiv=refresh content="1;url=w?n=%s">'%n+','.join(k for k in u if(u[n]-9<u[k])*k)+'<hr>'+'<br>'.join(l[::-1])
S.quickstart(C())

wersja 2

boothby
źródło
2
Wątpię, czy mogę skierować moją przeglądarkę http://localhost:8080/c i uzyskać dostęp do serwera HTTP
John Dvorak,
1
@JanDvorak Dlatego nie zrobiłem tego linku.
stoisko
1
Dla tych, którzy już mają usługę uruchomioną na porcie 8080, możesz wcześniej przygotować następującą opcję, aby użyć innego portu:S.config.update({'server.socket_port':8090})
primo
Jak trudno byłoby zaktualizować okno czatu, gdy ktoś wysyła nową wiadomość, a nie tylko użytkownik? (W bieżącej formie, aby sprawdzić, czy są jakieś nowe wiadomości, przed zaktualizowaniem okna należy przesłać pustą wiadomość.)
primo
1
@primo Racja! W ten sposób sprawdzasz, czy ludzie coś powiedzieli. Problem rzekomo odtworzył lata 90-te. A wtedy oczekiwanie, że użytkownicy zaakceptują interfejs sugerowany przez najprostszy kod, było nadal fajne. HP dało nam RPN i podobało nam się . Myślenie jak 201 * -er daje 1280 znaków wzdęcia.
stoisko
5

Meteor: 575 znaków

Świetnie się z tym bawiłem! Aplikacja jest dostępna na stronie http://cgchat.meteor.com/ .

chat.html: 171 znaków

<body>{{>b}}</body><template name="b">{{#if l}}Online: {{#each u}}{{n}}, {{/each}}<hr>{{#each m}}{{n}}: {{t}}<p>{{/each}}<hr><input>{{else}}Name: <input>{{/if}}</template>

lib / chat.js: 45 znaków

c=Meteor.Collection;u=new c('u');m=new c('m')

client / client.js: 359 znaków

j=$.now;s=Session;t=Template.b;t.events({'change input':function(){v=$('input').val();s.get('u')?(m.insert({n:s.get('u'),t:v}),u.update(u.findOne({n:s.get('u')})._id,{$set:{l:j()}})):(s.set('u',v),u.insert({n:v,l:j()}))}});t.l=function(){return !!s.get('u')};t.u=function(){return u.find({l:{$gt:(j()-20000)}}).fetch()};t.m=function(){return m.find().fetch()}
Pieter Bos
źródło
Link już nie żyje.
programista
5

Węzeł / Meteor javascript + html + css + websocket: 1,105 bajtów

Oto jeden za pomocą node.js / meteor . Oczywiście napisane w js, w czasie rzeczywistym i przy użyciu websockets. Korzysta z domyślnych wbudowanych pakietów meteorów.

Może być znacznie mniejszy. Jest też trwały dzięki dołączonemu mangowi (nie jest to dobre).

Działający zrzut ekranu:

wprowadź opis zdjęcia tutaj

Aby wykonać, zainstaluj meteor.

Linux:

curl https://install.meteor.com | /bin/sh`

Windows: win.meteor.com

Sklonuj moje repozytorium i wykonaj meteor:

git clone http://github.com/bradgearon/meteor-chat
cd meteor-chat
meteor

skieruj swoją przeglądarkę na localhost: 3000

chat.js: 703 bajty (klient / serwer):

l='subscribe',d=[],n='n',i='i',b='b',c='click #',r='return ',u='u',y=0
f=Function,m=Meteor,o=m.Collection,p=new o(b),t=new o(u)
w=f('t.remove({i:d.pop()})'),g=f('_(d.length).times(w)')
m.isClient&&(h=Template.h,e=h.events={},m[l](b),m[l](u),s=Session,
w=f(r+'s.get(i)'),h.p=f(r+'p.find()'),h.t=f(r+'t.find()'),a=f('a','a','y=$("#3").val(),s.set(i,1)'),
e[c+'2']=f('p.insert({c:(y||"?")+": "+$("#l").val()})'),
e[c + '4'] = f('w()||m.call("x",$("#3").val(),t._connection._lastSessionId,a)')
)||(
m.startup(f('t.remove({}),p.remove({}),m.setInterval(g,100)')),j=f('h=this.id;h&&d.push(h)'),
m.methods({x:f('k','d','s=m.default_server.sessions[d].socket,s.on("close",j),t.insert({n:k,i:s.id})')}))

chat.css: 132 bajty

g{display:block;overflow-y:scroll;margin:10px;}
n{float:right;width:40%;min-height:100%;}
d{float:left;width:60%;min-height:100%;}

chat.html: 270 bajtów

<body>
    {{> h}}
</body>
<template name="h">
<d>
<g>{{#each p}}{{c}}<br />{{/each}}</g>
<input id=l>{{this.k}}</input>
<input type=submit id=2 />
</d>
<n>
<g>{{#each t}}{{n}}<br />{{/each}}</g>
<input id=3 />
<input type=submit id=4 />
</n>
</template>
piwo
źródło
1
Witamy w codegolf! Ten plik chat.htmlwydaje się mieć tylko 254 bajty. Zauważ, że przeglądarki nie są strasznie wybredne - nie zawracam sobie głowy zamykaniem tagów i zdecydowanie nie potrzebujesz ukośnika na końcu tagów (chyba że węzeł tego wymaga?). Zabij też więcej białych znaków! Widzę parę w javascript i zdecydowanie za dużo w HTML.
stoisko