This is another state-driven simulation.

The crux of the simulation:
This code simulates a small school campus with one teacher, one classroom,
and three students. The tearcher waits in the classroom until there are
enough students in the room to begin the class. The teacher then tries to
transfer knowledge to the student(s). At the end of the semester (3 days)
the teacher gives a test over all of the knowledge available and scores the
students performance.

Ths students go about their daily activities (sleep, goto class, study, go back
to the dorm). Students will get upset when they have to go back to the
dorm because they got to class to late (the classroom doors are closed when
the class is filled).

This exampe demonstraits more complex inteteractions than the earlier miners
example that can found on this site.

Some of the objects are too tightly coupled. You can loosen the coupling on
your own by creating objects to handle the coupled interactions.

Code:
<!doctype html>
<html>
<head>
<title>
A less-simple state-driven simulation
</title>
<style type='text/css'>
body {font-family:Tempus Sans ITC,Times New Roman,Times, Serif;
	background: #23292e;
	color:#c5c5c5;
	margin: 20px;
}
textarea {
	background: #e8ed90;
	border: 1px solid #a9ae54;
	padding: 15px;
	width: 500px;
	font-weight: bold;
	font-size: 14px;
	color: #7c7834;
}
td {padding-left:5px;}
#dormroom {width:100px;height:200px;background-color:navy;color:white;}
#commonroom {width:100px;height:200px;background-color:blue;color:white;}
#in_class {width:100px;height:200px;background-color:red;color:white;}
#goto_class {width:200px;height:75px;background-color:red;color:white;}
#goto_dorm {width:200px;height:75px;background-color:blue;color:white;}
h1 span {font:normal normal 14px/14px Tempus Sans ITC,Times New Roman,Times, Serif;}
</style>
<script type="text/javascript">
/*
state driven objects.
*/
var Campus ={								//this is an eviornment object. It coordinites objects actions.
	classrooms:[],
	test_day:false,							//used to control testing
	enter_room:function(s,c){					// students enter a class through this method.
		for(var i=0;i<Campus.classrooms.length;i++){
			if(Campus.classrooms[i].course_name==c){
				if(Campus.classrooms[i].ready==false){
					Campus.classrooms[i].add_student(s);
				}else{
					s.stamina=1;
					s.symbol="@!#";
				}
			}
		}
	},
	exit_room:function(s,c){					// students exit normally with this method
		for(var i=0;i<Campus.classrooms.length;i++){
			if(Campus.classrooms[i].coursename==c){
				Campus.classrooms[i].drop_student(s);
			}
		}	
	},
	add_room:function(c){						// a way to add rooms
		Campus.classrooms.push(c);
	},
	remove_room:function(c){					// a way to remove rooms
		for(var i in Campus.classrooms.length){
			if(Campus.classrooms[i]==c){
				Campus.classrooms.splice(i,1);
			}
		}
	}
}

function ClassRoom(course_name,min)				// there is no explicit doors variable in the code. closed doors is a concept.
{									// teaching only occurs after the classroom doors close.
	if(min==null)min=1;					// min is the minimun # of students before doors close.
	this.days_to_test=3;					// 3 day until testing starts
	this.min=min;
	this.course_name = course_name;			// identifies the classroom
	this.ready=false;						// true when the doors close.
	this.students=[];
	this.add_student=function(s){				//only smooth way for a student to enter a room
		this.students.push(s);
log("added "+s.name);
		if(this.students.length>=this.min){
			this.ready=true;
		}
		if(this.days_to_test<1){
			this.ready=false;
		}
	}
	this.drop_student=function(s){			//only smooth way for a student to exit a room
		for(var i in this.students){
			if(this.students[i]==s){
				students.splice(i,1);
log("dropped "+s.name);
			}
		}
		if(this.students.length<this.min){
			this.ready=false;
		}
	}
	this.end_class=function(){				// open the doors and kick every one out - not a smooth move.
		for(var i=0;i<this.students.length;i++){
			this.students.stamina=1;
		}
		this.students=[];					// roughly kick all students out of the classroom
		this.ready=false;					// classroom doors are open
log("dropped all");
	}
	this.teach=function(lesson){				// lesson is knowledge = {idea name: idea details}
		for(var i=0;i<this.students.length;i++){
			if(this.teachable(this.students[i])){
				this.students[i].knowledge[lesson.name]=lesson[lesson.name];   // transfer knowledge to the student
			}
		}
	}
	this.teachable=function(s){				// controls student learning
		if(s.intelligence>Math.random()*20)		// simple-random 'did you get that?'
			return true;
		return false;
	}
	this.in_class=function(){				// count the number of students in the classroom
		return this.students.length;
	}
	this.ask=function(n){					// the end of semester test
		var r="<font size='+1'><u>Define '"+n+"'?</u></font><br>";
		for(var i=0;i<this.students.length;i++){
			if(this.students[i].knowledge[n]!=undefined){						// student knows the answer.
				r+=this.students[i].name + ": "+this.students[i].knowledge[n]+"<br>";
				this.students[i].score++;
			}else{												// student has no clue.
				if(Math.random()>.3){
					r+=this.students[i].name + ": ???<br>";
				}else{
					r+=this.students[i].name + ": "+flippantQuess[Math.floor(Math.random()*flippantQuess.length)]+"<br>"
				}
			}
		}
		return r;
	}
}

function Teacher(state,name,knowledge){				// the teacher object - transfers it knowledge to students 
	if(knowledge==null)knowledge=[];
	this.name = name;
	this.intelligence=Math.floor(Math.random()*10)+10;
	this.knowledge=knowledge;
	this.symbol="";
	this.lesson=0;
	this.students = 0;
	this.teaching=false;
	this.answers="";
	this.reknown=0;			// not used
	this.hours_max=3;
	this.classroom=null;
	this.state=state;
}

function Student(state,name,knowledge){				// student objects - learns from a teacher
	if(knowledge==null)knowledge=[];
	this.symbol="";
	this.name = name;
	this.intelligence=Math.floor(Math.random()*10)+10;
	this.knowledge=knowledge;
	this.reknown=0;			// not used
	this.stamina = Math.floor(Math.random()*10);
	this.fully_rested = Math.floor(Math.random()*10)+5;
	this.learning=false;
	this.score=0;
	this.state=state;
}

var teacher_state={							//  bunch of states. all teachers actions are cotrolled through states
	waiting:function(){						// wait for the classroom to fill up - snoozing encouraged
		this.statename="waiting";
		this.symbol="Zzz";
		if(this.classroom!=null){
			if(this.classroom.days_to_test<1){
				this.state=teacher_state.testing;
				Campus.test_day=true;
			}else	if(this.classroom.ready){
				this.state=teacher_state.teach;
			}
		}
	},
	teach:function(){							// try to transfer randomly selected knowledge to the students
		this.statename="teach";
		this.symbol="!";
		if(this.lesson>this.hours_max){			// shutdown the class if over the union enforced max teaching hours
			this.lesson=0;
			this.state=teacher_state.end_class;
		}else{							// teach a random lesson
			var kn = this.knowledge[Math.floor(Math.random()*this.knowledge.length)];
			this.classroom.teach(kn);
			this.lesson++;
		}
	},
	teach2:function(){						// try to transfer knowledge to students in an orderly manner - not used
		this.statename="teach";
		if(this.lesson>=this.knowledge.length){		// go through all the lessons
			this.lesson=0;
			this.state=teacher_state.end_class;
		}else{
log("teaching");
			this.classroom.teach(this.knowledge[this.lesson]);
			this.lesson++;
		}
	},
	end_class:function(){						// class is over. say bye. one day closer to the test.
		this.statename="end_class";
		this.symbol="Bye"
		this.classroom.end_class();
		this.classroom.days_to_test--;
		this.state=teacher_state.waiting;
	},
	testing:function(){						// keep the noise down
		this.statename="testing";
		this.symbol = " shh";
log("("+this.classroom.in_class()+" in class)");
		if(this.classroom.in_class()>2){			// wait for at least 3 students to show up
			this.state=teacher_state.run_test;
		}
	},
	run_test:function(){						// test time
		this.statename="run_test";
		this.symbol = "";
		if(this.expando1==undefined){				// use the expand to make is one-off method
			if(glb_questions>this.knowledge.length){  // don't trust global data
				glb_questions=this.knowledge.length;
			}
			if(glb_questions<1){
				glb_questions=1;
			}
			this.expando1=0;
			this.answers="<font size='+1'>A "+glb_questions+" Question TEST:</font><br>"  // the rest is assigning/answering test questions
			for(var i=0;i<glb_questions;i++){
				this.answers+=this.classroom.ask(this.knowledge[Math.floor(Math.random()*this.knowledge.length)].name) + "<br>";
			}
			this.answers+="Final Results:<br>";
			for(var i=0;i<this.classroom.students.length;i++){
				this.answers += this.classroom.students[i].name +": "+this.classroom.students[i].score+"/"+glb_questions+ " ("+Math.floor(100*this.classroom.students[i].score/glb_questions)+"%)<br>";
			}
			this.answers+="<hr>";
			this.answers+="** Refresh the page to run again **";
			glb_rungame=false;
		}
	}
}
var student_state={								// a bunch of states. all student actions are controlled through states
	in_dorm_room:function(){						// a nice place to rest
		this.statename="in_dorm_room";
		this.symbol="Zzz";
		this.stamina++;
		if(this.stamina>this.fully_rested){
			this.state = student_state.in_common_room;
		}
	},
	in_common_room:function(){						// all students use the common room to come and go
		this.statename="in_common_room";
		this.symbol="";
		if(this.stamina>this.fully_rested){
			this.state = student_state.goto_class;
		}else{
			this.state = student_state.in_dorm_room;
		}
	},
	goto_class:function(){							// going to class.
		this.statename="goto_class";
		this.symbol="hi ho";
		this.state = student_state.in_class;
	},
	goto_dorm:function(){							// going back to the dorm.
		this.statename="goto_dorm";
		this.symbol="tired";
		this.state = student_state.in_common_room;
	},
	in_class:function(){							// try to get into class
		this.statename="in_class";
		if(Campus.test_day==true){					// if its a test day, take a seat - doors stay open on test day.
			this.symbol="...";
			Campus.enter_room(this,"programming basics");
			this.state = student_state.testing;
		}else{								// otherwise try to get into class before the doors close
			this.symbol="?"
			if(this.learning==false){				// the doors are open. take a seat.
				Campus.enter_room(this,"programming basics");
				this.learning=true;
			}
			if(--this.stamina<1){					// too late. the doors are closed. go back to the dorm.
				Campus.exit_room(this,"programming basics");
				this.learning=false;
				this.state = student_state.goto_dorm;
			}
		}
	},
	testing:function(){							// in a seat, ready for testing
		this.statename="testing";
		this.symbol="???"
	}
}

