Skip to content

Instantly share code, notes, and snippets.

@shadabahmed
Created March 23, 2013 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shadabahmed/5227612 to your computer and use it in GitHub Desktop.
Save shadabahmed/5227612 to your computer and use it in GitHub Desktop.
A CodePen by Shadab Ahmed.
<div class="rumor">
<div class="dropdown">
<label>Algorithm:</label>
<select id="algo">
</select>
&nbsp;
<label>Number of People:</label>
<input id="count" type="text" value="60" name="count"/>
<label>Speed:</label>
<select name="speed" id="speed">
<option value="10">Slow</option>
<option value="5">Medium</option>
<option value="1">Fast</option>
</select>
<input id="start" type="button" value="Start"/>
</div>
<div class="total">
Total Messages : <span id="msg_count">0</span><span class="message"></span>
</div>
<div class="cells">
</div>
</div>
class Arrow
@draw = (ele1, ele2)->
pt1 = getCenter(ele1)
pt2 = getCenter(ele2)
distance = getDistance(pt1, pt2)
$arrow = $('<div class=\"arrow\"></div>')
$('body').append($arrow)
$arrow.css({left: pt1[0], top: pt1[1],width: Math.floor(distance)})
rotation_trans = "rotate(#{Math.ceil(getSlope(pt1, pt2))}deg)"
$arrow.css('-webkit-transform', rotation_trans)
$arrow.css('-moz-transform', rotation_trans)
$arrow.css('transform', rotation_trans)
@delete = ($arrow)->
$arrow.remove()
getCenter = (ele)->
offset = ele.offset()
[offset.left + ele.width()/2, offset.top + ele.height()/2]
getSlope = (pt1, pt2)->
console.log [pt1[1]-pt2[1], pt2[0] - pt1[0]]
r = Math.atan2(pt2[1]-pt1[1], pt2[0] - pt1[0])
r *180 / Math.PI
getDistance = (pt1, pt2)->
Math.sqrt(Math.pow(pt1[0] - pt2[0],2) + Math.pow(pt1[1] - pt2[1],2))
class Grid
ele = undefined
[max_width, cell_count, cell_size] = [0, 0, 70]
[rows, cols, cell_count] = [0, 0, 0]
connections = {}
@init = (selector, n)->
[ele, cell_count] = [$(selector), n]
max_width = ele.width()
ele.addClass('grid')
calculateRowsCols()
addCells()
@connectCells = (cell1, cell2)->
[$cell1, $cell2] = [getCell(cell1), getCell(cell2)]
$cell1.addClass 'outgoing'
$cell2.addClass 'incoming'
connections["#{cell1}-#{cell2}"] = Arrow.draw($cell1, $cell2)
@disconnectCells = (cell1, cell2)->
[$cell1, $cell2] = [getCell(cell1), getCell(cell2)]
$cell1.removeClass 'outgoing'
$cell2.removeClass 'incoming'
Arrow.delete(connections["#{cell1}-#{cell2}"])
@clear = ->
ele.find('.incoming').removeClass('incoming')
ele.find('.outgoing').removeClass('outgoing')
for own key, id of connections
Arrow.delete(id)
@setCellText = (cellNo, text)->
getCell(cellNo).find('span.rumor-cnt').text(text)
addCells = ()->
tags = "<table><tbody>"
for x in [1..rows]
tags += "<tr>"
for y in [1..cols]
cellNo = (x - 1)*cols + y
break if cellNo > cell_count
tags += "<td><div class=\"container\">\
<span class=\"top left\">#{cellNo}</span>\
<span class=\"bottom right rumor-cnt\"></span>\
</div></td>"
tags += "</tbody></table>"
ele.html(tags)
calculateRowsCols = ()->
cols = Math.floor(max_width / cell_size)
rows = Math.ceil(cell_count / cols)
getCell = (cellNo)->
cellRow = Math.ceil(cellNo / cols)
cellCol = (cellNo % cols)
cellCol = cols if cellCol == 0
$cell = ele.find("table tr:nth-child(#{cellRow}) td:nth-child(#{cellCol})")
class Rumor
state = {}
total_messages = 0
timeout = undefined
@delay = 50
init = (n)->
clearTimeout(timeout)
Grid.init('.cells', n)
Grid.clear()
for i in [1..n]
Grid.setCellText(i,1)
state[i] = 1
@start = (algo, n)->
init(n)
total_messages = 0
algoCaller = ->
return if rumorSpread(state,n)
Grid.clear()
next_messages = algo(state, n)
$('.message').text("Person #{next_messages[0][0]} sends #{next_messages.length} message(s)") if next_messages[0] && next_messages[0][0]
for [sender, receiver, message_cnt] in next_messages
Grid.connectCells(sender, receiver)
Grid.setCellText(receiver, state[receiver] + message_cnt)
state[receiver] += message_cnt
total_messages += 1
timeout = setTimeout(algoCaller, Rumor.delay)
$("#msg_count").text(total_messages)
setTimeout(algoCaller, Rumor.delay)
rumorSpread = (state, n)->
spread = true
for own num, rumor_cnt of state
if rumor_cnt < n
spread = false
break
spread
algos = {}
algos[1] =
name: "All rumors in one message"
func: (state, n)->
this.max = 1 if !this.max || this.max > n
this.max_num = 1 if !this.max_num || this.max_num > n
messages = []
if max_num == n
for i in [1..n]
continue if i == max_num
messages.push [max_num, i, max - state[i]]
else
messages.push [max_num, max_num + 1, max]
this.max += 1
this.max_num += 1
messages
algos[2] =
name: "Only one rumor in one message"
func: (state, n)->
messages = []
this.itr = 1 if !this.itr || this.itr > n
for i in [1..n]
continue if i == this.itr
messages.push [this.itr, i, 1]
this.itr += 1
messages
$(->
for own index,algo of algos
$("#algo").append("<option value=\"#{index}\">#{algo.name}</option>")
$('#speed').change(->
Rumor.delay = parseInt($(this).val()) * 50
)
$('#start').click(->
$("#msg_count").text(0)
Rumor.delay = parseInt($('#speed').val()) * 50
Rumor.start(algos[$("#algo").val()].func, parseInt($("#count").val()))
)
)
@import "compass";
.arrow{
position: absolute;
z-index: 9999;
border-top: 1px solid black;
background-color: black;
width: 100px;
@include apply-origin(0,0);
@include translate3d(0,0,0);
@include border-radius(4px);
@include box-shadow(#EEE 0 0 10px 5px);
opacity: 0.4;
&:after{
content: "►";
position: absolute;
right: -5px;
color: #000000;
font-size: 10px;
top: -6px
}
}
.rumor{
font-family: "Helvetica";
.total{
padding: 10px;
#msg_count{
color: grey;
font-weight: bold;
}
.message{
padding: 0 50px;
}
}
}
.dropdown {
padding: 10px;
}
.grid table{
border-collapse:collapse;
tr{
position: normal;
}
tr td{
width: 60px;
height: 60px;
border: 1px solid grey;
font-size: 10px;
background: url( data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAA3UlEQVR4Xu3asQ2DMBAF0LMIBVVGSEvPAs4GjMBoGSEjmAWoaRkhtaV/ucJSWqL4ohD9L53c3uOusUxQVdmTYRjOdtytovglWY3Lsjz29nWSnTFoad41sXykq1V1wKt5f4R4AORnQgABBBAQHQDpa4B1XefagL7vj71CquoLAOAKAMAJEEAAAQQQQAABBBBAAO8D/z0BAggggAACCCCg6zr1B/B9gIBbqanU8QA557ltW/EB+N8HpqZpBMB0yBX6ZHUMfrFjqw1IdkTxTwKwVZ+AZfzCHysphDC+o30CYFgMjsAPnYQAAAAASUVORK5CYII=) center center no-repeat;
&.incoming{
background-color: #B3D1B2;
}
&.outgoing{
background-color: #F7D4BE;
}
.container{
position: relative;
width: 100%;
height: 100%;
span{
position: absolute;
padding: 3px;
&.top{
top: 0px;
}
&.bottom{
bottom: 0px;
}
&.left{
left: 0px;
color: blue;
}
&.right{
right: 0px;
color: green;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment