Skip to content

Instantly share code, notes, and snippets.

@niahoo
Created August 21, 2015 14:44
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 niahoo/3ecb6fa0658e7dda3bb2 to your computer and use it in GitHub Desktop.
Save niahoo/3ecb6fa0658e7dda3bb2 to your computer and use it in GitHub Desktop.
Calcul de temps d'attentes aux ascenseurs pour deux algorithmes différents
<!doctype html>
<html lang='en-GB'>
<head>
<meta charset='utf-8'>
<title>Ractive test</title>
</head>
<body>
<style type="text/css" media="screen">
#container {
margin:auto;
font-family: monospace;
}
svg {
background: white;
}
circle.lowerFirst {
fill: red;
fill-opacity: 0.5;
stroke-width: 0.5px;
stroke: red;
}
circle.upperFirst {
fill: blue;
fill-opacity: 0.5;
stroke-width: 0.5px;
stroke: blue;
}
circle.equal {
fill: #e4e4e4;
stroke-width: 0.5px;
stroke: #1d1d1d;
}
circle.clickBait {
fill: white;
fill-opacity: 0;
cursor: pointer;
}
circle.clickBait:hover {
fill: white;
fill-opacity: 0;
cursor: pointer;
stroke: green;
stroke-width: 2px;
}
circle.clickBait.selected {
fill: white;
fill-opacity: 0;
stroke: green;
stroke-width: 2px;
}
.infos {
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.infos div {}
</style>
<!--
1. This is the element we'll render our Ractive to.
-->
<div id='container'></div>
<!--
2. You can load a template in many ways. For convenience, we'll include it in
a script tag so that we don't need to mess around with AJAX or multiline strings.
Note that we've set the type attribute to 'text/ractive' - though it can be
just about anything except 'text/javascript'
-->
<script id='template' type='text/ractive'>
<div class='svg-wrapper'> <!-- needed to determine size of SVG element in Firefox -->
<svg width='{{config.svgWidth}}' height='{{config.svgHeight}}'>
<g id="graph" transform='translate({{config.margin.left}},{{config.margin.top}})'>
{{#each scenari:i,scenario}}
<g class='marker' transform='translate({{ xScale(lowerFloor) }},{{ yScale(upperFloor) }})'>
{{#if lowerFirstTime.sum === upperFirstTime.sum}}
<circle class='equal' r='{{rScale(lowerFirstTime.sum)}}'/>
{{else}}
<circle class='lowerFirst' r='{{rScale(lowerFirstTime.sum)}}'/>
<circle class='upperFirst' r='{{rScale(upperFirstTime.sum)}}'/>
{{/if}}
<circle on-click='select(i,scenari[i])' class='{{#if scenari[i].selected}}selected {{/if}}clickBait' r='{{rScale(localMaxTime) + 1}}'/>
</g>
{{/each}}
</g>
</svg>
</div>
<div class="infos">
<div>
<h4>Étages</h4>
<p>Étage haut : {{scenari[selected].upperFloor}}</p>
<p>Étage bas : {{scenari[selected].lowerFloor}}</p>
<p>Ratio: {{scenari[selected].upperFloor / scenari[selected].lowerFloor}}</p>
</div>
<div>
<h4>Attentes « bas premier »</h4>
<p>Attente Étage haut : {{scenari[selected].lowerFirstTime.upperFloorTime}}</p>
<p>Attente Étage bas : {{scenari[selected].lowerFirstTime.lowerFloorTime}}</p>
<p>Cumul : {{scenari[selected].lowerFirstTime.sum}}</p>
</div>
<div>
<h4>Attentes « haut premier »</h4>
<p>Attente Étage haut : {{scenari[selected].upperFirstTime.upperFloorTime}}</p>
<p>Attente Étage bas : {{scenari[selected].upperFirstTime.lowerFloorTime}}</p>
<p>Cumul : {{scenari[selected].upperFirstTime.sum}}</p>
</div>
</div>
</script>
<!--
3. You can always get the most recent stable version from the URL below.
If you want the newest features (unstable!), use the 'edge' version instead:
http://cdn.ractivejs.org/edge/ractive.min.js
If you need IE8 support, change 'ractive' to 'ractive-legacy'.
-->
<script src='http://cdn.ractivejs.org/latest/ractive.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!--
4. We've got an element in the DOM, we've created a template, and we've
loaded the library - now it's time to build our Hello World app.
-->
<script>
// On compte les temps d'attente cumulés de deux personnes, l'une étant à un
// étage "lowerFloor" et l'autre étant à un étage supérieur "upperFloor" quand
// l'ascenseur commence au RdC (floor = 0). Les deux personnes souhaitent se
// rendre au RdC
// L'algo "lowerFirst" va d'abord chercher la personne la plus basse, la fait
// descendre, et remonte chercher la personne la plus haute. L'algo "upperFirst"
// va d'abord chercher la personne la plus haute et s'arrête au passage prendre
// la personne la plus basse.
// On compte uniquement le temps d'attente, une fois la personne dans
// l'ascenseur on ne compte pas son attente, car les deux algos permettentent à
// la personne, une fois dans l'ascenseur, de faire uniquement un trajet "leur
// étage" -> "sol", avec potentiellement un arrêt, mais sans remonter
// inutilement quand il est dans la cabine.
// Le "temps" d'attente est simplement compté en nombre d'étages
var config = {
maxFloor: 10,
svgWidth: 1000,
svgHeight: 750,
minRadius: 2,
maxRadius: 10,
margin: {top:20,right:20,bottom:20,left:20}
}
d3.select('#container').style('width',config.svgWidth+'px')
function lowerFirstTime(lowerFloor, upperFloor) {
// la personne à l'étage du bas attends simplement l'assenceur monter à son
// étage
var lowerFloorTime = lowerFloor
// la personne d'en haut attend que l'ascenseur aille à l'étage du bas, le
// redescende et remonte à lui
var upperFloorTime = lowerFloor + lowerFloor + upperFloor
// on renvoie le cumul
return {
lowerFloorTime: lowerFloorTime,
upperFloorTime: upperFloorTime,
sum: lowerFloorTime + upperFloorTime
}
}
function upperFirstTime(lowerFloor, upperFloor) {
// la personne d'en bas attend que l'ascenseur aille à l'étage du haut puis
// redescende à lui
var lowerFloorTime = upperFloor + (upperFloor - lowerFloor)
// la personne à l'étage du haut attends simplement l'assenceur monter à son
// étage
var upperFloorTime = upperFloor
// on renvoie le cumul
return {
lowerFloorTime: lowerFloorTime,
upperFloorTime: upperFloorTime,
sum: lowerFloorTime + upperFloorTime
}
}
// Pour chaque position possible de upperFloor, on calcule les temps pour chaque
// position possible de lowerFloor sous cet upperFloor
var scenari = []
var maxTime = 0
var minTime = 0
for(var upperFloor=2; upperFloor <= config.maxFloor; upperFloor += 1) {
for(var lowerFloor=1; lowerFloor <= upperFloor; lowerFloor += 1) {
var lt = lowerFirstTime(lowerFloor, upperFloor)
var ut = upperFirstTime(lowerFloor, upperFloor)
maxTime = Math.max.apply(null, [maxTime, lt.sum, ut.sum])
scenari.push({
lowerFloor: lowerFloor,
upperFloor: upperFloor,
lowerFirstTime: lt,
upperFirstTime: ut,
localMaxTime: Math.max(lt.sum, ut.sum)
})
}
}
// On va représenter les données sur un graphe 2D présentant 3 dimensions : en
// abscisses le lowerFloor, en ordonnées l'upperFloor et la taille du point à
// leur rencontre indiquera le temps d'attente. On pourrait également faire un
// graphe en 3D mais ce n'est pas plus lisible comparé à la difficulté
// supplémentaire.
function debugScale(scaleName, scale) {
/**/
return scale
/*/
return function(value) {
var scaled = scale(value)
console.log('%s %s -> %s',scaleName, value, scaled)
return scaled
}
/**/
}
var xScale = debugScale('xScale',d3.scale.linear()
.domain([0, config.maxFloor - 1])
.range([0, config.svgWidth - config.margin.left - config.margin.right]))
var yScale = debugScale('yScale',d3.scale.linear()
.domain([0, config.maxFloor])
.range([config.svgHeight - config.margin.top - config.margin.bottom, 0]))
var rScale = debugScale('rScale',d3.scale.linear()
.domain([0, maxTime])
.range([config.minRadius, config.maxRadius]))
// var xScale = d3.scale.linear()
// .domain([0, config.maxFloor - 1])
// .range([0, config.svgWidth])
// var yScale = d3.scale.linear()
// .domain([0, config.maxFloor])
// .range([config.svgHeight, 0])
// var rScale = d3.scale.linear()
// .domain([0, maxTime])
// .range([config.minRadius, config.maxRadius])
function keypath() {
return Array.prototype.slice.call(arguments).join('.')
}
var ractive = new Ractive({
// The `el` option can be a node, an ID, or a CSS selector.
el: '#container',
// We could pass in a string, but for the sake of convenience
// we're passing the ID of the <script> tag above.
template: '#template',
// Here, we're passing in some initial data
data: {
config: config,
yScale: yScale,
xScale: xScale,
rScale: rScale,
scenari: scenari,
selected: 0
},
select: function(i,scenario) {
console.log('select scenario', scenario)
var current = this.get('selected')
this.set('selected', i)
// chaque scenario a une propriété selected false (ou undefined) ou
// true afin de pouvoir mettre une classe sur les cercles
this.set(keypath('scenari',current,'selected'), false)
this.set(keypath('scenari',i,'selected'), true)
console.log('selected ?',this.get(keypath('scenari',i)))
}
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment