Hard Code Golf: สร้างห้องแชท


13

เรื่องราวของคิว: มันเป็นช่วงต้นศตวรรษที่ 21 และสิ่งต่าง ๆ ได้กลายเป็นอดีตไปแล้ว อย่างไรก็ตามคุณและเพื่อนร่วมวง code-eteers ของคุณอยู่ในการสืบเสาะเพื่อทำซ้ำในปี 1990 เป็นส่วนหนึ่งของความท้าทายนี้คุณต้องสร้างห้องแชทที่เรียบง่าย

เป้าหมาย: เพื่อสร้างห้องแชทที่มีไบต์น้อยที่สุด โปรแกรมที่คุณเขียนจะทำงานเป็นเซิร์ฟเวอร์อย่างง่ายซึ่งทำหน้าที่เป็นเว็บเพจซึ่งอนุญาตให้ผู้ใช้โพสต์ข้อความบนหน้าจอ

เป้าหมายที่แท้จริง: เพื่อโฮสต์ห้องแชทที่ใช้งานได้จริงจากคอมพิวเตอร์ของคุณเอง คุณไม่ต้องทำสิ่งนี้ แต่มันสนุกกว่านี้มาก

ที่ต้องการ:

  • ผู้ใช้ควรให้ชื่อผู้ใช้กับเซสชันนั้นได้
  • ผู้ใช้ควรสามารถพิมพ์และส่งข้อความซ้ำ ๆ ซึ่งจะปรากฏแก่ผู้ใช้รายอื่น
  • ผู้ใช้แต่ละคนควรสามารถเห็นข้อความที่ส่งโดยผู้ใช้ทั้งหมดพร้อมกับชื่อผู้ใช้ของผู้ส่งและข้อมูลควรแสดงตามลำดับเวลา
  • หน้าควรแสดงจำนวนผู้ใช้ออนไลน์และรายชื่อผู้ใช้
  • ห้องแชทของคุณควรเข้าถึงได้โดยทุกคนบนอินเทอร์เน็ตที่รู้ว่าจะหาได้ที่ไหน (เช่นรู้ที่อยู่ IP)
  • ควรทำงานในเว็บเบราว์เซอร์ที่ทันสมัย

ทุกอย่างขึ้นอยู่กับคุณ!

ที่ส่ง:

  • ควรรวมซอร์สโค้ดหรือลิงก์ไปยังซอร์สโค้ด
  • ควรมีภาพหน้าจอของห้องแชทที่ใช้งานได้
  • ควรมีขนาดรวมเป็นไบต์ของโปรแกรม / ไฟล์ทั้งหมดที่คุณเขียนซึ่งจำเป็นต้องใช้เพื่อให้มันทำงานได้

ความท้าทายนี้อยู่ในกล่องทรายมาระยะหนึ่งแล้วดังนั้นหวังว่าข้อผิดพลาดทั้งหมดจะได้รับการแก้ไข


1
จะอนุญาตหรือไม่ถ้าเราบังคับให้นักแชตพิมพ์คำตอบแต่ละคำภายในเก้าวินาที
John Dvorak

ฉันคิดว่า 9 วินาทีนั้นสั้นเกินไป แม้ว่าบางอย่างเช่น 99 วินาทีอาจทำงานได้ ฉันไม่เคยคิดถึงการ จำกัด เวลาในการแชท
PhiNotPi

กำหนด "ออนไลน์" เราจำเป็นต้องโพสต์อีกครั้งก่อนที่จะยกเลิกการโหลดการหมดเวลา 5 วินาทีจะเพียงพอหรือไม่หรือเราได้รับอนุญาตให้อ้างสิทธิ์ผู้ที่ไม่เคยออกจากระบบด้วยหรือไม่
John Dvorak

เราอนุญาตให้ใช้การฉีด HTML และสิ่งอื่น ๆ ที่อาจทำให้ห้องแชทเสียหายได้หรือไม่ (ตราบใดที่เราไม่ทำให้คอมพิวเตอร์ของเราเสียหาย)
John Dvorak