// bunch of globals - lazy.
// each global represents a student state - for display purposes.
var in_dorm_room="";
var in_common_room="";
var goto_class=""
var in_class="";
var testing="";
var goto_dorm="";


function loop(){ // <- run the simulation
	log("Days until test: "+teacher.classroom.days_to_test);
	in_dorm_room="";in_common_room="";goto_class="";in_class=teacher.name+" "+teacher.symbol+"<br>";testing="";goto_dorm=""; //reset globals
	for(var i=0;i<students.length;i++){
		students[i].state(); 	// run the current state.
		//the rest is junk for the display
		if(students[i].statename=="in_dorm_room")in_dorm_room+="("+students[i].name+" "+students[i].symbol+")<br>";
		if(students[i].statename=="in_class")in_class+="("+students[i].name+" "+students[i].symbol+")<br>";
		if(students[i].statename=="in_common_room")in_common_room+="("+students[i].name+" "+students[i].symbol+")<br>";
		if(students[i].statename=="testing")testing+="("+students[i].name+" "+students[i].symbol+")<br>";
		if(students[i].statename=="goto_class")goto_class+="("+students[i].name+" "+students[i].symbol+")<br>";
		if(students[i].statename=="goto_dorm")goto_dorm+="("+students[i].name+" "+students[i].symbol+")<br>";
	}
	teacher.state(); // run the current state
	display();
	if(glb_rungame){ // turn off the simulation after the test is complete.
		setTimeout(loop,1000);
	}
}
function display(){
	var s = ""
	for(var i=0;i<students.length;i++){
		var n = students[i].name;
		var k="";
		for(var j in students[i].knowledge){
			k+="("+j+") "
		}
		s+=n+" (Student "+i+")\t is " + students[i].statename + "...\r\n"
		+ "intelligence = " + students[i].intelligence + "\r\n"
		+ "stamina = " + students[i].stamina + "/"+students[i].fully_rested+"\r\n"
		+ "learning = " + students[i].learning+ "\r\n"
		+ "known = " + k + "\r\n" + "\r\n\r\n";
		//+ "reknown = " + students[i].reknown + "\r\n\r\n";
	}
	document.getElementsByTagName("textarea")[0].value = s;
	document.getElementById("dormroom").innerHTML=in_dorm_room;
	document.getElementById("commonroom").innerHTML=in_common_room;
	document.getElementById("goto_class").innerHTML=goto_class;
	document.getElementById("in_class").innerHTML=in_class+testing;
	document.getElementById("goto_dorm").innerHTML=goto_dorm;
	document.getElementById("test").innerHTML=teacher.answers;
}
// a simple array of associations to teach 
var knowledgePB = [
	{"name":"value","value":"the current state of a concept which may varry"},
	{"name":"constant","constant":"stores values that do not varry. A constant is a name for a stored non-varying value."},
	{"name":"variable","variable":"stores values that can varry. A variable is a name for a stored value."},
	{"name":"statement","statement":"performs a single action on a value"},
	{"name":"loop","loop":"a control structure that orderly itterates through statement execution"},
	{"name":"conditional","conditional":"a controlled furcation of statment exectution"},
	{"name":"for","for":"a loop control structure. itteration is controlled via indexing variable test"},
	{"name":"do","do":"a loop control structure. itteration is controlled via variable test"},
	{"name":"if","if":"a bifurcation condtional control structure. bifurcation is controlled via value testing"},
	{"name":"switch","switch":"a polyfurcation condtional control structure. polyfurcation is cotrolled via value testing"}
];

