magwo / elevatorsaga Goto Github PK
View Code? Open in Web Editor NEWThe elevator programming game!
Home Page: http://play.elevatorsaga.com
License: MIT License
The elevator programming game!
Home Page: http://play.elevatorsaga.com
License: MIT License
It seems like there are certain cases where people will not get on elevators.
This is the simplest way to reproduce it that I've found:
{
init: function(elevators, floors) {
var elevator = elevators[0]; // Let's use the first elevator
elevator.on("idle", function() {
// The elevator is idle, so let's go to all the floors (or did we forget one?)
});
},
update: function(dt, elevators, floors) {
// We normally don't need to do anything here
}
}
Adding elevator.goToFloor(0);
to the idle event will make them get on.
Hi,
First - Cool game!!!
I think it is reasonable that when an elevator stops at a floor but has no room for the user to get on it, he/she should press the button again after the elevator has left the floor.
This is actual real life behavior.
without this, the current API doesn't expose an option to know that someone is still waiting at that floor
Thanks
If I use browser zoom - around 130% - then it exceed screen.
At this moment, if an elevator doesn't listen to any event, then people treat that elevator as "out of order" (not existing). But there should be a better way of defining how many elevators are working, or at least document how to make this happen (possibly by the same way I described as doing).
In the documentation this method claims to return a floating point between 0 and 1. However when I call it i have been getting floats anywhere from 1000 to 2000 if there are passengers and 0 if the elevator is empty.
Supporting this will require some refactoring and changes to the movePhysically function in the Movable.
This is a game I have in mind for long. I was really excited to see it finally appeared. While as I tried several levels and the code scale grows, I found it really difficult for me to write correct Javascript, as I'm, in most time, a Haskell/Racket/Ruby programmer.
Javascript is a language full of traps that drives me crazy on it. Most of my time were wasted on debugging with Javascript's terrible design and I could not focus well on the algorithm, which is really not what I wanted. You know, as in Javascript, weakly typed, everything just executes without yielding any error messages, while it's just not doing what I think it should do and gives me a totally wrong result, or it stuck at some point. These problems are hard to debug.
I don't even mind to learn a language that compiles to Javascript for just this game because I really want to play it well. Anyway, if you don't mind to add such functionality to allow players to write code in a language that compiles to Javascript, I would suggest Livescript. Though purescript is what I want most (because it's mostly the same as Haskell), but Livescript is much more popular and well supported.
Thank you anyway for bringing such a wonderful game. I was just a little bit tried on struggling with those Javascript traps 😭
Horizontal scrolls are ugly. And inconvenient.
Unless there's a good reason to have such a large lobby (there isn't on level 1 and 2), maybe you could make this work an an 1280 X 800 screen without the need to have the horizontal scroll...
Should override the Ctrl/Cmd+S binding in browser, so that the code is saved.
I have started making a for loop for floors and it seems to have frozen the animation :
{
init: function(elevators, floors) {
var calledElevator = [];
var calledElevatorUp = [];
var calledElevatorDown = [];
var elevator = elevators[0]; // Let's use the first elevator
for (i = 0; i < floors.length; i++) {
floors[i].on("up_button_pressed", function() {
calledElevatorUp.push(floors[i].floorNum);
calledElevator.push(floors[i].floorNum);
})
floors[i].on("down_button_pressed", function() {
calledElevatorDown.push(floors[i].floorNum);
calledElevator.push(floors[i].floorNum);
})
}
},
update: function(dt, elevators, floors) {
// We normally don't need to do anything here
}
}
Love to have API access to a challenge or world object that would allow adaptive algorithms to know the specs of the current challenge -- in particular, challenge type, challenge parameters, spawn rate, and elevator sizes (though the elevator size would probably fit better in the elevator object.)
Currently we have to resort to counting floors and elevators or scraping the challenge number from the URL, but that's not too pretty... plus needs adjustment with each change to challenges.js.
From user code, it is not possible to get the current floor number.
.loadFactor
is returning numbers in the thousands when people are in elevators, not a number between 0 and 1 as indicated in the documentation.
I thought it might be good to get a thread going of interesting additional challenges/levels. Here are some of my ideas.
Can't continue the game because of this problem.
There is a problem with your code: ReferenceError: floor is not defined
at Object.eval (eval at (http://play.elevatorsaga.com/app.js:68:35), :8:13)
at Object.el.trigger (http://play.elevatorsaga.com/libs/riot.js:45:12)
at Object.elevatorInterface.checkDestinationQueue (http://play.elevatorsaga.com/interfaces.js:15:35)
at http://play.elevatorsaga.com/world.js:168:64
at Function.St (http://play.elevatorsaga.com/libs/lodash.min.js:23:147)
at Object.world.init (http://play.elevatorsaga.com/world.js:168:15)
at updater (http://play.elevatorsaga.com/world.js:194:31)
Pasting this code into the game and pressing 'apply' makes firefox non-responsive, and chrome's tab to crash.
marado/elevator-saga-solutions@e13486a
I probably have a bug in there, but the game's parser probably should be more robust...
Sometimes I want to change my code according to certain passenger behavior but it is really hard to reproduce if the passengers change every time you restart a challenge.
My suggestion is to allow "Freeze" a challenge. A frozen challenge will generate the exact same passenger placement and behavior every time but passing a frozen challenge will not count as passing the challenge. That is to pass a challenge you must pass it in an unfrozen state.
For example, challenge 12 states "Challenge #12: Transport 80 people and let noone wait more than 17 seconds" however the failure condition is anyone waiting more than 16.5 seconds.
Using html with table layout is insane!
Generation preferrably in browser. It's so relaxing to not have a build stage.
One can easilly "cheat on" using loadFactor by just counting the number of button presses on an elevator.
Since it is not plausible that every person that enters an elevator presses the floor button (when it is already pressed), please add some logic here to humanize the passengers.
Thanks!
Some of us crazy people traverse the web with Javascript disabled (whitelisting sites that need it). It would be nice to have a <noscript> message instead of, well, nothing.
Apparently the requireUserCountWithinMoves() challenges can always be completed with some ridiculous solutions. This could be ok for one or two challenges, but the most interesting challenge would probably be one that requires both efficiency and speed - requiring a number of transported passengers with a limited number of moves while not letting them wait long.
I have found that the passing_floor event sometimes has floorNum = -1
Often (every 200s or so) on the challenge 18 when the elevator comes from a high floor to ground floor it seems that the passing_floor is triggered twice
using the code snippet similar to below the log shows
LOG
prevfloor:1 floorNum:0 dir:down
prevfloor:0 floorNum:-1 dir:down
elevator.on("passing_floor", function(floorNum, direction) {
console.log('prevfloor:' + prevFloor + ' floorNum:' + floorNum + ' dir:' + direction);
prevFloor = floorNum;
});
I'm wondering whether it is possible to add a direction
method to the elevators, which returns "up"
, "down"
or "stopped"
, so that the programmers can use this information to make better decision.
I understand that current passing_floor
event provides direction
as an argument to the callback, but I hope this information to be more accessible on other events as well (say when a floor's up button is pressed, programmers might want to know which elevator is coming to its direction).
I see that programmers can try to manage this information themselves with goingUpIndicator
and goingDownIndicator
, but the purpose of those indicators is to tell passengers whether to get on or not. It would be nice to provide the direction
to the programmer, so that they can easily set the indicators accordingly.
Hi,
Awesome game. Not sure if this is a bug in my solution or in game code, but challenge 5 stops randomly after some time. I.e. it never reaches success or fail screen, elevators just stop in the middle of transition doing nothing. Floor buttons work fine, but game time does not progress.
Clicking 'apply' resets the game, but it hangs again after some time.
http://play.elevatorsaga.com/#challenge=5
{
init: function(elevators, floors) {
var onIdle = function(elev){
elev.goToFloor(0);
};
var onFloorButtonPressed = function(elev, floorNum){
elev.goToFloor(floorNum);
}
var onPassingFloor = function(elev, floorNum, direction){
var pressed = elev.getPressedFloors();
if (pressed.length > 0)
{
if (pressed.lastIndexOf(floorNum) > 0)
elevator2.goToFloor(floorNum, true);
}
}
var setUp = function (el){
el.on("idle", function() {
onIdle(el)
});
el.on("floor_button_pressed", function(floorNum) {
onFloorButtonPressed(el, floorNum);
})
el.on("passing_floor", function(floorNum, direction) {
onPassingFloor(el, floorNum, direction);
});
}
setUp(elevators[0]);
setUp(elevators[1]);
setUp(elevators[2]);
setUp(elevators[3]);
},
update: function(dt, elevators, floors) {
// We normally don't need to do anything here
}
}
Challenge #1
The intent:
Bugs:
Code to reproduce:
{
init: function(elevators, floors) {
Array.prototype.contains = function (item) {
for (var i = 0; i < this.length; i++)
if (this[i] === item)
return true;
return false;
};
var elevator = elevators[0];
elevator.on("passing_floor", function(floorNum, direction) {
console.log("Passing floor: " + floorNum + " with destinationQueue: " + elevator.destinationQueue);
if(elevator.getPressedFloors().contains(floorNum)){
/*note:
Sometimes destinationQueue has two entries, I assume it shouldn't.
When this happens the invalid entry is very close to but not 1 (the floor we are passing).
*/
//var originalDestination = elevator.destinationQueue[0]; //eventually get's stuck at floor 1
var originalDestination = elevator.destinationQueue.filter(function(x){ return x === 0 || x === 2; })[0]; //workaround
elevator.stop(); //clears destinationQueue but passengers do not exit
elevator.destinationQueue.push(originalDestination); //continue to originalDestination
}
});
elevator.on("stopped_at_floor", function(floorNum) {
if(floorNum === 0)
elevator.destinationQueue.push(2);
else if(floorNum === 2)
elevator.destinationQueue.push(0);
});
},
update: function(dt, elevators, floors) {
elevators[0].checkDestinationQueue();
}
}
As a more convenient alternative to the existing up_button_pressed
and down_button_pressed
events, also fire a hall_button_pressed
event.
up_button_pressed
and down_button_pressed
don’t pass any parameters to their callbacks. hall_button_pressed
would pass one parameter, direction
, which would be either "up"
or "down"
. This allows it to do the work of both of the other events.
Right now, my algorithm handles hall button presses with this code:
floors.forEach(function(floor) {
floor.on("up_button_pressed", function() {
handleHallButtonPress(floor, "up");
});
floor.on("down_button_pressed", function() {
handleHallButtonPress(floor, "down");
});
});
function handleHallButtonPress(floor, direction) {
// …
}
With the addition of hall_button_pressed
, I could simplify it to this:
floors.forEach(function(floor) {
floor.on("hall_button_pressed", function(direction) {
// …
});
}
It is true that hall_button_pressed
is redundant with the other events, but I think that’s okay because it’s the more fundamental and generally useful event. I think most people will use just the hall_button_pressed
event, and only specialized algorithms that treat up and down movement very differently will use the other two events instead.
Does this sound like a good addition to the API?
The challenges should scale more quickly to block any simple implementations from getting far.
Perhaps an early move efficiency challenge.
Repo has no explicit license
Hacker News commenter LoSboccacc mentioned a bug 5 days ago where people don’t reconsider entering the elevator when an elevator changes its up/down indicator lights while on a floor, even though that should tempt some people into entering the elevator.
After that comment was written, #18 “People not getting on elevator” was fixed with 6ce62a1. But I don’t think that 6ce62a1 fixes this issue, because in that change’s code, I don’t see any events triggered by changes in an elevator’s up/down indicator lights (the indicatorstate_change
event).
I've noticed that some of my "best" solutions sometimes hold passengers hostage on the elevator, ignoring their floor for an extended period of time if it's for the good of the system. I think average time spent on an elevator would be an important metric to track, along the same lines as the existing average time spent waiting for an elevator.
Edit: I suppose the most beneficial metric for measuring an elevator system's effectiveness would be the average time to destination, which would include time spent waiting for and getting to the desired floor.
When people press the floor buttons in the elevator the little numbers light up visually to indicate which floors have been pressed but there is no way to directly get an array of those numbers in the code. Instead one would have to manually keep track of all those which is rather inconvenient, especially when the system actually already exists.
Should probably do something about that.
The floor call indicator arrows currently look like this (on challenge 1):
But it doesn’t make sense for floor 0 to have a down button, or the topmost floor to have an up button. You can’t go any farther, and thankfully the simulated users never press that button.
Thus, I suggest that those two impossible arrows be hidden:
Hopefully, hiding those arrows will guide programmers into handling the floor call button presses better, because they will instantly realize that no users will ever press those two hidden buttons.
You can hide the icons with the CSS visibility: hidden;
so that the top floor’s down indicator is still aligned with other down indicators. The other part of the implementation is changing the floor-template
in index.html
so that just those two indicators get the appropriate class added to them, and possibly also changing the data that is passed to that template.
Hey there,
the visually displayed floor indicators ( as introduced by pull request #28) seem to be reversed -when logging elevator.goingUpIndicator() or elevator.goingDownIndicator() I get the opposite of what is visually displayed.
First, congratulations I been wanting to simulate elevators for a long time, and this game covers so much of the fun of it.
Could the core simulate some random behaviored people? I mean people flooding the elevator (over capacity) or who presses buttons twice, or buttons outside the current scheduled movement, might trick some implementations.
They push the button (lights up green)
Elevator arrives, green light dims
Nobody gets in
If an elevator going up stops at a floor (to unload passengers), passengers waiting outside of the elevator will enter, even if they need to go down.
Using the following code:
{
init: function(elevators, floors) {
var elevator = elevators[0];
elevator.goToFloor(2);
elevator.on("passing_floor", function(floorNum, direction) {
console.log("Passing floor "+floorNum);
elevator.stop();
});
},
update: function(dt, elevators, floors) {}
}
You would expect to see only Passing floor 1
printed, and then nothing else.
The actual result is sometimes it prints:
Passing floor 1
Passing floor 2
Passing floor 1
And sometimes even:
Passing floor 1
Passing floor 2
Passing floor 1
Passing floor 2
Passing floor 1
You can try this in challenge 1
The floor's down_button_pressed event doesn't seem to be getting fired, or at least the floor.on("down_button_pressed", function(){})
doesn't seem to work...
I never see console logs for Down button pressed on floor: X
which seems a little odd to me...
Tested this on a Safari 8.0.2 browser on a Mac on Yosemite - having looked at floors.js I can not for the life of me figure out why up
would fire the event, but down
not... I'll start throwing some breakpoints in and stepping through...
{
init: function(elevators, floors) {
var elevator = elevators[0]; // Let's use the first elevator
elevator.on("idle", function() {
if (elevator.destinationQueue.length == 0) {
elevator.goToFloor(2);
} else {
elevator.goToFloor(elevator.destinationQueue[0]);
}
});
elevator.on("floor_button_pressed", function(floorNum) {
console.log("In Elevator button pressed: " + floorNum);
elevator.destinationQueue.push(floorNum);
elevator.checkDestinationQueue();
});
var floor = floors[0];
floor.on("up_button_pressed", function() {
console.log("Up button pressed on floor: " + floor.floorNum());
elevator.destinationQueue.push(floor.floorNum());
elevator.checkDestinationQueue();
});
floor.on("down_button_pressed", function() {
console.log("Down button pressed on floor: " + floor.floorNum());
elevator.destinationQueue.push(floor.floorNum());
elevator.checkDestinationQueue();
});
},
update: function(dt, elevators, floors) {
// We normally don't need to do anything here
}
}
No matter what I do, even with the default script from level one, as soon as I press start the moves counter increases to six, before I get a change to call goToFloor() on any elevator
I've spent ages trying to find out what behaviour of my elevators causes the max wait time to run out on the levels. It is really hard to debug such problems without #34 or having a way to spot the waiting time of each passenger easily. Maybe changing the colour of each passenger from white through blue, green, up to red as a function their current wait time? Would make the game much nicer to look at and maybe even provide more motivation for some people to keep the elevators moving in the minimum moves challenges.
The floor objects need a safe interface facade for user programming. Currently the real floor object is exposed, which can lead to strangeness if changed by user code.
It would be handy to know whether or not a floor's up or down button is illuminated for making a decision in events like passing_floor. I could track it myself, but it's a pain especially since the simulation is clearly already tracking it. Right now I'm using floor.buttonStates.up/down, but I feel like that's cheating since it's not explicitly mentioned in the API.
It would be useful to have an event fire when an elevator is about to pass a floor, at the last possible opportunity to stop at the floor without reversing the elevator. Should be easy to implement now that the elevators support changing destination arbitrarily whenever.
Should try to not change the URL when we enter, or avoid pushing to history?
It seems I sometimes get an undefined floor object in these events.
Code like
for (i = _i = 0, _len = floors.length; _i < _len; i = ++_i) {
floor = floors[i];
floor.on('up_button_pressed down_button_pressed', function(event) {
console.log(event)
console.log(i)
activeFloors.push(i);
});
}
reports one floor every time. In my case it's 8
It feels like cheating to expose the exact number of passengers. However, an approximate weight and load factor could be exposed, to emulate a real-world weight sensor.
The elevator up/down indications that are set by goingUpIndicator()
and goingDownIndicator()
aren't visible on the elevator display. An arrow on the elevator itself would help when writing scripts that use this functionality.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.