ที่จริงแล้วคุณสามารถชี้แจง "พิมพ์คำตอบแต่ละข้อภายในเก้าวินาทีหรือไม่" โดย "ออนไลน์" ฉันหมายถึงรายชื่อคนที่กำลังดูห้องแชทอยู่เช่นเปิดห้องแชทไว้ในหน้าต่างเบราว์เซอร์ หมดเวลาจะดี
PhiNotPi

คำตอบ:


18

PHP + JQuery + HTML + CSS ขนาด 1535 ไบต์

นี่คือการส่งเอนทับต่อสิ่งที่ OP เห็นว่าเป็น 'เป้าหมายที่แท้จริง' นั่นคือเซิร์ฟเวอร์แชทที่ทำงานได้อย่างสมบูรณ์ซึ่งอาจโฮสต์บนเว็บเซิร์ฟเวอร์เกือบทุกที่

ฟังก์ชั่นรวมถึง:

  • การแจ้งเตือนเมื่อผู้ใช้เข้าหรือออกจากห้องแชท
  • การแจ้งเตือนเมื่อผู้ใช้เปลี่ยนนามแฝง
  • การทำโพลแบบเรียลไทม์สำหรับข้อความใหม่โดยไม่สร้างทราฟฟิกเซิร์ฟเวอร์ส่วนเกินหรือโหลดเซิร์ฟเวอร์
  • เลย์เอาต์และการใช้งานคล้ายกับไคลเอนต์แชทที่มีอยู่อย่างยิ่งเช่น X-Chat

ในการเป็นเซสชันให้ป้อนชื่อแทนในกล่องที่เหมาะสมแล้วกดTabหรือEnterเพื่อส่ง หากมีการใช้นามแฝงอยู่แล้วคุณจะได้รับแจ้ง การส่งข้อความก็ทำได้เช่นEnterกัน

เพื่อความสะดวกของคุณอาจพบไฟล์เก็บถาวรทั้งหมดที่นี่: chat.zip (เลือกดาวน์โหลดจากเมนูไฟล์) ในการติดตั้งให้แกะเว็บสารบบบนเซิร์ฟเวอร์ใด ๆ ที่ใช้ PHP 5.4 ขึ้นไป

คำเตือน:

  • IE 8 หรือต่ำกว่าจะหมุนวนเป็นวงแบบไม่ จำกัด ในขณะที่ทำการสำรวจเพราะด้วยเหตุผลบางประการที่ไม่รู้จักกับมนุษยชาติคำขอ Ajax ทั้งหมดจะถูกแคชตามค่าเริ่มต้น นอกจากนี้ยังป้องกันไม่ให้คุณส่งข้อความเดิมสองครั้งและอัปเดตรายชื่อผู้ใช้อย่างถูกต้อง อาจแก้ไขได้ด้วยการเพิ่มcache:falseคำขอ Ajax ทุกครั้ง
  • ใน IE ทุกเวอร์ชันข้อความจะไม่ถูกส่งโดยการกด Enter เนื่องจากchangeเหตุการณ์ไม่ได้ถูกทริกเกอร์ (กด Tab แต่ทำงานได้) ซึ่งอาจได้รับการแก้ไขโดยการเพิ่มการจัดการการตรวจสอบถ้าคีย์คือใส่แล้วโทรonkeypress$(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 ...ตามตัวแปรโพสต์ที่มีอยู่ การสร้างสคริปต์แยกต่างหากการขอเพียงอย่างเดียวจากสคริปต์ที่คุณต้องการนั้นสั้นกว่ามากและอาจง่ายกว่ากันมาก

o.php (119 bytes) ปากกาOเชื่อมต่อกับ 'ฐานข้อมูล'

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

c.php (57 bytes) C ommits เปลี่ยนเป็น 'ฐานข้อมูล'

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

p.php (151 bytes) 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 bytes) Sสิ้นสุดข้อความไปยังเซิร์ฟเวอร์

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