var glb_rungame=true;   // used to control the simluation
var glb_questions=4;	// the total number of question to ask in the test

var teacher = new Teacher(teacher_state.waiting,"Dr Bob",knowledgePB);		// a state, a name, and a knowledge array
teacher.classroom = new ClassRoom("programming basics",2);				// a cource name and the maxmimum number os students
Campus.add_room(teacher.classroom);								// what is a teacher without a classroom - mom.
var students=[];
students[0] = new Student(student_state.in_dorm_room,"Fred");			// a states, a name , no knowlege to start off.
students[1] = new Student(student_state.in_dorm_room,"Mark");
students[2] = new Student(student_state.in_dorm_room,"Buddy");

var flippantQuess=["doh...","Your mama","kilroy was here","#@!","true"];	// what is said when there is no answer.

// let 'em loose.
window.onload=loop;

function log(n){
	document.getElementById("info").innerHTML=n;
}
</script>
</head>
<body>
<div>Course: Programming Basics. Teacher: Dr Bob. <span id="info">&nbsp;</span></div>
<h1>A less-simple state-driven simulation <span>(An automated campus)</span></h1>
<!-- bad style-table based display -->
<table><tr>
<td valign="top"><textarea rows="20" cols="40"></textarea></td>
<td valign="top">
<table>
	<tr>
		<td align="center">dorm room</td><td align="center">common room</td><td align="right">going to class =></td><td align="center">class room</td>
	</tr><tr>
		<td id='dormroom' rowspan="3"></td><td id="commonroom" rowspan="3"></td><td id="goto_class"></td><td id='in_class' rowspan="3"></td>
	</tr><tr>
		<td>&nbsp;</td>
	</tr><tr>
		<td id='goto_dorm'></td>
	</tr></tr>
		<td align="center">dorm room</td><td align="center">common room</td><td align="left"><= going to dorm</td><td align="center">class room</td>
	</tr>
</table>
<div id="test"></div>
</td>
</tr></table>

</body>
</html>
tested on non-mobile windows platform.
tested in ie, ff, safari, chrome, opera