硬编码高尔夫:创建聊天室


13

提示故事情节: 这是21世纪初,大多数事情已经成为过去。但是,您和您的代码高尔夫球专家正在重新制定1990年代。作为此挑战的一部分,您必须重新创建一个简约的聊天室。

目标: 创建一个聊天室,并使其字节数尽可能少。您编写的程序应充当简单的服务器,该服务器提供一个网页,允许用户在屏幕上张贴文本。

实际目标: 通过自己的计算机实际托管一个正常工作的聊天室。您不必执行此操作,但是通过这种方式它会有趣得多。

要求:

  • 用户应该能够给自己一个持续会话的用户名
  • 用户应该能够重复键入和提交文本,这些文本将显示给其他用户
  • 每个用户都应该能够看到所有用户提交的文本以及提交者的用户名,并且信息应按时间顺序显示
  • 该页面还应显示在线人数及其用户名列表
  • 互联网上任何知道在哪里找到它的人(例如知道IP地址)都应该可以访问您的聊天室。
  • 它应可在现代Web浏览器中运行。

其他一切都取决于您!

提交内容:

  • 应该包括源代码,或到源代码的链接
  • 应包括功能聊天室的屏幕截图
  • 应该包括使之正常工作所需的所有已编写程序/文件的总大小(以字节为单位)。

这个挑战已经存在了一段时间,所以希望所有的问题都已经解决了。


1
如果我们强迫聊天者在9秒钟内键入他们的每个回答,那将是允许的吗?
约翰·德沃夏克

我认为9秒可能太短了。不过,大约99秒可能会起作用。我从没想过要限制聊天时间。
PhiNotPi

定义“在线”。我们是否需要在卸载前重新发布,5s的超时就足够了,还是我们甚至可以要求人们从未注销?
John Dvorak

我们是否允许HTML注入和其他可能破坏聊天室的内容(只要我们不伤害自己的计算机)?
John Dvorak

实际上,您能否澄清“在9秒钟内输入他们的每个答复”?“在线”是指当前正在查看聊天室的人员列表,例如在浏览器窗口中打开聊天室。超时就可以了。
PhiNotPi

Answers:


18

PHP + JQuery + HTML + CSS,1535字节

这是一份更倾向于OP认为是“实际目标”的意见书。也就是说,功能齐全的聊天服务器,可以托管在几乎任何地方的任何Web服务器上。

功能包括:

  • 用户进入或离开聊天室时的通知。
  • 用户更改别名时的通知。
  • 实时轮询新消息,而不会产生过多的服务器流量或服务器负载。
  • 布局和可用性非常类似于现有的聊天客户端,例如X-Chat。

要成为会话,请在相应的框中输入别名,然后按TabEnter提交。如果别名已被使用,则会通知您。也可以通过发送消息Enter

为了方便起见,可以在这里找到所有文件的存档:chat.zip(从“文件”菜单中选择“下载”)。要安装,请解压缩到任何运行PHP 5.4或更高版本的服务器上的Web目录。

注意事项:

  • IE 8或更低版本在轮询时将陷入无限循环,因为出于人类未知的某种原因,默认情况下会缓存所有Ajax请求。它还会阻止您发送两次相同的消息,并正确更新用户列表。可以通过添加cache:false到每个Ajax请求中来解决此问题。
  • 在所有版本的IE中,都不会通过按Enter键来发送消息,因为change不会触发该事件(但是,按Tab键是可以的)。可以通过添加onkeypress处理程序,检查键是否为Enter并调用来解决此问题$(v).blur().focus()

简而言之,不支持IE。


客户

元素的定位可能会更健壮,但在最小窗口大小约为800x600的情况下应该看起来不错。

chat.htm(190字节)

<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字节)

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字节)

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

服务器

对于服务器被拆分成这么小的块,我深表歉意。另一种选择是使用适当的消息协议(通过JSON编码/解码),或者if ... elseif ...根据存在的post变量使用较大的消息协议。制作单独的脚本,只是从您需要的脚本中请求一个脚本,比两个脚本都短得多,甚至可能更简单。

o.php(119字节)O笔连接到“数据库”

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

c.php(57字节)C忽略对“数据库”的更改

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

p.php(151个字节)P olls新消息

<?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字节)S向服务器发送一条消息

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

u.php(222字节)U ser注册或别名更改

<?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字节)检索用户n ames 的列表

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

l.php(98个字节)用户具有 EFT(关闭他们的浏览器)

<?include('o.php');$m[]=[$t,"<i><b>$l</b> has left the chat.</i>"];
unset($u[$l]);include('c.php');

我认为您可以onchange=u不用括号。但是,您不会获得一致的上下文,但是无论如何您都不需要它。
约翰·德沃夏克

您可以使本教程更加详细吗?我想在Mac上进行设置。
haykam

@Peanut我输入了一些指令:codepad.org/UKGwb4g2。我正在盲目工作,但这可能会起作用。
primo

13

Python,230

这是相当少的,但似乎符合规范。如果用户在最近99秒钟内聊天,则被视为“正在查看页面”。

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)

这使用了我在python中最喜欢的技巧之一:默认值只是对您传入的内容的引用。如果它是可变对象,它就随它而来。

我不经常使用的另一个-烦人!

运行服务器:

从python运行聊天脚本(例如python chat.py),然后将浏览器指向http://localhost:8080,看到类似

屏幕截图

巨蟒,442

实际上,这是一个很好用的工具。这是高尔夫,所以我认为这不是令人满意的解决方案。现在,我滥用了iframe和具有键处理功能的表单...以及元刷新来轮询新内容。

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

版本2


2
我怀疑我可以点我的浏览器http://localhost:8080/c ,并访问您的HTTP服务器
约翰·德沃夏克

1
@JanDvorak这就是为什么我没有将其链接。
2013年

1
对于已经在端口上运行服务的用户8080,您可以使用以下端口来使用其他端口:S.config.update({'server.socket_port':8090})
primo

任何人而不是用户发送新消息时,更新聊天窗口有多困难?(以当前形式,为了检查是否有任何新消息,您需要在更新窗口之前提交空白消息。)
primo

1
@primo对!这就是您检查人们是否发表意见的方式。问题说重新制定了90年代。那时,期望您的用户接受最简单的代码建议的界面仍然很酷。惠普给了我们RPN,我们喜欢它。像201 * -er的思维方式会膨胀1280个字符。
2013年

5

流星:575个字符

我玩得很开心!该应用程序位于http://cgchat.meteor.com/

chat.html:171个字符

<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个字符

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

client / client.js:359个字符

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

链接现在已死。
程序员

5

节点/流星javascript + html + css + websocket:1,105字节

这是使用node.js / meteor的一种。显然是用js实时编写的,并使用了websockets。使用流星的默认内置程序包。

它可能小很多。另外,它通过包含的mongo是持久的(不是那是一件好事)。

工作屏幕截图:

在此处输入图片说明

要执行,请安装流星。

Linux:

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

Windows:win.meteor.com

克隆我的仓库并执行流星:

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

将您的浏览器指向localhost:3000

chat.js:703个字节(客户端/服务器):

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个字节

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个字节

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

1
欢迎来到codegolf!该文件chat.html似乎只有254个字节。请注意,浏览器并不十分挑剔-我不必费心关闭标签,并且您绝对不需要标签末尾的斜杠(除非节点需要斜杠?)。另外,杀死更多的空格!我在javascript中看到了一对,而在html中看到了太多。
2013年
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.