Hard Code Golf: créer un salon de discussion

13

Cue Storyline: C'est le début du 21e siècle, et la plupart des choses sont devenues une chose du passé. Cependant, vous et vos collègues code-golf-eteers êtes en quête de reconstituer les années 1990. Dans le cadre de ce défi, vous devez recréer un salon de discussion minimaliste.

L'objectif: créer un salon de discussion avec le moins d'octets possible. Le ou les programmes que vous écrivez fonctionneront comme un simple serveur, qui sert une page Web, qui permet aux utilisateurs de publier du texte à l'écran.

L'objectif réel: héberger réellement un salon de discussion fonctionnel à partir de votre propre ordinateur. Vous n'avez pas à le faire, mais c'est beaucoup plus amusant de cette façon.

Exigences:

  • Les utilisateurs doivent pouvoir se donner un nom d'utilisateur qui dure la session
  • Les utilisateurs doivent être en mesure de taper et de soumettre du texte à plusieurs reprises, qui sera affiché aux autres utilisateurs
  • Chaque utilisateur doit pouvoir voir le texte qui est soumis par tous les utilisateurs, ainsi que les noms d'utilisateur des auteurs, et les informations doivent être affichées dans l'ordre chronologique
  • La page doit également afficher le nombre de personnes en ligne et une liste de leurs noms d'utilisateur
  • Votre salon de discussion doit être accessible à toute personne sur Internet qui sait où la trouver (comme connaître l'adresse IP).
  • Il devrait fonctionner dans les navigateurs Web modernes.

Tout dépend de vous!

Soumissions:

  • Doit inclure le code source ou un lien vers le code source
  • Devrait inclure des captures d'écran du salon de discussion fonctionnel
  • Doit inclure la taille totale, en octets, de tous les programmes / fichiers que vous avez écrits et qui sont nécessaires pour le faire fonctionner.

Ce défi est dans le bac à sable depuis un certain temps maintenant, alors j'espère que tous les problèmes ont été résolus.

PhiNotPi
la source
1
serait-il permis si nous forçions les chatteurs à taper chacune de leurs réponses dans les neuf secondes?
John Dvorak
Je pense que 9 secondes est probablement trop court. Cependant, quelque chose comme 99 secondes pourrait probablement fonctionner. Je n'ai jamais pensé à imposer des limites de temps aux chatteurs.
PhiNotPi
définir "en ligne". Avons-nous besoin de poster avant le déchargement, un délai de 5 secondes suffira, ou sommes-nous même autorisés à déclarer que les gens ne se déconnectent jamais?
John Dvorak
sommes-nous autorisés à autoriser l'injection HTML et d'autres choses qui pourraient briser le salon de discussion (tant que nous ne blessons pas notre propre ordinateur)?
John Dvorak
En fait, pouvez-vous préciser «tapez chacune de ses réponses dans les neuf secondes? Par «en ligne», j'entendrais une liste de personnes qui consultent actuellement le salon de discussion, comme ouvrir le salon de discussion dans une fenêtre de navigateur. Un timeout sera bien.
PhiNotPi

Réponses:

18

PHP + JQuery + HTML + CSS, 1535 octets

Il s'agit d'une soumission qui penche davantage vers ce que le PO considérait comme «l'objectif réel». Autrement dit, un serveur de chat entièrement fonctionnel, qui peut être hébergé sur à peu près n'importe quel serveur Web n'importe où.

La fonctionnalité comprend:

  • Notifications lorsque les utilisateurs entrent ou quittent la salle de chat.
  • Notifications lorsque les utilisateurs modifient leur alias.
  • Interrogation en temps réel pour les nouveaux messages, sans générer de trafic serveur excessif ni de charge serveur.
  • La mise en page et la convivialité ressemblent fortement aux clients de chat existants, tels que X-Chat.

Pour être une session, entrez un alias dans la case appropriée et appuyez sur Tabou Enterpour soumettre. Si l'alias est déjà utilisé, vous en serez informé. L'envoi de messages se fait également via Enter.

Pour votre commodité, une archive de tous les fichiers peut être trouvée ici: chat.zip (choisissez Télécharger dans le menu Fichier). Pour l'installer, décompressez vers un répertoire Web sur n'importe quel serveur exécutant PHP 5.4 ou supérieur.

Mises en garde:

  • IE 8 ou inférieur tournera dans une boucle infinie pendant l'interrogation, car pour une raison inconnue de l'humanité, toutes les requêtes Ajax sont mises en cache par défaut. Il vous empêche également d'envoyer deux fois le même message et de mettre à jour correctement la liste des utilisateurs. Cela pourrait être corrigé en ajoutant cache:falseà chaque demande Ajax.
  • Dans toutes les versions d'IE, les messages ne seront pas envoyés en appuyant sur Entrée, car l' changeévénement n'est pas déclenché (en appuyant sur Tab, cependant, cela fonctionne). Cela pourrait être résolu en ajoutant un onkeypressgestionnaire, en vérifiant si la clé était Entrée, puis en appelant $(v).blur().focus().

En bref, IE n'est pas pris en charge.


Client

Le positionnement des éléments pourrait être un peu plus robuste, mais il devrait bien paraître avec une taille de fenêtre minimale d'environ ~ 800x600.

chat.htm (190 octets)

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

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

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

Serveur

Je m'excuse pour le serveur étant divisé en autant de petits morceaux. L'alternative serait d'utiliser un protocole de message adéquat (via l'encodage / décodage JSON), ou d'avoir un grand if ... elseif ...en fonction des variables de post présentes. Faire des scripts séparés, une simple demande de celui dont vous avez besoin est beaucoup plus court, et peut-être plus simple que les deux.

o.php (119 octets) O stylets comme connexion à la 'base de données'

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

c.php (57 octets) C ommet les modifications de la 'base de données'

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

p.php (151 octets) P OLL pour les nouveaux messages

<?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 octets) S fin un message au serveur

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

u.php (222 octets) Enregistrement de ser u ou changement d'alias

<?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 octets) Récupère la liste des utilisateurs n ames

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

l.php (98 octets) L'utilisateur a l eft (fermé son navigateur)

<?include('o.php');$m[]=[$t,"<i><b>$l</b> has left the chat.</i>"];
unset($u[$l]);include('c.php');
primo
la source
Je pense que vous pouvez vous onchange=upasser des parenthèses. Cependant, vous n'obtiendrez pas un contexte cohérent, mais vous n'en avez pas besoin de toute façon.
John Dvorak
Pouvez-vous rendre le tutoriel un peu plus détaillé? Je veux configurer cela sur un Mac.
haykam
@Peanut J'ai tapé quelques instructions: codepad.org/UKGwb4g2 . Je travaille à l'aveugle, mais cela fonctionnera probablement.
primo
13

Python, 230

C'est assez minime, mais cela semble être conforme aux spécifications. Les utilisateurs sont comptés comme "affichant la page" s'ils ont discuté au cours des 99 dernières secondes.

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)

Cela utilise l'une de mes astuces préférées en python: les valeurs par défaut ne sont que des références à tout ce que vous avez passé. Si c'est un objet mutable, il vient juste pour le trajet.

Un autre que je n'utilise pas souvent - le curry!

Exécution du serveur:

Exécutez le script de chat à partir de python (par exemple, python chat.py) puis pointez votre navigateur vers http://localhost:8080pour voir quelque chose comme

capture d'écran

Python, 442

Celui-ci est en fait agréable à utiliser. C'est le golf, donc je considère que c'est une solution moins satisfaisante. Maintenant, j'abuse un iframe et un formulaire avec le traitement des clés ... et une méta-actualisation pour interroger le nouveau contenu.

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

version 2

boothby
la source
2
Je doute que je puisse pointer mon navigateur vers http://localhost:8080/c et accéder à votre serveur HTTP
John Dvorak
1
@JanDvorak C'est pourquoi je n'en ai pas fait un lien.
stand
1
Pour ceux qui ont déjà un service en cours d'exécution sur le port 8080, vous pouvez ajouter ce qui suit pour utiliser un autre port:S.config.update({'server.socket_port':8090})
primo
À quel point serait-il difficile de mettre à jour la fenêtre de discussion lorsque quelqu'un envoie un nouveau message, et pas seulement l'utilisateur? (Dans sa forme actuelle, afin de vérifier s'il y a de nouveaux messages, vous devez envoyer un message vierge avant la mise à jour de votre fenêtre.)
primo
1
@primo Droite! Voilà comment vous vérifiez si les gens ont dit quelque chose. Le problème dit de reconstituer les années 90. Et à l'époque, s'attendre à ce que vos utilisateurs acceptent l'interface suggérée par le code le plus simple était toujours cool. HP nous a donné RPN, et nous l'avons aimé . Penser comme un 201 * -er vous donne 1280 caractères de ballonnement.
boothby
5

Meteor: 575 caractères

J'ai eu beaucoup de plaisir avec celui-ci! L'application est en ligne sur http://cgchat.meteor.com/ .

chat.html: 171 caractères

<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 caractères

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

client / client.js: 359 caractères

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
la source
Le lien est maintenant mort.
programmer5000
5

Noeud / Meteor javascript + html + css + websocket: 1,105 octets

En voici un qui utilise node.js / meteor . Évidemment écrit en js, en temps réel et en utilisant des websockets. Utilise les packages intégrés par défaut de meteor.

Il pourrait être beaucoup plus petit. De plus, il est persistant grâce au mongo inclus (pas que ce soit une bonne chose).

Une capture d'écran fonctionnelle:

entrez la description de l'image ici

Pour exécuter, installez météore.

Linux:

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

Windows: win.meteor.com

Clonez mon dépôt et exécutez le météore:

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

pointer votre navigateur vers localhost: 3000

chat.js: 703 octets (client / serveur):

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 octets

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 octets

<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>
beeradg
la source
1
Bienvenue sur codegolf! Ce fichier ne chat.htmlsemble avoir que 254 octets. Notez que les navigateurs ne sont pas terriblement difficiles - je ne prends pas la peine de fermer les balises, et vous n'avez certainement pas besoin de la barre oblique à la fin des balises (sauf si le nœud l'exige?). Aussi, tuez plus d'espace! J'en vois quelques-uns dans le javascript, et beaucoup trop dans le html.
stand