Created
August 21, 2015 14:44
-
-
Save niahoo/3ecb6fa0658e7dda3bb2 to your computer and use it in GitHub Desktop.
Calcul de temps d'attentes aux ascenseurs pour deux algorithmes différents
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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