u.php (222 bytes) 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 ไบต์) ผู้ใช้มีl eft (ปิดเบราว์เซอร์)

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

ฉันคิดว่าคุณสามารถทำได้onchange=uโดยไม่ต้องวงเล็บ คุณจะไม่ได้รับบริบทที่สอดคล้องกัน แต่คุณไม่ต้องการมัน
John Dvorak

คุณช่วยทำให้การสอนมีรายละเอียดมากขึ้นได้ไหม? ฉันต้องการตั้งค่านี้บน Mac
haykam

@Peanut ฉันพิมพ์ขึ้นคำแนะนำบางอย่างcodepad.org/UKGwb4g2 ฉันทำงานตาบอด แต่อาจจะใช้ได้
โม่

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 chat.py) จากนั้นชี้เบราว์เซอร์ของคุณที่http://localhost:8080เพื่อดูสิ่งที่ต้องการ

ภาพหน้าจอ

Python 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 ของคุณ
John Dvorak

1
@JanDvorak นั่นเป็นสาเหตุที่ฉันไม่ได้สร้างลิงก์
บูธโดย

1
สำหรับผู้ที่มีบริการที่ใช้งานพอร์ตอยู่8080แล้วคุณอาจเพิ่มรายการต่อไปนี้เพื่อใช้พอร์ตอื่น:S.config.update({'server.socket_port':8090})
primo

มันจะยากแค่ไหนในการอัพเดทหน้าต่างแชทเมื่อมีคนส่งข้อความใหม่ไม่ใช่แค่ผู้ใช้? (ในรูปแบบปัจจุบันเพื่อที่จะตรวจสอบว่ามีข้อความใหม่ใด ๆ ที่คุณจำเป็นต้องส่งข้อความว่างเปล่าก่อนที่หน้าต่างของคุณมีการปรับปรุง.)
พรีโม่

1
@primo ใช่แล้ว! นั่นเป็นวิธีที่คุณตรวจสอบเพื่อดูว่าคนพูดอะไรบางอย่าง ปัญหาดังกล่าวเกิดขึ้นอีกครั้งใน 90 ปี และย้อนกลับไปตอนนั้นการคาดหวังให้ผู้ใช้ของคุณยอมรับอินเทอร์เฟซที่แนะนำโดยรหัสที่ง่ายที่สุดก็ยังเจ๋ง เอชพีทำให้เรา RPN และเราชอบมัน การคิดอย่าง 201 * -er ทำให้คุณมีตัวอักษร 1280 ตัว
บูธตาม

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

ลิงก์ตอนนี้ตายแล้ว
programmer5000

5

Node / Meteor javascript + html + css + websocket: 1,105 ไบต์

นี่คือหนึ่งใช้ Node.js / ดาวตก เห็นได้ชัดว่าเขียนใน js, เรียลไทม์และใช้เว็บซ็อกเก็ต ใช้แพ็คเกจในตัวที่เป็นค่าเริ่มต้นของ meteor

มันอาจจะเล็กกว่านี้เยอะ นอกจากนี้มันยังคงติดตัวมาโดยรวมของ mongo (ไม่ใช่ว่าเป็นสิ่งที่ดี)

ภาพหน้าจอที่ใช้งานได้:

ป้อนคำอธิบายรูปภาพที่นี่

เพื่อดำเนินการติดตั้งดาวตก

ลินุกซ์:

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

Windows: win.meteor.com

ลอกแบบ repo ของฉันและเรียกใช้ดาวตก:

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 ไบต์ โปรดทราบว่าเบราว์เซอร์ไม่จู้จี้จุกจิกอย่างมาก - ฉันไม่รำคาญที่จะปิดแท็กและแน่นอนว่าคุณไม่จำเป็นต้องใช้สแลชที่ส่วนท้ายของแท็ก (ยกเว้นว่าโหนดต้องการหรือไม่) นอกจากนี้ฆ่าช่องว่างมากขึ้น! ฉันเห็นคู่รักในจาวาสคริปต์และมีวิธีมากเกินไปใน html
บูธโดย
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.