
DJ Toenail
Prompt
CODE a time-management game where the player controls a server in a restaurant setting. Implement the core loop of seating incoming customers at available tables, taking their food orders, delivering prepared meals from the kitchen, and clearing the tables after they finish.
A system prompt was added to support web rendering
# Restaurant Time Management Game
I'll create a time management game where you control a restaurant server. The game will include seating customers, taking orders, delivering food, and clearing tables - all within a single HTML file.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Rush</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #fdbb2d);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
#game-container {
width: 900px;
height: 600px;
background: #f0f0f0;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
overflow: hidden;
}
#header {
background: #2c3e50;
color: white;
padding: 15px;
display: flex;
justify-content: space-between;
align-items: center;
}
#stats {
display: flex;
gap: 20px;
}
.stat {
background: #34495e;
padding: 8px 15px;
border-radius: 20px;
font-weight: bold;
}
#game-area {
display: flex;
flex: 1;
position: relative;
}
#restaurant {
flex: 3;
background: #8B4513;
position: relative;
overflow: hidden;
}
#ui-panel {
flex: 1;
background: #ecf0f1;
padding: 15px;
display: flex;
flex-direction: column;
gap: 15px;
}
.panel-section {
background: white;
border-radius: 10px;
padding: 15px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
h2 {
color: #2c3e50;
margin-bottom: 10px;
text-align: center;
}
#tutorial {
background: #3498db;
color: white;
}
#tutorial p {
font-size: 14px;
line-height: 1.4;
}
.table {
position: absolute;
width: 90px;
height: 90px;
background: #8B4513;
border: 5px solid #5D2906;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.table.chair-1 {
transform: rotate(0deg);
}
.table.chair-2 {
transform: rotate(90deg);
}
.table.chair-3 {
transform: rotate(180deg);
}
.table.chair-4 {
transform: rotate(270deg);
}
.chair {
position: absolute;
width: 25px;
height: 25px;
background: #5D2906;
border-radius: 5px;
}
.chair-1 { top: -35px; }
.chair-2 { right: -35px; }
.chair-3 { bottom: -35px; }
.chair-4 { left: -35px; }
.customer {
position: absolute;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 20px;
color: white;
font-weight: bold;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.3);
transition: all 0.3s ease;
}
.customer.waiting {
background: #e74c3c;
animation: pulse 1.5s infinite;
}
.customer.seated {
background: #3498db;
}
.customer.ordering {
background: #9b59b6;
}
.customer.eating {
background: #2ecc71;
}
.customer.done {
background: #f39c12;
}
.customer.leaving {
background: #34495e;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.kitchen {
position: absolute;
width: 150px;
height: 100px;
background: #7f8c8d;
border: 5px solid #2c3e50;
bottom: 20px;
right: 20px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
}
.food-item {
position: absolute;
width: 30px;
height: 30px;
background: #e67e22;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
z-index: 10;
}
.ready {
background: #27ae60;
}
.delivering {
background: #f1c40f;
}
.progressbar {
height: 10px;
background: #ecf0f1;
border-radius: 5px;
margin-top: 5px;
overflow: hidden;
}
.progress {
height: 100%;
background: #2ecc71;
width: 0%;
transition: width 0.5s;
}
#controls {
display: flex;
justify-content: space-around;
padding: 10px;
background: #2c3e50;
}
button {
padding: 10px 20px;
background: #3498db;
border: none;
border-radius: 5px;
color: white;
font-weight: bold;
cursor: pointer;
transition: all 0.2s;
}
button:hover {
background: #2980b9;
transform: translateY(-2px);
}
button:active {
transform: translateY(1px);
}
#orders-panel {
max-height: 200px;
overflow-y: auto;
}
.order-item {
background: #f8f9fa;
padding: 8px;
border-radius: 5px;
margin-bottom: 8px;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.order-item.ready {
background: #d4edda;
border-left: 4px solid #28a745;
}
.timer {
font-size: 12px;
color: #e74c3c;
font-weight: bold;
}
.completed {
opacity: 0.7;
text-decoration: line-through;
}
.notification {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: #27ae60;
color: white;
padding: 10px 20px;
border-radius: 30px;
font-weight: bold;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.2);
z-index: 100;
animation: slideIn 0.5s, fadeOut 0.5s 2.5s forwards;
}
@keyframes slideIn {
from { top: -50px; opacity: 0; }
to { top: 20px; opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
.tip {
position: absolute;
background: #f1c40f;
color: #7d5a00;
padding: 5px 10px;
border-radius: 15px;
font-weight: bold;
font-size: 14px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
animation: floatUp 1.5s forwards;
z-index: 50;
}
@keyframes floatUp {
0% { transform: translateY(0); opacity: 1; }
100% { transform: translateY(-50px); opacity: 0; }
}
</style>
</head>
<body>
<div id="game-container">
<div id="header">
<h1>Restaurant Rush</h1>
<div id="stats">
<div class="stat">Tips: $<span id="tips">0</span></div>
<div class="stat">Customers: <span id="customers">0</span></div>
<div class="stat">Level: <span id="level">1</span></div>
</div>
</div>
<div id="game-area">
<div id="restaurant">
<!-- Tables and customers will be generated here -->
<div class="kitchen">KITCHEN</div>
</div>
<div id="ui-panel">
<div class="panel-section" id="tutorial">
<h2>How to Play</h2>
<p>1. Click on waiting customers to seat them</p>
<p>2. Seat them at an available table</p>
<p>3. Click on seated customers to take orders</p>
<p>4. Click on ready food to deliver to customers</p>
<p>5. Click on finished customers to clear tables</p>
<p>6. Serve customers quickly to earn big tips!</p>
</div>
<div class="panel-section">
<h2>Current Orders</h2>
<div id="orders-panel">
<div class="order-item completed">
<span>Burger for Table 1</span>
<span class="timer">Delivered</span>
</div>
<div class="order-item">
<span>Salad for Table 3</span>
<span class="timer">Ready!</span>
</div>
<div class="order-item">
<span>Pizza for Table 2</span>
<span class="timer">Cooking</span>
</div>
</div>
</div>
<div class="panel-section">
<h2>Server Actions</h2>
<button id="speed-up">Speed Up (2x)</button>
<button id="take-break">Take Break</button>
</div>
</div>
</div>
<div id="controls">
<button id="start-btn">Start Game</button>
<button id="pause-btn">Pause</button>
<button id="reset-btn">Reset Game</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game state
const state = {
gameRunning: false,
gameTime: 0,
tips: 0,
customersServed: 0,
level: 1,
customers: [],
tables: [],
orders: [],
foodItems: [],
activeCustomer: null,
gameSpeed: 1
};
// DOM elements
const restaurantEl = document.getElementById('restaurant');
const tipsEl = document.getElementById('tips');
const customersEl = document.getElementById('customers');
const levelEl = document.getElementById('level');
const startBtn = document.getElementById('start-btn');
const pauseBtn = document.getElementById('pause-btn');
const resetBtn = document.getElementById('reset-btn');
const speedUpBtn = document.getElementById('speed-up');
const takeBreakBtn = document.getElementById('take-break');
const ordersPanel = document.getElementById('orders-panel');
// Create tables
function createTables() {
const tablePositions = [
{ x: 150, y: 100, chairs: [1, 3] },
{ x: 350, y: 100, chairs: [1, 2, 3, 4] },
{ x: 550, y: 100, chairs: [2, 4] },
{ x: 150, y: 300, chairs: [1, 3] },
{ x: 350, y: 300, chairs: [1, 2, 3, 4] },
{ x: 550, y: 300, chairs: [2, 4] }
];
tablePositions.forEach((pos, index) => {
const table = document.createElement('div');
table.className = 'table';
table.style.left = `${pos.x}px`;
table.style.top = `${pos.y}px`;
table.dataset.tableId = index;
// Add chairs
pos.chairs.forEach(chair => {
const chairEl = document.createElement('div');
chairEl.className = `chair chair-${chair}`;
table.appendChild(chairEl);
});
// Add serving spot
const spot = document.createElement('div');
spot.className = 'chair chair-serving';
spot.style.position = 'absolute';
spot.style.width = '25px';
spot.style.height = '25px';
spot.style.background = '#ecf0f1';
spot.style.borderRadius = '5px';
spot.style.top = '30px';
spot.style.left = '30px';
spot.dataset.tableId = index;
table.appendChild(spot);
restaurantEl.appendChild(table);
state.tables.push({
id: index,
element: table,
x: pos.x,
y: pos.y,
occupied: false,
customerId: null
});
});
}
// Create a customer
function createCustomer() {
const customerEl = document.createElement('div');
customerEl.className = 'customer waiting';
customerEl.innerHTML = '👤';
customerEl.style.left = `${Math.random() * 100 + 50}px`;
customerEl.style.top = `${Math.random() * 50 + 350}px`;
const customerId = state.customers.length;
customerEl.dataset.customerId = customerId;
restaurantEl.appendChild(customerEl);
const customer = {
id: customerId,
element: customerEl,
state: 'waiting', // waiting, seated, ordering, eating, done, leaving
tableId: null,
order: null,
patience: 100,
statusTimeout: null
};
state.customers.push(customer);
// Add click event to seat customer
customerEl.addEventListener('click', () => {
if (customer.state === 'waiting') {
seatCustomer(customer);
} else if (customer.state === 'seated') {
takeOrder(customer);
} else if (customer.state === 'eating') {
deliverBill(customer);
} else if (customer.state === 'done') {
clearTable(customer);
}
});
return customer;
}
// Seat a customer at an available table
function seatCustomer(customer) {
// Find an available table
const availableTable = state.tables.find(table => !table.occupied);
if (availableTable) {
customer.state = 'seated';
customer.element.className = 'customer seated';
customer.tableId = availableTable.id;
// Position customer at table
customer.element.style.left = `${availableTable.x + 30}px`;
customer.element.style.top = `${availableTable.y + 30}px`;
availableTable.occupied = true;
availableTable.customerId = customer.id;
// Show notification
showNotification('Customer seated!');
} else {
showNotification('All tables occupied!');
}
}
// Take order from seated customer
function takeOrder(customer) {
customer.state = 'ordering';
customer.element.className = 'customer ordering';
// Create order
const menuItems = ['Burger', 'Pizza', 'Salad', 'Pasta', 'Steak'];
const order = menuItems[Math.floor(Math.random() * menuItems.length)];
customer.order = order;
// Add to orders panel
const orderEl = document.createElement('div');
orderEl.className = 'order-item';
orderEl.innerHTML = `
<span>${order} for Table ${customer.tableId + 1}</span>
<span class="timer">Cooking</span>
`;
orderEl.dataset.customerId = customer.id;
ordersPanel.appendChild(orderEl);
// Create food item in kitchen after delay
setTimeout(() => {
createFoodItem(order, customer.id, customer.tableId);
orderEl.querySelector('.timer').textContent = 'Ready!';
orderEl.classList.add('ready');
}, 3000);
showNotification('Order taken!');
}
// Create food item in kitchen
function createFoodItem(order, customerId, tableId) {
const foodEl = document.createElement('div');
foodEl.className = 'food-item';
foodEl.innerHTML = '🍔';
foodEl.style.left = '680px';
foodEl.style.top = '380px';
foodEl.dataset.customerId = customerId;
foodEl.dataset.tableId = tableId;
restaurantEl.appendChild(foodEl);
const foodItem = {
element: foodEl,
customerId: customerId,
tableId: tableId,
state: 'ready'
};
state.foodItems.push(foodItem);
// Add click to deliver
foodEl.addEventListener('click', () => {
deliverFood(foodItem);
});
return foodItem;
}
// Deliver food to customer
function deliverFood(foodItem) {
const customer = state.customers.find(c => c.id === foodItem.customerId);
if (!customer) return;
// Update customer state
customer.state = 'eating';
customer.element.className = 'customer eating';
// Remove food item
foodItem.element.remove();
state.foodItems = state.foodItems.filter(f => f !== foodItem);
// Update order panel
const orderEl = document.querySelector(`.order-item[data-customer-id="${customer.id}"]`);
if (orderEl) {
orderEl.querySelector('.timer').textContent = 'Delivered';
// Timer for customer finishing meal
setTimeout(() => {
customer.state = 'done';
customer.element.className = 'customer done';
orderEl.classList.add('completed');
showNotification('Customer finished meal!');
}, 5000);
}
showNotification('Food delivered!');
}
// Deliver bill to eating customer
function deliverBill(customer) {
// Pay customer and give tip
const tipAmount = Math.floor(Math.random() * 10) + 5;
state.tips += tipAmount;
tipsEl.textContent = state.tips;
// Show tip animation
const tipEl = document.createElement('div');
tipEl.className = 'tip';
tipEl.textContent = `+$${tipAmount}`;
tipEl.style.left = `${parseInt(customer.element.style.left) + 20}px`;
tipEl.style.top = `${parseInt(customer.element.style.top) - 20}px`;
restaurantEl.appendChild(tipEl);
setTimeout(() => {
tipEl.remove();
}, 1500);
// Move customer to leaving state
customer.state = 'leaving';
customer.element.className = 'customer leaving';
// Remove customer after delay
setTimeout(() => {
customer.element.remove();
state.customers = state.customers.filter(c => c !== customer);
state.customersServed++;
customersEl.textContent = state.customersServed;
}, 2000);
showNotification('Customer paid!');
}
// Clear table after customer leaves
function clearTable(customer) {
// Free up table
const table = state.tables.find(t => t.id === customer.tableId);
if (table) {
table.occupied = false;
table.customerId = null;
}
// Remove customer
customer.element.remove();
state.customers = state.customers.filter(c => c !== customer);
// Update stats
state.customersServed++;
customersEl.textContent = state.customersServed;
showNotification('Table cleared!');
}
// Show notification
function showNotification(message) {
const notification = document.createElement('div');
notification.className = 'notification';
notification.textContent = message;
document.getElementById('game-container').appendChild(notification);
setTimeout(() => {
notification.remove();
}, 3000);
}
// Game loop
function gameLoop() {
if (!state.gameRunning) return;
state.gameTime++;
// Every 5 seconds, add a new customer
if (state.gameTime % (5 * state.gameSpeed) === 0) {
createCustomer();
}
// Update customer patience
state.customers.forEach(customer => {
if (customer.state === 'waiting' || customer.state === 'seated') {
customer.patience -= 0.5;
if (customer.patience <= 0) {
// Customer leaves unhappy
if (customer.state === 'seated') {
const table = state.tables.find(t => t.id === customer.tableId);
if (table) {
table.occupied = false;
table.customerId = null;
}
}
customer.element.remove();
state.customers = state.customers.filter(c => c !== customer);
showNotification('Customer left unhappy!');
}
}
});
requestAnimationFrame(gameLoop);
}
// Initialize game
function initGame() {
createTables();
createCustomer();
// Button event listeners
startBtn.addEventListener('click', () => {
state.gameRunning = true;
gameLoop();
startBtn.disabled = true;
});
pauseBtn.addEventListener('click', () => {
state.gameRunning = !state.gameRunning;
pauseBtn.textContent = state.gameRunning ? 'Pause' : 'Resume';
});
resetBtn.addEventListener('click', () => {
// Reset game state
state.gameRunning = false;
state.gameTime = 0;
state.tips = 0;
state.customersServed = 0;
state.level = 1;
// Clear restaurant
restaurantEl.innerHTML = '<div class="kitchen">KITCHEN</div>';
// Reset arrays
state.customers = [];
state.tables = [];
state.orders = [];
state.foodItems = [];
// Update UI
tipsEl.textContent = '0';
customersEl.textContent = '0';
levelEl.textContent = '1';
ordersPanel.innerHTML = '';
// Reinitialize
createTables();
createCustomer();
startBtn.disabled = false;
pauseBtn.textContent = 'Pause';
});
speedUpBtn.addEventListener('click', () => {
state.gameSpeed = state.gameSpeed === 1 ? 2 : 1;
speedUpBtn.textContent = state.gameSpeed === 2 ? 'Normal Speed' : 'Speed Up (2x)';
});
takeBreakBtn.addEventListener('click', () => {
showNotification('Taking a quick break...');
setTimeout(() => {
showNotification('Break over! Back to work!');
}, 2000);
});
}
// Start the game
initGame();
});
</script>
</body>
</html>
```
## How to Play the Restaurant Management Game
1. **Start the Game**: Click the "Start Game" button to begin
2. **Seat Customers**: Click on waiting customers (red) to seat them at tables
3. **Take Orders**: Click on seated customers (blue) to take their food orders
4. **Deliver Food**: When food is ready, click on the food items to deliver to customers
5. **Collect Tips**: Customers who finish their meals pay and leave tips
6. **Clear Tables**: Click on done customers (orange) to clear the table for new guests
## Features
- **Dynamic Restaurant Layout**: Tables with chairs positioned realistically
- **Customer States**: Visual indicators show customer progress (waiting, seated, ordering, eating, done)
- **Food Preparation**: Kitchen area where food is prepared and ready for pickup
- **Orders Panel**: Track current orders and their status
- **Tips System**: Earn money for fast, efficient service
- **Patience System**: Customers leave if not served quickly enough
- **Game Controls**: Start, pause, reset, speed adjustment, and take break options
The game is completely self-contained in a single HTML file with no external dependencies. Simply copy the entire code into an HTML file and open it in any modern browser to play!
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restaurant Rush – Time-Management Mini-Game</title>
<style>
*{box-sizing:border-box;font-family:Arial,Helvetica,sans-serif}
body{background:#fafafa;margin:0;padding:10px;color:#333}
h1{text-align:center;margin:0 0 10px}
#game{display:grid;grid-template-columns:160px 1fr 160px;gap:10px;max-width:1000px;margin:0 auto}
/* Queue ------------------------------------------------*/
#queue-container{background:#ffe9e9;border:2px solid #d88;padding:5px}
#queue-container h2{margin:0;font-size:18px;text-align:center}
#queue{display:flex;flex-direction:column-reverse;align-items:center;gap:4px;margin-top:5px;min-height:300px}
.customer{
width:40px;height:40px;border-radius:50%;
background:#ff6b6b;border:2px solid #b33;cursor:pointer;
display:flex;justify-content:center;align-items:center;
color:#fff;font-weight:bold;
}
/* Tables ----------------------------------------------*/
#tables-container{background:#e9f9ff;border:2px solid #88c;padding:5px}
#tables-container h2{margin:0;font-size:18px;text-align:center}
.tables{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin-top:5px}
.table{
background:#fffbe6;border:2px solid #caa;border-radius:6px;
min-height:120px;position:relative;cursor:pointer;
display:flex;flex-direction:column;align-items:center;justify-content:center;
}
.table.empty{opacity:0.4}
.table.waitingOrder{background:#fff0c2}
.table.waitingFood{background:#ffd9c2}
.table.eating{background:#d6ffc2}
.table.done{background:#e0e0e0}
.table span{font-size:14px;text-align:center}
.timer{
position:absolute;bottom:4px;right:4px;
background:#000a;color:#fff;font-size:12px;padding:0 4px;border-radius:3px
}
/* Kitchen ---------------------------------------------*/
#kitchen-container{background:#e9ffe9;border:2px solid #8c8;padding:5px}
#kitchen-container h2{margin:0;font-size:18px;text-align:center}
#kitchen{display:flex;flex-direction:column;align-items:center;margin-top:5px}
#stove{
width:100%;height:60px;background:#555;color:#fff;
display:flex;justify-content:center;align-items:center;border-radius:4px
}
#dishes{margin-top:6px;display:flex;flex-wrap:wrap;gap:6px;justify-content:center}
.dish{
width:40px;height:40px;border-radius:50%;background:#ffa502;cursor:pointer;
border:2px solid #e08700;position:relative
}
.dish::after{
content:attr(data-table);position:absolute;top:50%;left:50%;
transform:translate(-50%,-50%);color:#fff;font-weight:bold;font-size:14px
}
/* Score -----------------------------------------------*/
#score{text-align:center;margin-top:10px;font-size:18px;font-weight:bold}
/* Selected dish follow cursor -------------------------*/
.carried{
position:fixed!important;pointer-events:none;
opacity:0.9;transform:translate(-50%,-50%);
z-index:1000
}
</style>
</head>
<body>
<h1>Restaurant Rush</h1>
<div id="game">
<!-- Queue -->
<div id="queue-container">
<h2>Queue</h2>
<div id="queue"></div>
</div>
<!-- Tables -->
<div id="tables-container">
<h2>Tables</h2>
<div class="tables" id="tables"></div>
</div>
<!-- Kitchen -->
<div id="kitchen-container">
<h2>Kitchen</h2>
<div id="kitchen">
<div id="stove">Stove</div>
<div id="dishes"></div>
</div>
</div>
</div>
<div id="score">Served: 0</div>
<script>
/* --- Game Configuration ----------------------------------------------*/
const TABLE_COUNT = 4;
const ORDER_PREP_TIME = 5; // seconds
const EAT_TIME = 7; // seconds
const CUSTOMER_INTERVAL = 3000; // ms new customer arrival
/* --- Game State -------------------------------------------------------*/
let nextCustomerId = 1;
let score = 0;
const queue = []; // customers waiting
const tables = []; // table objects
const cookingOrders = []; // {tableIndex, remaining}
const readyDishes = []; // {tableIndex}
let carriedDish = null; // HTMLElement being carried
/* --- DOM Elements -----------------------------------------------------*/
const queueDiv = document.getElementById('queue');
const tablesDiv = document.getElementById('tables');
const dishesDiv = document.getElementById('dishes');
const scoreDiv = document.getElementById('score');
/* --- Utility ----------------------------------------------------------*/
function createCustomer() {
const cust = { id: nextCustomerId++ };
queue.unshift(cust); // newest at front, will render bottom because column-reverse
renderQueue();
}
function renderQueue() {
queueDiv.innerHTML = '';
queue.forEach(cust=>{
const el = document.createElement('div');
el.className = 'customer';
el.textContent = cust.id;
el.title = 'Click to seat';
el.addEventListener('click',()=>seatCustomer(cust));
queueDiv.appendChild(el);
});
}
function seatCustomer(cust){
const freeIndex = tables.findIndex(t=>t.state==='empty');
if(freeIndex===-1) return; // no table
// remove from queue
const pos = queue.indexOf(cust);
if(pos>-1) queue.splice(pos,1);
renderQueue();
// seat at table
const table = tables[freeIndex];
table.state = 'waitingOrder';
table.customer = cust;
renderTables();
}
function renderTables(){
tables.forEach((table,i)=>{
const el = table.el;
el.className = 'table '+table.state;
el.innerHTML = '';
const span = document.createElement('span');
switch(table.state){
case 'empty':
span.textContent = 'Table '+(i+1);
break;
case 'waitingOrder':
span.textContent = 'Customer '+table.customer.id+'\nClick to take order';
break;
case 'waitingFood':
span.textContent = 'Order cooking...';
break;
case 'eating':
span.textContent = 'Eating...';
break;
case 'done':
span.textContent = 'Finished\nClick to clear';
break;
}
el.appendChild(span);
if(table.timer>0){
const t = document.createElement('div');
t.className='timer';
t.textContent = table.timer;
el.appendChild(t);
}
});
}
function takeOrder(idx){
const table = tables[idx];
if(table.state!=='waitingOrder') return;
table.state = 'waitingFood';
cookingOrders.push({tableIndex:idx, remaining:ORDER_PREP_TIME});
renderTables();
}
function deliverDish(tableIdx){
const table = tables[tableIdx];
if(table.state!=='waitingFood') return;
table.state = 'eating';
table.timer = EAT_TIME;
// remove dish
const dishIndex = readyDishes.findIndex(d=>d.tableIndex===tableIdx);
if(dishIndex>-1) readyDishes.splice(dishIndex,1);
renderDishes();
renderTables();
}
function clearTable(idx){
const table = tables[idx];
if(table.state!=='done') return;
table.state='empty';
table.customer=null;
score++;
scoreDiv.textContent='Served: '+score;
renderTables();
}
/* --- Kitchen ----------------------------------------------------------*/
function renderDishes(){
dishesDiv.innerHTML='';
readyDishes.forEach(d=>{
const el = document.createElement('div');
el.className='dish';
el.dataset.table = d.tableIndex+1;
el.title = 'Click, then click table';
el.addEventListener('mousedown',e=>{
carriedDish = el;
el.classList.add('carried');
moveCarried(e);
});
dishesDiv.appendChild(el);
});
}
function moveCarried(e){
if(!carriedDish) return;
carriedDish.style.left = e.pageX+'px';
carriedDish.style.top = e.pageY+'px';
}
/* --- Game Loop --------------------------------------------------------*/
function tick(){
// update cooking orders
cookingOrders.forEach(o=>{
o.remaining--;
});
for(let i=cookingOrders.length-1;i>=0;i--){
if(cookingOrders[i].remaining<=0){
readyDishes.push({tableIndex:cookingOrders[i].tableIndex});
cookingOrders.splice(i,1);
}
}
// update tables (eating timers)
tables.forEach(t=>{
if(t.state==='eating'){
t.timer--;
if(t.timer<=0){
t.state='done';
}
}
});
renderDishes();
renderTables();
}
setInterval(tick,1000);
/* --- Spawn Customers --------------------------------------------------*/
setInterval(()=>createCustomer(),CUSTOMER_INTERVAL);
/* --- Initialise Tables ------------------------------------------------*/
for(let i=0;i<TABLE_COUNT;i++){
const obj = {
state:'empty',
customer:null,
timer:0,
el: document.createElement('div')
};
obj.el.className='table empty';
obj.el.innerHTML='Table '+(i+1);
// click handler
obj.el.addEventListener('click',()=>{
switch(obj.state){
case 'waitingOrder': takeOrder(i); break;
case 'waitingFood': break;
case 'done': clearTable(i); break;
}
// if carrying dish, attempt deliver
if(carriedDish){
deliverDish(i);
carriedDish.remove();
carriedDish=null;
}
});
tables.push(obj);
tablesDiv.appendChild(obj.el);
}
renderTables();
/* --- Global Events ----------------------------------------------------*/
window.addEventListener('mousemove',moveCarried);
window.addEventListener('mouseup',()=>{
if(carriedDish){
carriedDish.remove();
carriedDish=null;
}
});
</script>
</body>
</html>
```Here's a complete HTML file with embedded JavaScript and CSS to create a time-management game where the player controls a server in a restaurant. The game includes seating customers, taking orders, delivering food, and clearing tables, all within a single code block.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Rush</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 10px;
background-color: #f0f0f0;
display: flex;
flex-direction: column;
align-items: center;
}
#gameContainer {
display: flex;
flex-direction: column;
align-items: center;
background-color: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
width: 800px;
}
#restaurant {
width: 700px;
height: 400px;
border: 2px solid #333;
position: relative;
background-color: #e8f5e9;
margin-bottom: 20px;
}
.table {
width: 60px;
height: 60px;
background-color: #8d6e63;
border-radius: 10px;
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
cursor: pointer;
}
.customer {
width: 30px;
height: 30px;
background-color: #ffca28;
border-radius: 50%;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
font-size: 12px;
}
#kitchen {
width: 100px;
height: 60px;
background-color: #757575;
position: absolute;
bottom: 10px;
right: 10px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
border-radius: 5px;
cursor: pointer;
}
#waitingArea {
width: 80px;
height: 40px;
background-color: #c0c0c0;
position: absolute;
top: 10px;
left: 10px;
display: flex;
justify-content: center;
align-items: center;
color: black;
font-weight: bold;
border-radius: 5px;
}
#player {
width: 30px;
height: 30px;
background-color: #2196f3;
border-radius: 50%;
position: absolute;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 12px;
}
#stats {
width: 700px;
text-align: center;
margin-top: 10px;
font-size: 18px;
}
#message {
margin-top: 10px;
font-weight: bold;
color: #d32f2f;
}
</style>
</head>
<body>
<div id="gameContainer">
<h1>Restaurant Rush</h1>
<div id="restaurant">
<div id="player">You</div>
<div id="kitchen">Kitchen</div>
<div id="waitingArea">Waiting</div>
</div>
<div id="stats">
Score: <span id="score">0</span> | Customers Served: <span id="served">0</span> | Time: <span id="time">0</span>s
</div>
<div id="message"></div>
</div>
<script>
const restaurant = document.getElementById('restaurant');
const player = document.getElementById('player');
const kitchen = document.getElementById('kitchen');
const waitingArea = document.getElementById('waitingArea');
const scoreDisplay = document.getElementById('score');
const servedDisplay = document.getElementById('served');
const timeDisplay = document.getElementById('time');
const message = document.getElementById('message');
let playerPos = { x: 335, y: 185 };
let score = 0;
let customersServed = 0;
let gameTime = 0;
let tables = [];
let customers = [];
let waitingCustomers = [];
let ordersInKitchen = [];
let playerHolding = null;
const tablePositions = [
{ x: 100, y: 100 }, { x: 250, y: 100 }, { x: 400, y: 100 },
{ x: 100, y: 250 }, { x: 250, y: 250 }, { x: 400, y: 250 }
];
function initTables() {
tablePositions.forEach(pos => {
const table = document.createElement('div');
table.className = 'table';
table.style.left = pos.x + 'px';
table.style.top = pos.y + 'px';
table.innerText = 'Empty';
table.addEventListener('click', () => handleTableClick(table, pos));
restaurant.appendChild(table);
tables.push({ element: table, pos, occupied: false, customer: null, order: null, served: false });
});
}
function handleTableClick(tableElement, pos) {
if (playerHolding === 'customer' && !tables.find(t => t.element === tableElement).occupied) {
seatCustomer(pos);
} else if (tables.find(t => t.element === tableElement).occupied) {
const table = tables.find(t => t.pos === pos);
if (!table.order) {
takeOrder(table);
} else if (playerHolding === table.order && table.order) {
deliverFood(table);
} else if (table.served) {
clearTable(table);
} else {
message.innerText = 'Action not possible!';
}
}
}
kitchen.addEventListener('click', () => {
if (!playerHolding && ordersInKitchen.length > 0) {
playerHolding = ordersInKitchen.shift();
message.innerText = `Picked up ${playerHolding} from kitchen.`;
} else if (playerHolding && playerHolding.includes('order')) {
ordersInKitchen.push(playerHolding);
message.innerText = `Dropped ${playerHolding} at kitchen.`;
playerHolding = null;
}
});
function seatCustomer(tablePos) {
if (waitingCustomers.length > 0) {
const customer = waitingCustomers.shift();
const table = tables.find(t => t.pos.x === tablePos.x && t.pos.y === tablePos.y);
table.occupied = true;
table.customer = customer;
customer.element.style.left = tablePos.x + 15 + 'px';
customer.element.style.top = tablePos.y + 15 + 'px';
table.element.innerText = 'Seated';
playerHolding = null;
message.innerText = 'Customer seated!';
updateWaitingArea();
} else {
message.innerText = 'No customers waiting!';
}
}
function takeOrder(table) {
if (!playerHolding) {
const order = `order-${Math.floor(Math.random() * 1000)}`;
table.order = order;
table.element.innerText = 'Ordered';
playerHolding = order;
message.innerText = 'Order taken!';
} else {
message.innerText = 'Already holding something!';
}
}
function deliverFood(table) {
table.served = true;
table.element.innerText = 'Eating';
playerHolding = null;
message.innerText = 'Food delivered!';
setTimeout(() => {
if (table.served) {
table.element.innerText = 'Finished';
}
}, 5000);
}
function clearTable(table) {
table.occupied = false;
table.order = null;
table.served = false;
table.customer.element.remove();
table.customer = null;
table.element.innerText = 'Empty';
score += 10;
customersServed++;
scoreDisplay.innerText = score;
servedDisplay.innerText = customersServed;
message.innerText = 'Table cleared!';
}
function spawnCustomer() {
const customer = document.createElement('div');
customer.className = 'customer';
customer.innerText = 'Waiting';
restaurant.appendChild(customer);
customers.push({ element: customer, id: `cust-${Math.random().toString(36).substr(2, 9)}` });
waitingCustomers.push({ element: customer, id: customers[customers.length - 1].id });
updateWaitingArea();
}
function updateWaitingArea() {
waitingCustomers.forEach((cust, index) => {
cust.element.style.left = 20 + index * 20 + 'px';
cust.element.style.top = 20 + 'px';
});
waitingArea.innerText = `Waiting: ${waitingCustomers.length}`;
}
function updatePlayerPosition() {
player.style.left = playerPos.x + 'px';
player.style.top = playerPos.y + 'px';
}
document.addEventListener('keydown', (e) => {
const speed = 10;
switch (e.key) {
case 'ArrowUp':
if (playerPos.y > 0) playerPos.y -= speed;
break;
case 'ArrowDown':
if (playerPos.y < 370) playerPos.y += speed;
break;
case 'ArrowLeft':
if (playerPos.x > 0) playerPos.x -= speed;
break;
case 'ArrowRight':
if (playerPos.x < 670) playerPos.x += speed;
break;
}
updatePlayerPosition();
});
function gameLoop() {
gameTime++;
timeDisplay.innerText = gameTime;
if (gameTime % 10 === 0 && waitingCustomers.length < 5) {
spawnCustomer();
}
if (gameTime % 5 === 0 && playerHolding && playerHolding.includes('order') && !ordersInKitchen.includes(playerHolding)) {
ordersInKitchen.push(playerHolding);
message.innerText = `Order ${playerHolding} sent to kitchen.`;
playerHolding = null;
}
if (gameTime > 300) {
message.innerText = 'Game Over! Time's Up!';
alert(`Game Over! Final Score: ${score}, Customers Served: ${customersServed}`);
location.reload();
}
}
initTables();
updatePlayerPosition();
setInterval(gameLoop, 1000);
message.innerText = 'Use arrow keys to move. Click tables to interact. Pick up orders from kitchen!';
</script>
</body>
</html>
```
This code creates a simple yet functional time-management game called "Restaurant Rush." Here's a breakdown of the core mechanics:
- **Player Movement**: Use arrow keys to move the blue circle (the server) around the restaurant.
- **Tables**: Brown rectangles represent tables where customers can be seated, orders taken, food delivered, and tables cleared.
- **Customers**: Yellow circles represent customers who spawn in the waiting area (top-left gray box). Click on an empty table while near it to seat a waiting customer.
- **Orders**: Click on a seated customer’s table to take their order, then click the kitchen (bottom-right gray box) to drop it off. Later, pick up the prepared order from the kitchen and deliver it by clicking the table.
- **Clearing Tables**: After customers finish eating, click the table to clear it and earn points.
- **Game Loop**: New customers arrive every 10 seconds if fewer than 5 are waiting. The game ends after 300 seconds, showing your final score.
The UI includes a score tracker, number of customers served, and a timer. All styling and logic are contained within the HTML file using inline CSS and JavaScript, with no external dependencies. Simply open this in a browser to play!An excellent choice! Here is a complete, self-contained time-management restaurant game. You control the server with your mouse. Click on customers, tables, and stations to perform actions and keep your patrons happy.
Good luck running your virtual restaurant!
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Diner Dash Clone</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #333;
font-family: 'Arial', sans-serif;
color: #fff;
flex-direction: column;
}
canvas {
background-color: #f0eAD6;
border: 5px solid #5a3a22;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
</style>
</head>
<body>
<h1>Server Sprint</h1>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// --- GAME CONFIGURATION ---
const config = {
playerSpeed: 200, // pixels per second
customerSpawnTime: 8000, // ms
patienceTime: 25000, // ms
orderTime: 10000, // ms for kitchen to prepare
eatTime: 15000, // ms
pointsPerCustomer: 100,
patiencePenalty: -50,
};
// --- GAME STATE ---
let state = {
player: {
x: 400, y: 550,
targetX: 400, targetY: 550,
width: 30, height: 40,
color: '#0077be',
carrying: null, // {type: 'order'/'food'/'dishes', forTable: tableIndex}
selectedCustomer: null
},
tables: [],
customers: [],
kitchen: {
orders: [], // { forTable: tableIndex, timer: 0 }
readyFood: [] // { forTable: tableIndex }
},
stations: {
entrance: { x: 50, y: 550, width: 80, height: 50 },
kitchenWindow: { x: 740, y: 150, width: 60, height: 100 },
dishes: { x: 740, y: 400, width: 60, height: 80 }
},
score: 0,
gameOver: false,
lastSpawn: 0,
lastTime: 0
};
// --- ENTITY SETUP ---
function setupTables() {
state.tables = [
{ id: 0, x: 150, y: 100, size: 60, state: 'empty', customer: null },
{ id: 1, x: 350, y: 100, size: 60, state: 'empty', customer: null },
{ id: 2, x: 550, y: 100, size: 60, state: 'empty', customer: null },
{ id: 3, x: 150, y: 300, size: 60, state: 'empty', customer: null },
{ id: 4, x: 350, y: 300, size: 60, state: 'empty', customer: null },
{ id: 5, x: 550, y: 300, size: 60, state: 'empty', customer: null },
];
}
// --- HELPER FUNCTIONS ---
function distance(p1, p2) {
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
}
function isAtTarget(entity) {
return distance(entity, { x: entity.targetX, y: entity.targetY }) < 5;
}
function isPointInRect(point, rect) {
return point.x >= rect.x && point.x <= rect.x + rect.width &&
point.y >= rect.y && point.y <= rect.y + rect.height;
}
// --- DRAW FUNCTIONS ---
function drawPlayer() {
const p = state.player;
ctx.fillStyle = p.color;
ctx.fillRect(p.x - p.width / 2, p.y - p.height / 2, p.width, p.height);
// Draw what the player is carrying
if (p.carrying) {
switch(p.carrying.type) {
case 'order':
ctx.fillStyle = 'white';
ctx.fillRect(p.x - 8, p.y - 25, 16, 20);
ctx.strokeStyle = 'black';
ctx.strokeRect(p.x - 8, p.y - 25, 16, 20);
ctx.fillStyle = 'black';
ctx.fillText("📝", p.x-6, p.y-10);
break;
case 'food':
ctx.fillStyle = 'silver';
ctx.beginPath();
ctx.arc(p.x, p.y - 20, 15, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = 'brown';
ctx.fillText("🍔", p.x - 8, p.y - 14);
break;
case 'dishes':
ctx.fillStyle = '#bbb';
ctx.fillRect(p.x-10, p.y - 25, 20, 8);
ctx.fillRect(p.x-10, p.y - 35, 20, 8);
break;
}
}
if (p.selectedCustomer) {
ctx.fillStyle = 'yellow';
ctx.font = '20px Arial';
ctx.fillText('👤➡️', p.x - 12, p.y + 35);
}
}
function drawTables() {
state.tables.forEach(table => {
ctx.fillStyle = '#8B4513';
ctx.fillRect(table.x, table.y, table.size, table.size);
if (table.customer) {
const cust = table.customer;
ctx.fillStyle = cust.color;
ctx.beginPath();
ctx.arc(table.x + table.size/2, table.y + table.size/2, 20, 0, Math.PI*2);
ctx.fill();
}
let icon = '';
switch (table.state) {
case 'waiting_to_order': icon = '💬'; break;
case 'waiting_for_food': icon = '🕒'; break;
case 'eating': icon = '🍔'; break;
case 'finished_eating': icon = '💰'; break;
case 'needs_clearing': icon = '🍽️'; break;
}
if (icon) {
ctx.font = '30px Arial';
ctx.fillText(icon, table.x + table.size / 2 - 15, table.y - 10);
}
});
}
function drawCustomers() {
let waitingLineX = state.stations.entrance.x + state.stations.entrance.width / 2;
let waitingLineY = state.stations.entrance.y - 40;
state.customers.forEach((cust, index) => {
if(cust.state === 'waiting_for_table') {
ctx.fillStyle = cust.color;
ctx.beginPath();
ctx.arc(waitingLineX, waitingLineY - (index * 50), 20, 0, Math.PI * 2);
ctx.fill();
// Patience meter
const patiencePercent = cust.patience / config.patienceTime;
ctx.fillStyle = patiencePercent > 0.5 ? 'green' : (patiencePercent > 0.2 ? 'orange' : 'red');
ctx.fillRect(waitingLineX - 20, waitingLineY - (index * 50) - 30, 40 * patiencePercent, 5);
}
});
}
function drawStations() {
// Entrance Mat
ctx.fillStyle = '#a9a9a9';
ctx.fillRect(state.stations.entrance.x, state.stations.entrance.y, state.stations.entrance.width, state.stations.entrance.height);
ctx.fillStyle = '#333';
ctx.font = '14px Arial';
ctx.fillText('ENTRANCE', state.stations.entrance.x + 5, state.stations.entrance.y + 30);
// Kitchen Window
ctx.fillStyle = '#ddd';
ctx.fillRect(state.stations.kitchenWindow.x, state.stations.kitchenWindow.y, state.stations.kitchenWindow.width, state.stations.kitchenWindow.height);
ctx.fillStyle = '#333';
ctx.fillText('KITCHEN', state.stations.kitchenWindow.x+5, state.stations.kitchenWindow.y+20);
// Ready Food display
state.kitchen.readyFood.forEach((food, i) => {
ctx.font = '30px Arial';
ctx.fillText('🍔', state.stations.kitchenWindow.x + 15, state.stations.kitchenWindow.y + 50 + i * 30);
});
// Dishwashing station
ctx.fillStyle = '#add8e6';
ctx.fillRect(state.stations.dishes.x, state.stations.dishes.y, state.stations.dishes.width, state.stations.dishes.height);
ctx.fillStyle = '#333';
ctx.fillText('DISHES', state.stations.dishes.x+10, state.stations.dishes.y+20);
}
function drawUI() {
ctx.fillStyle = 'black';
ctx.font = '24px Arial';
ctx.fillText(`Score: ${state.score}`, 20, 30);
// Instructions
ctx.font = '14px Arial';
ctx.fillStyle = '#444';
ctx.fillText("How to Play:", 250, 530);
ctx.fillText("1. Click waiting customer, then click an empty table to seat them.", 250, 550);
ctx.fillText("2. Click the seated customer (💬) to take their order.", 250, 570);
ctx.fillText("3. Take the order (📝) to the kitchen, then bring the food (🍔) back.", 250, 590);
}
function drawGameOver() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '60px Arial';
ctx.textAlign = 'center';
ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2 - 40);
ctx.font = '30px Arial';
ctx.fillText(`Final Score: ${state.score}`, canvas.width / 2, canvas.height / 2 + 20);
ctx.font = '20px Arial';
ctx.fillText('Refresh to play again', canvas.width / 2, canvas.height / 2 + 60);
ctx.textAlign = 'left';
}
// --- UPDATE FUNCTIONS ---
function updatePlayer(deltaTime) {
const p = state.player;
if (isAtTarget(p)) {
// Arrived at destination, perform action
handleArrival();
return;
}
const dx = p.targetX - p.x;
const dy = p.targetY - p.y;
const dist = Math.sqrt(dx * dx + dy * dy);
const moveX = (dx / dist) * config.playerSpeed * deltaTime;
const moveY = (dy / dist) * config.playerSpeed * deltaTime;
p.x += moveX;
p.y += moveY;
}
function updateCustomers(deltaTime) {
// Spawn new customers
if (Date.now() - state.lastSpawn > config.customerSpawnTime) {
if (state.customers.filter(c => c.state === 'waiting_for_table').length < 4) {
state.customers.push({
id: Math.random(),
state: 'waiting_for_table',
patience: config.patienceTime,
color: `hsl(${Math.random() * 360}, 50%, 50%)`
});
}
state.lastSpawn = Date.now();
}
// Update existing customers
for (let i = state.customers.length - 1; i >= 0; i--) {
const cust = state.customers[i];
cust.patience -= deltaTime * 1000;
if (cust.patience <= 0) {
// Customer leaves angry
if (cust.tableId !== undefined) {
const table = state.tables[cust.tableId];
table.state = 'empty';
table.customer = null;
}
state.customers.splice(i, 1);
state.score += config.patiencePenalty;
if(state.score < 0) state.gameOver = true;
continue;
}
if(cust.state === 'eating') {
if(!cust.eatTimer) cust.eatTimer = config.eatTime;
cust.eatTimer -= deltaTime * 1000;
if(cust.eatTimer <= 0) {
cust.state = 'finished_eating';
state.tables[cust.tableId].state = 'finished_eating';
}
}
}
}
function updateKitchen(deltaTime) {
for (let i = state.kitchen.orders.length - 1; i >= 0; i--) {
const order = state.kitchen.orders[i];
order.timer -= deltaTime * 1000;
if(order.timer <= 0) {
state.kitchen.readyFood.push({ forTable: order.forTable});
state.kitchen.orders.splice(i, 1);
}
}
}
// --- CORE LOGIC ---
function handleArrival() {
const p = state.player;
// logic is handled by the click handler assigning a target and an onArrival callback
if(p.onArrival) {
p.onArrival();
// Reset target and callback to prevent re-triggering
p.targetX = p.x;
p.targetY = p.y;
p.onArrival = null;
}
}
function handleCanvasClick(event) {
if(state.gameOver) return;
const rect = canvas.getBoundingClientRect();
const clickPos = {
x: event.clientX - rect.left,
y: event.clientY - rect.top
};
const p = state.player;
// 1. Check for clicks on tables
for (const table of state.tables) {
if (isPointInRect(clickPos, {x: table.x, y: table.y, width: table.size, height: table.size})) {
// SEAT a selected customer
if (table.state === 'empty' && p.selectedCustomer) {
const customerToSeat = p.selectedCustomer;
p.targetX = table.x + table.size / 2;
p.targetY = table.y - 20;
p.onArrival = () => {
table.state = 'waiting_to_order';
table.customer = customerToSeat;
customerToSeat.state = 'seated';
customerToSeat.tableId = table.id;
customerToSeat.patience = config.patienceTime * 1.5; // More patient once seated
state.customers = state.customers.filter(c => c.id !== customerToSeat.id);
p.selectedCustomer = null;
};
return; // Action set, exit click handler
}
// TAKE ORDER
if (table.state === 'waiting_to_order' && !p.carrying) {
p.targetX = table.x + table.size / 2;
p.targetY = table.y - 20;
p.onArrival = () => {
p.carrying = { type: 'order', forTable: table.id };
table.state = 'waiting_for_food';
}
return;
}
// DELIVER FOOD
if (table.state === 'waiting_for_food' && p.carrying?.type === 'food' && p.carrying.forTable === table.id) {
p.targetX = table.x + table.size / 2;
p.targetY = table.y - 20;
p.onArrival = () => {
p.carrying = null;
table.state = 'eating';
table.customer.state = 'eating';
}
return;
}
// COLLECT MONEY
if (table.state === 'finished_eating' && !p.carrying) {
p.targetX = table.x + table.size / 2;
p.targetY = table.y - 20;
p.onArrival = () => {
state.score += config.pointsPerCustomer;
table.state = 'needs_clearing';
table.customer = null;
}
return;
}
// CLEAR DISHES
if(table.state === 'needs_clearing' && !p.carrying) {
p.targetX = table.x + table.size / 2;
p.targetY = table.y - 20;
p.onArrival = () => {
p.carrying = { type: 'dishes', fromTable: table.id };
table.state = 'being_cleaned';
}
return;
}
}
}
// 2. Click on waiting customers at entrance
const waitingCustomers = state.customers.filter(c => c.state === 'waiting_for_table');
for(let i=0; i < waitingCustomers.length; i++) {
const cust = waitingCustomers[i];
let waitingLineX = state.stations.entrance.x + state.stations.entrance.width / 2;
let waitingLineY = state.stations.entrance.y - 40 - (i * 50);
if (distance(clickPos, {x: waitingLineX, y:waitingLineY}) < 20) {
if (!p.selectedCustomer) {
p.selectedCustomer = cust;
// No movement needed, just select them
}
return;
}
}
// 3. Click on stations
// Kitchen Window
if (isPointInRect(clickPos, state.stations.kitchenWindow)) {
// DROP OFF order
if (p.carrying?.type === 'order') {
p.targetX = state.stations.kitchenWindow.x - 20;
p.targetY = state.stations.kitchenWindow.y + state.stations.kitchenWindow.height / 2;
p.onArrival = () => {
state.kitchen.orders.push({forTable: p.carrying.forTable, timer: config.orderTime});
p.carrying = null;
}
return;
}
// PICK UP food
if (!p.carrying && state.kitchen.readyFood.length > 0) {
p.targetX = state.stations.kitchenWindow.x - 20;
p.targetY = state.stations.kitchenWindow.y + state.stations.kitchenWindow.height / 2;
p.onArrival = () => {
const food = state.kitchen.readyFood.shift();
p.carrying = {type: 'food', forTable: food.forTable};
}
return;
}
}
// Dishes
if (isPointInRect(clickPos, state.stations.dishes)) {
if (p.carrying?.type === 'dishes') {
p.targetX = state.stations.dishes.x - 20;
p.targetY = state.stations.dishes.y + state.stations.dishes.height / 2;
p.onArrival = () => {
const tableId = p.carrying.fromTable;
state.tables[tableId].state = 'empty';
p.carrying = null;
}
return;
}
}
// 4. Click on floor to de-select customer
p.selectedCustomer = null;
p.targetX = clickPos.x;
p.targetY = clickPos.y;
p.onArrival = null;
}
// --- MAIN GAME LOOP ---
function gameLoop(timestamp) {
if (!state.lastTime) {
state.lastTime = timestamp;
}
const deltaTime = (timestamp - state.lastTime) / 1000; // in seconds
state.lastTime = timestamp;
// UPDATE
if(!state.gameOver) {
updatePlayer(deltaTime);
updateCustomers(deltaTime);
updateKitchen(deltaTime);
}
// RENDER
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas
drawStations();
drawTables();
drawCustomers();
drawPlayer();
drawUI();
if(state.gameOver) {
drawGameOver();
}
requestAnimationFrame(gameLoop);
}
// --- INITIALIZATION ---
function init() {
setupTables();
canvas.addEventListener('click', handleCanvasClick);
state.lastSpawn = Date.now();
requestAnimationFrame(gameLoop);
}
init();
</script>
</body>
</html>
``````html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Server Simulator</title>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.game-container {
display: flex;
width: 900px;
height: 600px;
background-color: #fff;
border-radius: 10px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.restaurant-area {
width: 70%;
height: 100%;
background-color: #f8f8e8;
position: relative;
border-right: 2px solid #ddd;
}
.control-panel {
width: 30%;
height: 100%;
background-color: #f0f4f8;
padding: 15px;
overflow-y: auto;
}
.table {
position: absolute;
width: 60px;
height: 60px;
background-color: #c8a27c;
border: 2px solid #8b5a2b;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-weight: bold;
cursor: pointer;
}
.table:hover {
opacity: 0.9;
}
.table-occupied {
background-color: #e76f51;
}
.table-ready {
background-color: #2a9d8f;
}
.table-finished {
background-color: #e9c46a;
}
.customer {
position: absolute;
width: 40px;
height: 40px;
background-color: #3a86ff;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 12px;
}
.order-area {
margin-bottom: 20px;
}
margin-bottom: 10px;
font-size: 18px;
color: #333;
}
.order-list {
list-style-type: none;
padding: 0;
margin-bottom: 15px;
}
.order-item {
background-color: #e9ecef;
padding: 8px;
margin-bottom: 5px;
border-radius: 4px;
font-size: 14px;
}
.order-item.completed {
background-color: #d4edda;
text-decoration: line-through;
color: #155724;
}
.kitchen-area {
background-color: #e76f51;
color: white;
padding: 10px;
border-radius: 5px;
margin-bottom: 15px;
text-align: center;
cursor: pointer;
}
.kitchen-area:hover {
background-color: #d62828;
}
.kitchen-area.ready {
background-color: #2a9d8f;
}
.action-buttons {
display: flex;
flex-direction: column;
gap: 10px;
}
.btn {
padding: 10px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
text-align: center;
}
.btn-seat {
background-color: #2a9d8f;
color: white;
}
.btn-take-order {
background-color: #e9c46a;
color: #333;
}
.btn-pickup-meal {
background-color: #e76f51;
color: white;
}
.btn-serve {
background-color: #3a86ff;
color: white;
}
.btn-clear {
background-color: #8338ec;
color: white;
}
.btn-disabled {
background-color: #ccc;
color: #666;
cursor: not-allowed;
}
.status-bar {
display: flex;
justify-content: space-between;
padding: 10px;
background-color: #eee;
border-radius: 5px;
margin-bottom: 15px;
}
.timer {
font-weight: bold;
color: #d62828;
}
.score {
font-weight: bold;
color: #2a9d8f;
}
.message-log {
margin-top: 10px;
font-size: 12px;
color: #666;
max-height: 100px;
overflow-y: auto;
}
.menu-items {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 10px;
}
.menu-item {
background-color: #e9ecef;
padding: 5px 10px;
border-radius: 5px;
font-size: 12px;
cursor: pointer;
}
.menu-item:hover {
background-color: #dee2e6;
}
</style>
</head>
<body>
<div class="game-container">
<div class="restaurant-area" id="restaurantArea">
<!-- Tables will be generated by JavaScript -->
</div>
<div class="control-panel">
<h2>Control Panel</h2>
<div class="status-bar">
<div class="timer">Time: <span id="time">0</span>s</div>
<div class="score">Score: <span id="score">0</span></div>
</div>
<div class="order-area">
<h3>Current Orders</h3>
<ul id="orderList"></ul>
</div>
<div class="kitchen-area" id="kitchen">
<div>Kitchen</div>
<div id="kitchenStatus">No meals</div>
</div>
<div class="action-buttons">
<button class="btn btn-seat" id="btnSeat">Seat Customer</button>
<button class="btn btn-take-order btn-disabled" id="btnTakeOrder" disabled>Take Order</button>
<button class="btn btn-pickup-meal btn-disabled" id="btnPickupMeal" disabled>Pickup Meal</button>
<button class="btn btn-serve btn-disabled" id="btnServe" disabled>Serve Meal</button>
<button class="btn btn-clear btn-disabled" id="btnClear" disabled>Clear Table</button>
</div>
<div>
<h3>Take Order</h3>
<div class="menu-items">
<div class="menu-item" data-item="Burger">Burger</div>
<div class="menu-item" data-item="Pasta">Pasta</div>
<div class="menu-item" data-item="Salad">Salad</div>
<div class="menu-item" data-item="Steak">Steak</div>
<div class="menu-item" data-item="Pizza">Pizza</div>
</div>
</div>
<div class="message-log" id="messageLog"></div>
</div>
</div>
<script>
// Game state
const state = {
tables: [],
customers: [],
currentTable: null,
currentCustomer: null,
currentOrders: [],
kitchenMeal: null,
time: 0,
score: 0,
customerSpawnTimer: 0,
messages: []
};
// Table positions
const tablePositions = [
{ x: 100, y: 80, id: 1 },
{ x: 200, y: 80, id: 2 },
{ x: 300, y: 80, id: 3 },
{ x: 100, y: 200, id: 4 },
{ x: 200, y: 200, id: 5 },
{ x: 300, y: 200, id: 6 },
{ x: 100, y: 320, id: 7 },
{ x: 200, y: 320, id: 8 },
{ x: 300, y: 320, id: 9 }
];
// DOM elements
const restaurantArea = document.getElementById('restaurantArea');
const orderList = document.getElementById('orderList');
const kitchen = document.getElementById('kitchen');
const kitchenStatus = document.getElementById('kitchenStatus');
const btnSeat = document.getElementById('btnSeat');
const btnTakeOrder = document.getElementById('btnTakeOrder');
const btnPickupMeal = document.getElementById('btnPickupMeal');
const btnServe = document.getElementById('btnServe');
const btnClear = document.getElementById('btnClear');
const timeDisplay = document.getElementById('time');
const scoreDisplay = document.getElementById('score');
const messageLog = document.getElementById('messageLog');
// Initialize game
function initGame() {
// Create tables
tablePositions.forEach(pos => {
const table = {
id: pos.id,
x: pos.x,
y: pos.y,
status: 'empty', // empty, occupied, ready, finished
customer: null,
order: null
};
state.tables.push(table);
// Create table element
const tableElement = document.createElement('div');
tableElement.className = 'table';
tableElement.id = `table-${table.id}`;
tableElement.style.left = `${table.x}px`;
tableElement.style.top = `${table.y}px`;
tableElement.textContent = table.id;
tableElement.addEventListener('click', () => selectTable(table.id));
restaurantArea.appendChild(tableElement);
});
// Add event listeners to buttons
btnSeat.addEventListener('click', seatCustomer);
btnTakeOrder.addEventListener('click', startTakingOrder);
btnPickupMeal.addEventListener('click', pickupMeal);
btnServe.addEventListener('click', serveMeal);
btnClear.addEventListener('click', clearTable);
// Add event listeners to menu items
document.querySelectorAll('.menu-item').forEach(item => {
item.addEventListener('click', () => addOrder(item.dataset.item));
});
// Add click listener to kitchen
kitchen.addEventListener('click', checkKitchen);
// Start game loop
setInterval(gameLoop, 1000);
spawnCustomer();
}
// Game loop
function gameLoop() {
state.time++;
timeDisplay.textContent = state.time;
// Update kitchen status
if (state.kitchenMeal && state.kitchenMeal.readyTime <= state.time) {
kitchen.classList.add('ready');
kitchenStatus.textContent = `Ready: ${state.kitchenMeal.item}`;
}
// Update customer patience
state.customers.forEach(customer => {
if (customer.patience <= 0 && customer.table) {
// Customer leaves due to impatience
const table = state.tables.find(t => t.id === customer.table);
if (table) {
table.status = 'empty';
table.customer = null;
removeCustomerElement(customer.id);
logMessage(`Customer ${customer.id} left due to impatience!`);
}
const index = state.customers.indexOf(customer);
if (index > -1) {
state.customers.splice(index, 1);
}
updateTableUI(customer.table);
} else if (customer.table && customer.arrivalTime + customer.patience < state.time) {
customer.patience--;
}
});
// Spawn new customers occasionally
state.customerSpawnTimer++;
if (state.customerSpawnTimer >= 15) {
spawnCustomer();
state.customerSpawnTimer = 0;
}
}
// Spawn a new customer
function spawnCustomer() {
// Find empty table
const emptyTable = state.tables.find(table => table.status === 'empty');
if (!emptyTable) return;
const customerId = 'C' + Math.floor(Math.random() * 1000);
const customer = {
id: customerId,
table: emptyTable.id,
patience: 15, // Will leave after 15 seconds if not served
arrivalTime: state.time
};
state.customers.push(customer);
// Create customer element
const customerElement = document.createElement('div');
customerElement.className = 'customer';
customerElement.id = `customer-${customerId}`;
customerElement.textContent = customerId.charAt(1);
// Position customer near the entrance
customerElement.style.left = '650px';
customerElement.style.top = '280px';
restaurantArea.appendChild(customerElement);
// Animate customer to table
setTimeout(() => {
const table = state.tables.find(t => t.id === emptyTable.id);
if (table) {
customerElement.style.transition = 'all 1s';
customerElement.style.left = `${table.x - 20}px`;
customerElement.style.top = `${table.y - 20}px`;
// Update table status
table.status = 'occupied';
table.customer = customer;
updateTableUI(emptyTable.id);
logMessage(`Customer ${customerId} has arrived and is seated at Table ${emptyTable.id}`);
enableButton(btnTakeOrder);
}
}, 500);
emptyTable.customer = customer;
updateTableUI(emptyTable.id);
}
function removeCustomerElement(customerId) {
const customerElement = document.getElementById(`customer-${customerId}`);
if (customerElement) {
customerElement.remove();
}
}
// Select a table
function selectTable(tableId) {
const table = state.tables.find(t => t.id === tableId);
if (!table || table.status === 'empty') return;
state.currentTable = table;
state.currentCustomer = table.customer;
// Update button states
if (table.status === 'occupied' && !table.order) {
enableButton(btnTakeOrder);
} else if (table.status === 'occupied' && table.order && table.order.ready) {
enableButton(btnServe);
} else if (table.status === 'finished') {
enableButton(btnClear);
disableButton(btnTakeOrder);
disableButton(btnServe);
} else {
disableButton(btnTakeOrder);
disableButton(btnServe);
}
logMessage(`Selected Table ${tableId}`);
}
// Seat customer manually (if they're waiting)
function seatCustomer() {
// Find a customer waiting to be seated
const unseatedCustomer = state.customers.find(c => !c.table);
if (unseatedCustomer) {
// Find empty table
const emptyTable = state.tables.find(table => table.status === 'empty');
if (emptyTable) {
unseatedCustomer.table = emptyTable.id;
emptyTable.status = 'occupied';
emptyTable.customer = unseatedCustomer;
// Move customer to table
const customerElement = document.getElementById(`customer-${unseatedCustomer.id}`);
if (customerElement) {
customerElement.style.transition = 'all 1s';
customerElement.style.left = `${emptyTable.x - 20}px`;
customerElement.style.top = `${emptyTable.y - 20}px`;
}
updateTableUI(emptyTable.id);
logMessage(`Seated customer ${unseatedCustomer.id} at Table ${emptyTable.id}`);
enableButton(btnTakeOrder);
state.currentTable = emptyTable;
state.currentCustomer = unseatedCustomer;
}
} else {
logMessage("No waiting customers to seat");
// Try to spawn a customer if no unseated ones
spawnCustomer();
}
}
// Start taking an order
function startTakingOrder() {
if (!state.currentTable || state.currentTable.status !== 'occupied') {
logMessage("No customer to take order from");
return;
}
if (state.currentTable.order) {
logMessage("Order already taken");
return;
}
logMessage(`Taking order from Table ${state.currentTable.id}`);
logMessage("Select items from the menu");
// Clear any previous orders
state.currentOrders = [];
updateOrderList();
// Enable menu items
document.querySelectorAll('.menu-item').forEach(item => {
item.style.opacity = '1';
item.style.pointerEvents = 'auto';
});
}
// Add an item to the current order
function addOrder(item) {
if (state.currentOrders.length >= 3) {
logMessage("Maximum 3 items per order");
return;
}
state.currentOrders.push({ item, completed: false });
updateOrderList();
logMessage(`Added ${item} to order`);
}
// Update the order list display
function updateOrderList() {
orderList.innerHTML = '';
state.currentOrders.forEach(order => {
const li = document.createElement('li');
li.className = 'order-item';
if (order.completed) {
li.classList.add('completed');
}
li.textContent = order.item;
orderList.appendChild(li);
});
}
// Send order to kitchen
document.getElementById('btnTakeOrder').addEventListener('click', function() {
if (this.disabled) return;
if (!state.currentTable || state.currentTable.status !== 'occupied') {
logMessage("Cannot take order");
return;
}
if (state.currentOrders.length === 0) {
logMessage("No items in order");
return;
}
// Set the order on the table
state.currentTable.order = {
items: [...state.currentOrders],
ready: false
};
logMessage(`Order taken from Table ${state.currentTable.id}: ${state.currentOrders.map(o => o.item).join(', ')}`);
// Disable menu items
document.querySelectorAll('.menu-item').forEach(item => {
item.style.opacity = '0.5';
item.style.pointerEvents = 'none';
});
// Disable take order, enable wait for kitchen
disableButton(btnTakeOrder);
logMessage("Order sent to kitchen...");
// Schedule meal preparation
const preparationTime = 5; // seconds
state.kitchenMeal = {
tableId: state.currentTable.id,
item: state.currentOrders[0].item, // Simplified - just use first item
readyTime: state.time + preparationTime
};
kitchen.classList.remove('ready');
kitchenStatus.textContent = `Preparing: ${state.kitchenMeal.item}`;
enableButton(btnPickupMeal);
});
// Check kitchen for ready meals
function checkKitchen() {
if (state.kitchenMeal && state.kitchenMeal.readyTime <= state.time) {
logMessage(`Meal ready: ${state.kitchenMeal.item} for Table ${state.kitchenMeal.tableId}`);
enableButton(btnServe);
} else if (state.kitchenMeal) {
logMessage("Meal still being prepared...");
} else {
logMessage("No meals in preparation");
}
}
// Pick up meal from kitchen
function pickupMeal() {
if (!state.kitchenMeal || state.kitchenMeal.readyTime > state.time) {
logMessage("No meal ready to pickup");
return;
}
logMessage(`Picked up ${state.kitchenMeal.item} for Table ${state.kitchenMeal.tableId}`);
disableButton(btnPickupMeal);
enableButton(btnServe);
}
// Serve meal to customer
function serveMeal() {
if (!state.currentTable || state.currentTable.status !== 'occupied') {
logMessage("No customer to serve");
return;
}
if (!state.kitchenMeal || state.kitchenMeal.tableId !== state.currentTable.id) {
logMessage("This meal is for another table");
return;
}
// Mark order as ready
state.currentTable.order.ready = true;
// Update UI
logMessage(`Served ${state.kitchenMeal.item} to Table ${state.currentTable.id}`);
// Clear kitchen meal
state.kitchenMeal = null;
kitchen.classList.remove('ready');
kitchenStatus.textContent = "No meals";
disableButton(btnPickupMeal);
disableButton(btnServe);
disableButton(btnTakeOrder);
// Customer eats for a while
setTimeout(() => {
if (state.currentTable && state.currentTable.id === state.kitchenMeal?.tableId) {
state.currentTable.status = 'finished';
updateTableUI(state.currentTable.id);
enableButton(btnClear);
logMessage(`Customers at Table ${state.currentTable.id} have finished eating`);
}
}, 3000);
}
// Clear the table
function clearTable() {
if (!state.currentTable || state.currentTable.status !== 'finished') {
logMessage("Table is not ready to be cleared");
return;
}
// Remove customer
if (state.currentTable.customer) {
removeCustomerElement(state.currentTable.customer.id);
const customerIndex = state.customers.indexOf(state.currentTable.customer);
if (customerIndex > -1) {
state.customers.splice(customerIndex, 1);
}
}
// Clear table
state.currentTable.status = 'empty';
state.currentTable.customer = null;
state.currentTable.order = null;
updateTableUI(state.currentTable.id);
logMessage(`Table ${state.currentTable.id} cleared`);
disableButton(btnClear);
// Add score
state.score += 10;
scoreDisplay.textContent = state.score;
// Reset current selection
state.currentTable = null;
state.currentCustomer = null;
}
// Update table UI based on its state
function updateTableUI(tableId) {
const table = state.tables.find(t => t.id === tableId);
if (!table) return;
const tableElement = document.getElementById(`table-${tableId}`);
tableElement.className = 'table';
if (table.status === 'empty') {
tableElement.classList.add('table-ready');
} else if (table.status === 'occupied') {
tableElement.classList.add('table-occupied');
} else if (table.status === 'finished') {
tableElement.classList.add('table-finished');
}
}
// Helper functions for buttons
function enableButton(button) {
button.classList.remove('btn-disabled');
button.disabled = false;
}
function disableButton(button) {
button.classList.add('btn-disabled');
button.disabled = true;
}
function logMessage(message) {
const entry = document.createElement('div');
entry.textContent = `[${state.time}s] ${message}`;
messageLog.appendChild(entry);
messageLog.scrollTop = messageLog.scrollHeight;
// Limit log size
while (messageLog.children.length > 20) {
messageLog.removeChild(messageLog.children[0]);
}
}
// Initialize the game when page loads
window.onload = initGame;
</script>
</body>
</html>
``````html
<!DOCTYPE html>
<html>
<head>
<title>Restaurant Server Simulator</title>
<style>
body { margin: 0; overflow: hidden; }
#gameCanvas { background: #f0f0f0; }
#ui { position: absolute; top: 10px; left: 10px; color: white; }
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="ui">
<div>Score: <span id="score">0</span></div>
<div>Time: <span id="time">0</span>s</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;
class Server {
constructor() {
this.x = 400;
this.y = 300;
this.speed = 5;
this.holding = null;
}
move(dx, dy) {
this.x += dx * this.speed;
this.y += dy * this.speed;
}
}
class Table {
constructor(x, y) {
this.x = x;
this.y = y;
this.state = 'empty'; // empty, occupied, waiting_order, waiting_food, finished
this.customer = null;
this.order = null;
this.timer = 0;
}
draw() {
ctx.fillStyle = {
'empty': '#CCC',
'occupied': '#FFA',
'waiting_order': '#FAA',
'waiting_food': '#AFA',
'finished': '#F00'
}[this.state];
ctx.fillRect(this.x, this.y, 50, 50);
}
}
class Kitchen {
constructor() {
this.orders = [];
}
addOrder(order) {
this.orders.push({ item: order, timeLeft: 5 });
}
update() {
for (let i = this.orders.length - 1; i >= 0; i--) {
this.orders[i].timeLeft--;
if (this.orders[i].timeLeft <= 0) {
this.orders.splice(i, 1);
}
}
}
}
const server = new Server();
const tables = [
new Table(100, 100),
new Table(200, 100),
new Table(300, 100),
new Table(100, 200),
new Table(200, 200)
];
const kitchen = new Kitchen();
let customers = [];
let score = 0;
let time = 0;
function spawnCustomer() {
if (Math.random() < 0.02) {
const emptyTable = tables.find(t => t.state === 'empty');
if (emptyTable) {
emptyTable.state = 'occupied';
emptyTable.customer = { patience: 100 };
}
}
}
function update() {
time++;
spawnCustomer();
// Update customer patience
tables.forEach(table => {
if (table.state === 'occupied' || table.state === 'waiting_order') {
table.customer.patience--;
if (table.customer.patience <= 0) {
table.state = 'empty';
score -= 10;
}
}
});
// Update kitchen
kitchen.update();
// Update game state
requestAnimationFrame(draw);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw tables
tables.forEach(table => table.draw());
// Draw server
ctx.fillStyle = 'blue';
ctx.fillRect(server.x, server.y, 20, 20);
// Draw kitchen
ctx.fillStyle = '#0F0';
ctx.fillRect(700, 300, 50, 50);
// Update UI
document.getElementById('score').textContent = score;
document.getElementById('time').textContent = time;
}
document.addEventListener('keydown', (e) => {
switch(e.key) {
case 'ArrowUp': server.move(0, -1); break;
case 'ArrowDown': server.move(0, 1); break;
case 'ArrowLeft': server.move(-1, 0); break;
case 'ArrowRight': server.move(1, 0); break;
case ' ': // Space bar
// Check interactions
tables.forEach(table => {
if (Math.abs(server.x - table.x) < 30 && Math.abs(server.y - table.y) < 30) {
if (table.state === 'occupied') {
table.state = 'waiting_order';
} else if (table.state === 'waiting_order') {
table.state = 'waiting_food';
kitchen.addOrder('burger');
} else if (table.state === 'waiting_food' && server.holding) {
table.state = 'finished';
server.holding = null;
score += 20;
} else if (table.state === 'finished') {
table.state = 'empty';
score += 5;
}
}
});
// Check kitchen interaction
if (Math.abs(server.x - 700) < 30 && Math.abs(server.y - 300) < 30) {
if (kitchen.orders.length > 0 && !server.holding) {
server.holding = kitchen.orders.shift().item;
}
}
break;
}
});
setInterval(update, 1000/60);
</script>
</body>
</html>
``````html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restaurant Server Time-Management Game</title>
<style>
body {
background: #f0eee5;
font-family: 'Segoe UI', sans-serif;
margin: 0;
padding: 0;
user-select: none;
}
h1 { text-align: center; margin: 15px 0; }
#game {
margin: 0 auto;
background: #fff;
border: 2px solid #aaa;
width: 820px;
height: 600px;
position: relative;
border-radius: 8px;
box-shadow: 0 0 20px #aaa4;
overflow: hidden;
}
#tables {
display: flex;
justify-content: space-around;
align-items: flex-end;
position: absolute;
width: 700px;
left: 60px;
bottom: 130px;
z-index: 2;
}
.table {
background: #d8a87e;
width: 90px; height: 90px;
border-radius: 50%;
border: 3px solid #7b5e32;
margin: 0 10px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
cursor: pointer;
transition: box-shadow 0.2s;
}
.table.active {
box-shadow: 0 0 15px #ffd700cc, 0 0 8px #aa8c4a88 inset;
border-color: #ffda87;
}
.table .status {
position: absolute;
top: -34px;
left: 50%;
transform: translateX(-50%);
background: #fffbe0;
color: #7b5e32;
border: 1px solid #eec671;
border-radius: 20px;
font-size: 14px;
padding: 3px 9px;
min-width: 54px;
text-align: center;
font-weight: bold;
}
.table .emoji {
font-size: 28px;
}
.table .order-bubble {
position: absolute;
bottom: 96px;
left: 50%;
transform: translateX(-50%);
background: #f9ffe0;
color: #006c19;
border: 1px solid #8ae076;
border-radius: 12px;
padding: 3px 7px;
font-size: 18px;
pointer-events: none;
white-space: nowrap;
}
#waiting-area {
position: absolute;
left: 18px;
bottom: 40px;
width: 160px;
height: 80px;
border-radius: 16px;
display: flex;
align-items: center;
padding: 8px 8px;
background: #ffe2e0bb;
border: 2px dashed #b66969;
z-index: 2;
}
#waiting-area .customer {
margin: 0 7px 0 0;
filter: drop-shadow(1px 2px 1px #d09fa4);
opacity: 1;
transition: opacity 0.3s;
}
#waiting-area .customer.leave {
opacity: 0.2;
filter: grayscale(100%);
}
.customer {
font-size: 32px;
user-select: none;
cursor: pointer;
transition: transform 0.08s;
}
.customer.selected {
outline: 3px solid #aefabc;
border-radius: 50%;
transform: scale(1.1) rotate(-3deg);
background: #f6fff6;
}
#kitchen {
position: absolute;
right: 10px;
bottom: 38px;
width: 150px;
height: 85px;
background: #e7eadc;
border: 2px solid #7d9467;
border-radius: 14px;
display: flex;
flex-direction: column;
align-items: center;
z-index: 2;
padding: 8px 0;
}
#kitchen-title {
font-size: 14px;
color: #695936;
margin-bottom: 3px;
letter-spacing: 1px;
}
#prepared-dishes {
display: flex;
justify-content: center;
align-items: center;
}
.dish {
font-size: 28px;
margin: 0 5px;
cursor: pointer;
filter: drop-shadow(1px 2px 1px #a8c095);
transition: transform 0.08s;
}
.dish.selected {
outline: 2px solid #f7ea61;
background: #fffede;
border-radius: 10px;
transform: scale(1.11) rotate(3deg);
}
#order-panel {
position: absolute;
left: 50%;
bottom: 16px;
transform: translateX(-50%);
background: #fff6da;
border: 2px solid #f4c28b;
border-radius: 12px;
padding: 7px 24px 8px;
min-width: 210px;
box-shadow: 0 2px 10px #ead07a30;
font-size: 16px;
visibility: hidden;
z-index: 5;
}
#order-panel button {
background: #ffdf88;
border: none;
font-weight: bold;
color: #7b4f02;
padding: 4px 14px;
border-radius: 8px;
margin-left: 12px;
cursor: pointer;
transition: background 0.13s;
font-size: 14px;
}
#order-panel button:hover {
background: #ffe795;
}
#server {
position: absolute;
width: 74px;
height: 74px;
left: 370px;
top: 500px;
z-index: 3;
pointer-events: none;
transition: left 0.23s cubic-bezier(.7,1.9,.4,.7), top 0.23s cubic-bezier(.7,1.9,.4,.7);
filter: drop-shadow(1px 2px 4px #88340080);
font-size: 62px;
text-align: center;
line-height: 74px;
background: none;
}
#score-panel {
position: absolute;
top: 7px;
right: 24px;
background: #fff7e5;
border: 1px solid #e0ba87;
border-radius: 10px;
font-size: 18px;
padding: 5px 18px;
color: #724b09;
box-shadow: 0 1px 6px #c9b29e28;
z-index: 10;
}
#message {
position: absolute;
top: 58px;
left: 50%;
transform: translateX(-50%);
background: #efb681fc;
color: #fff;
font-weight: bold;
font-size: 28px;
border-radius: 9px;
padding: 7px 45px;
opacity: 0;
pointer-events: none;
z-index: 20;
text-shadow: 1px 2px 4px #8e6421c0;
transition: opacity 0.5s;
}
#start-panel {
position: absolute;
top: 55px;
left: 50%;
transform: translateX(-50%);
width: 340px;
background: #fff7ea;
border-radius: 14px;
border: 2px solid #fbc187;
text-align: center;
box-shadow: 0 2px 18px #dfa25a38;
font-family: inherit;
z-index: 90;
padding: 18px 28px 26px;
font-size: 16px;
}
#start-panel button {
margin-top: 18px;
padding: 7px 28px;
background: #ffdf77;
font-weight: bold;
border-radius: 8px;
border: none;
color: #7b4f02;
font-size: 20px;
box-shadow: 0 2px 13px #cea86025;
cursor: pointer;
transition: background 0.16s;
}
#start-panel button:hover {
background: #fff49c;
}
#instructions {
text-align: left;
font-size: 15px;
color: #945f2e;
margin-top: 6px;
margin-bottom: 8px;
line-height: 1.6em;
}
@media (max-width: 900px) {
#game { width: 98vw; }
}
@media (max-width: 870px) {
#tables { width: 97vw; left: 0; }
}
@media (max-width: 870px) {
#game { height: 91vh; }
}
</style>
</head>
<body>
<h1>🍔 Restaurant Server Time-Management Game</h1>
<div id="game">
<div id="score-panel">Score: <span id="score">0</span></div>
<div id="message"></div>
<div id="start-panel">
<h2>Welcome, Server!</h2>
<div id="instructions">
<b>How to Play:</b><br>
- <b>Seat customers</b> from the <span style="color:#d88;">waiting area</span> to empty tables<br>
- Click a table to <b>take their order</b><br>
- When a meal is prepared in the kitchen, <b>pick it up</b> and deliver it to the correct table<br>
- After eating, click the table to <b>clear it for the next customer</b><br>
Try to serve as many customers as possible!
</div>
<button id="btn-start">Start Game</button>
</div>
<div id="waiting-area"></div>
<div id="kitchen">
<div id="kitchen-title">KITCHEN</div>
<div id="prepared-dishes"></div>
</div>
<div id="tables"></div>
<div id="order-panel">
<span id="order-message"></span>
<button id="btn-order">Take Order</button>
<button id="btn-clear">Clear Table</button>
<button id="btn-deliver">Deliver Meal</button>
</div>
<div id="server">🧑🍳</div>
</div>
<script>
// GAME STATE
const TABLES_COUNT = 5, WAITING_SPOTS = 5;
const CUSTOMER_EMOJIS = ['🧔', '👩', '👦', '👵', '👴', '🧑🦰', '👨🦱', '👩🦱'];
const FOOD_EMOJIS = [
{name: "Burger", emoji: "🍔"},
{name: "Pizza", emoji: "🍕"},
{name: "Salad", emoji: "🥗"},
{name: "Fries", emoji: "🍟"},
{name: "Sushi", emoji: "🍣"},
{name: "Soup", emoji: "🥣"},
{name: "Steak", emoji: "🥩"}
];
let tables = [];
let waitingCustomers = [];
let preparedDishes = [];
let customerIdInc = 0;
let server = {
x: 370, y: 500,
carrying: null,
carryingType: null, // 'customer', 'dish'
destination: null
};
let selectedTableIdx = null;
let score = 0;
let gameRunning = false;
let intervalHandles = [];
let incomingCustomerTimeout = null;
// DOM references
const $tables = document.getElementById('tables');
const $waitingArea = document.getElementById('waiting-area');
const $preparedDishes = document.getElementById('prepared-dishes');
const $orderPanel = document.getElementById('order-panel');
const $orderMsg = document.getElementById('order-message');
const $btnOrder = document.getElementById('btn-order');
const $btnClear = document.getElementById('btn-clear');
const $btnDeliver = document.getElementById('btn-deliver');
const $score = document.getElementById('score');
const $server = document.getElementById('server');
const $message = document.getElementById('message');
const $startPanel = document.getElementById('start-panel');
const $btnStart = document.getElementById('btn-start');
function resetGame() {
tables = [];
waitingCustomers = [];
preparedDishes = [];
customerIdInc = 0;
server = { x: 370, y: 500, carrying: null, carryingType: null, destination: null };
selectedTableIdx = null;
score = 0;
$score.textContent = score;
$message.style.opacity = 0;
$orderPanel.style.visibility = 'hidden';
clearTimeout(incomingCustomerTimeout);
intervalHandles.forEach(h=>clearInterval(h));
intervalHandles = [];
// Create new tables
$tables.innerHTML = '';
for(let i=0;i<TABLES_COUNT;i++) {
tables.push({
state: 'empty', // empty, seated, ordered, served, eating, finished
customer: null,
order: null, // {food: {...}, status:[...]}
timer: null // {type: 'eating', ttl: ...}
});
}
updateView();
}
// CUSTOMER ARRIVAL & LEAVING
function getRandomCustomerEmoji() {
return CUSTOMER_EMOJIS[Math.floor(Math.random()*CUSTOMER_EMOJIS.length)];
}
function getRandomFood() {
return FOOD_EMOJIS[Math.floor(Math.random()*FOOD_EMOJIS.length)];
}
function incomingCustomerLoop() {
if (!gameRunning) return;
// Chance to add customer if waiting line not full
if (waitingCustomers.length < WAITING_SPOTS) {
let newCustomer = {
id: ++customerIdInc,
emoji: getRandomCustomerEmoji(),
patience: Math.floor(12 + Math.random()*9), // seconds before leaving
status: 'waiting', // 'waiting','leaving'
};
waitingCustomers.push(newCustomer);
// Timer to leave if not seated
newCustomer._leaveTimer = setTimeout(()=>{
newCustomer.status='leaving';
updateView();
setTimeout(()=>{
// Remove customer from waiting list
let idx = waitingCustomers.findIndex(c=>c.id===newCustomer.id);
if (idx>-1) waitingCustomers.splice(idx,1);
updateView();
},1300);
},newCustomer.patience*1000);
}
updateView();
// Next arrival (more frequent if less busy)
const nextIn = Math.floor(Math.random()*2000 + 2500 - waitingCustomers.length*350);
incomingCustomerTimeout = setTimeout(incomingCustomerLoop,nextIn);
}
// TABLE ACTIONS
function seatCustomer(tableIdx, customer) {
const table = tables[tableIdx];
if (table.state !== 'empty' || customer.status==='leaving') return false;
table.customer = customer;
table.state = 'seated';
waitingCustomers = waitingCustomers.filter(c=>c.id!==customer.id);
clearTimeout(customer._leaveTimer);
customer.status = "seated";
table.order = null;
updateView();
flyServerTo('table', tableIdx, ()=>{});
return true;
}
function takeOrder(tableIdx) {
const table = tables[tableIdx];
if (table.state !== 'seated') return false;
const food = getRandomFood();
table.order = { food: food, status: 'ordered' };
table.state = 'ordered';
updateView();
flyServerTo('table', tableIdx, ()=>{
showMessage("Order for " + food.emoji + "!", 1100);
setTimeout(()=>prepareDish({ tableIdx, food }), 900);
});
return true;
}
function prepareDish({tableIdx,food}) {
// Simulate kitchen prep time
setTimeout(()=>{
// Only prepare if order is still pending
const table = tables[tableIdx];
if (!gameRunning) return;
if(table.order && table.order.status==='ordered') {
preparedDishes.push({
food: food,
tableIdx: tableIdx,
id: Date.now() + Math.random(),
ready: true
});
updateView();
}
}, 1400+Math.random()*1000);
}
function deliverMeal(tableIdx, dishObj) {
const table = tables[tableIdx];
if (!table.order || table.order.status!=='ordered') return false;
if (dishObj.tableIdx !== tableIdx) return false;
// Remove from kitchen/prepared
preparedDishes = preparedDishes.filter(d=>d.id!==dishObj.id);
// Table receives meal
table.order.status = 'served';
table.state = 'eating';
updateView();
flyServerTo('table', tableIdx, ()=>{
showMessage("Meal delivered!",980);
// Eating time
table.timer && clearTimeout(table.timer);
table.timer = setTimeout(()=>{
table.state = 'finished';
updateView();
},2200+Math.random()*2000);
});
return true;
}
function clearTable(tableIdx) {
const table = tables[tableIdx];
if (table.state!=='finished') return false;
table.state = 'empty';
table.customer = null;
table.order = null;
updateView();
flyServerTo('table',tableIdx, ()=>{
showMessage("Table cleared!", 850);
score+=15; $score.textContent=score;
});
return true;
}
// VIEW/UI RENDERING
function updateView() {
$score.textContent = score;
// Render waiting area
$waitingArea.innerHTML = waitingCustomers.map((c,idx)=>
`<span class="customer ${server.carrying&&server.carryingType==='customer'&&server.carrying.id===c.id?'selected':''} ${c.status==='leaving'?'leave':''}"
data-customerid="${c.id}" draggable="false"
title="Patience: ${c.patience}s">${c.emoji}</span>`
).join('');
// Render tables
$tables.innerHTML = '';
tables.forEach((table,idx)=>{
let status = '';
if(table.state==='empty') status = 'Empty';
else if(table.state==='seated') status="Waiting";
else if(table.state==='ordered') status="Waiting";
else if(table.state==='eating') status="Eating";
else if(table.state==='finished') status="Done";
let customer = table.customer ?
`<span class="emoji">${table.customer.emoji}</span>`:'';
let orderBubble = '';
if(table.state==='ordered')
orderBubble = `<span class="order-bubble">${table.order.food.emoji}</span>`;
if(table.state==='eating')
orderBubble = `<span class="order-bubble">${table.order.food.emoji} <span style="font-size:15px;color:#9b8322;">🍴</span></span>`;
$tables.innerHTML += `
<div class="table${selectedTableIdx===idx?" active":""}" data-tableidx="${idx}">
<span class="status">${status}</span>
${customer}
${orderBubble}
</div>
`;
});
// Render prepared dishes
$preparedDishes.innerHTML = preparedDishes.map((dish,idx)=>
`<span class="dish ${server.carryingType==='dish'&&server.carrying&&server.carrying.id===dish.id?'selected':''}"
data-dishid="${dish.id}"
title="For Table ${dish.tableIdx+1}">${dish.food.emoji}</span>`
).join('');
updateOrderPanel();
updateServerUI();
}
function showMessage(str, ms=1500) {
$message.textContent = str;
$message.style.opacity = 1;
setTimeout(()=>{ $message.style.opacity = 0; }, ms);
}
// Handle order panel UI (action buttons)
function updateOrderPanel() {
if(selectedTableIdx === null) {
$orderPanel.style.visibility = 'hidden';
return;
}
const table = tables[selectedTableIdx];
$orderPanel.style.visibility = 'visible';
let rect = $tables.children[selectedTableIdx].getBoundingClientRect();
let gameRect = document.getElementById('game').getBoundingClientRect();
// Position panel above table
$orderPanel.style.left = (rect.left+rect.width/2-gameRect.left)+'px';
$orderPanel.style.top = (rect.top-40-gameRect.top)+'px';
$btnClear.style.display = table.state==='finished'?'':'none';
$btnOrder.style.display = table.state==='seated'?'':'none';
$btnDeliver.style.display = table.state==='ordered'?'':'none';
if(table.state==='seated') {
$orderMsg.textContent = "Take their order:";
} else if (table.state==='finished') {
$orderMsg.textContent = "Table ready to clear.";
} else if(table.state==='ordered') {
$orderMsg.textContent = "Deliver correct meal!";
} else {
$orderMsg.textContent = "";
$orderPanel.style.visibility = 'hidden';
}
}
// Server character animation + carry
function flyServerTo(type, idx, cb) {
// Move to table/kitchen/waiting/customer/dish
let dst={x:server.x,y:server.y};
let el = null;
if(type==='table') {
el = $tables.children[idx];
let r = el.getBoundingClientRect(), g=document.getElementById('game').getBoundingClientRect();
dst.x = r.left-g.left+30; dst.y = r.top-g.top+12;
} else if(type==='waiting') {
el = $waitingArea; let r = el.getBoundingClientRect(), g=document.getElementById('game').getBoundingClientRect();
dst.x = r.left-g.left+24; dst.y = r.top-g.top+20;
} else if(type==='kitchen') {
el = $kitchen; let r = el.getBoundingClientRect(), g=document.getElementById('game').getBoundingClientRect();
dst.x = r.left-g.left+46; dst.y = r.top-g.top+20;
}
$server.style.left = dst.x+'px';
$server.style.top = dst.y+'px';
server.x=dst.x; server.y=dst.y;
setTimeout(cb,300);
}
function updateServerUI() {
// You could render what the server is carrying as a badge/emoji
let str = '🧑🍳';
if(server.carryingType==='customer'&&server.carrying)
str = server.carrying.emoji+'🧑🍳';
else if(server.carryingType==='dish'&&server.carrying)
str = '🧑🍳'+server.carrying.food.emoji;
$server.innerHTML = str;
}
// INTERACTION HANDLERS
// Click customer to pick them up
$waitingArea.addEventListener('click', e=>{
if(!gameRunning) return;
let span = e.target.closest('.customer');
if(!span) return;
let cid = Number(span.getAttribute('data-customerid'));
let customer = waitingCustomers.find(c=>c.id===cid);
if(customer && !server.carrying) {
server.carrying = customer;
server.carryingType = 'customer';
updateView();
}
});
// Click table to seat/serve/clear
$tables.addEventListener('click', e=>{
if(!gameRunning) return;
let tableDiv = e.target.closest('.table');
if(!tableDiv) return;
let idx = Number(tableDiv.getAttribute('data-tableidx'));
const table = tables[idx];
if(server.carryingType==='customer' && !table.customer && table.state==='empty') {
// Seat customer
seatCustomer(idx, server.carrying);
server.carrying = null; server.carryingType = null;
score+=10; $score.textContent=score;
showMessage("Customer seated!", 850);
} else if(server.carryingType==='dish' && table.state==='ordered' && table.order) {
// Deliver dish
if(deliverMeal(idx, server.carrying)) {
server.carrying = null; server.carryingType = null;
score+=25; $score.textContent=score;
}
} else {
// Select table (to show order/clear/deliver actions)
selectedTableIdx = idx; updateView();
}
});
// Deselect order panel by clicking outside
document.getElementById('game').addEventListener('click', function(e){
if(!this.contains(e.target)) return;
if(!e.target.closest('.table')) selectedTableIdx=null, updateView();
});
// Order Panel Buttons
$btnOrder.onclick = ()=>{
if(selectedTableIdx!==null) takeOrder(selectedTableIdx);
selectedTableIdx=null; updateView();
};
$btnClear.onclick = ()=>{
if(selectedTableIdx!==null) clearTable(selectedTableIdx);
selectedTableIdx=null; updateView();
};
// Click prepared dish to pick up
$preparedDishes.addEventListener('click', e=>{
if(!gameRunning) return;
let d = e.target.closest('.dish');
if(!d) return;
let dishid = (d.getAttribute('data-dishid'));
let dish = preparedDishes.find(di=>String(di.id)===String(dishid));
if(dish && !server.carrying) {
server.carrying = dish;
server.carryingType = 'dish';
flyServerTo('kitchen', 0, ()=>{});
updateView();
}
});
// Keyboard shortcuts
document.addEventListener('keydown', e=>{
if(!gameRunning) return;
if(e.key>='1' && e.key<='5') {
// select table
let idx = +e.key-1;
if(idx>=0 && idx<TABLES_COUNT) selectedTableIdx = idx, updateView();
}
if(e.key==='Escape') { selectedTableIdx=null; updateView(); }
});
// GAME LOOP (timers)
function startGame() {
resetGame();
gameRunning = true;
$startPanel.style.display='none';
showMessage("Day Started!",900);
incomingCustomerLoop();
// Table eating/cleanup check, per second
let h = setInterval(()=>{
if(!gameRunning) return;
tables.forEach((table,idx)=>{
// Decrease timers if needed
});
},870);
intervalHandles.push(h);
updateView();
}
$btnStart.onclick = ()=>{
$startPanel.style.display='none';
startGame();
};
// End game (when too many customers leave)
function checkGameOver() {
// (Optionally, end when 5 customers left, for demo)
let leftCount = 0;
waitingCustomers.forEach(c=>{ if(c.status==='leaving') leftCount++; });
if(leftCount>=3) {
endGame();
}
}
function endGame() {
gameRunning = false;
clearTimeout(incomingCustomerTimeout);
intervalHandles.forEach(h=>clearInterval(h));
showMessage("Game Over!",1800);
setTimeout(()=>{
$startPanel.style.display='';
$startPanel.innerHTML = `<h2>Game Over!</h2>
<div style="font-size:20px;margin:12px 0 10px;">Score: <b>${score}</b></div>
<div id="instructions"><b>Tip:</b> Try to keep all tables busy without letting too many customers leave.<br><br>Click <b>Restart</b> to play again!</div>
<button id="btn-start">Restart</button>
`;
// Need to rehook button
document.getElementById('btn-start').onclick = ()=>{
$startPanel.style.display='none'; startGame();
}
},2100);
}
// Leave checking loop
intervalHandles.push( setInterval(()=>{
if(!gameRunning) return;
checkGameOver();
}, 2000) );
// First load
resetGame();
</script>
</body>
</html>
```
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Restaurant Rush</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Fredoka:wght@400;600&display=swap');
* { box-sizing: border-box; }
body { margin: 0; font-family: 'Fredoka', cursive; background:#f3f7fb; user-select:none; overflow:hidden; }
#game { display:flex; height:100vh; gap:10px; }
#room { position:relative; background:#5eb0e5; flex:1 1 75%; padding:10px; overflow:hidden; }
#sidebar { background:#fff; flex:0 0 250px; padding:10px; display:flex; flex-direction:column; gap:10px; }
.table { width:90px; height:50px; background:#b87333; border:3px solid #622d18;
border-radius:6px; position:absolute; display:flex; align-items:center; justify-content:center;
font-size:17px; color:#fff; font-weight:600; cursor:pointer; }
.table.taken{ background:#d4a373; }
.customer { position:absolute; width:44px; height:44px; left:calc(50% - 22px); top:-54px;
background:#ffd34f; border-radius:50%; border:2px solid #333; font-size:26px;
display:flex; align-items:center; justify-content:center; }
.tip-coin { position:absolute; top:-20px; width:24px; height:24px; background:#ffd700;
border-radius:50%; animation:pop 0.3s; text-align:center; line-height:24px; }
@keyframes pop{0%{transform:scale(0);}100%{transform:scale(1);}}
#server { position:absolute; width:46px; height:46px; left:400px; top:300px;
background:#ec6262; border-radius:8px; transition:all 0.3s ease; cursor:pointer;
display:flex; align-items:center; justify-content:center; font-size:20px; }
#kitchen { position:absolute; bottom:5px; right:5px; width:120px; height:100px; font-size:30px;
display:flex; align-items:center; justify-content:center; }
.order-card { display:flex; gap:4px; align-items:center; margin-bottom:5px; }
.order-card span { background:#ffe082; padding:2px 5px; border-radius:4px; }
#status { background:#fafafa; border:1px solid #ccc; padding:10px; border-radius:8px; }
.btn { padding:10px; border:none; border-radius:6px; background:#28a745; color:#fff;
font-weight:600; cursor:pointer; }
</style>
</head>
<body>
<div id="game">
<div id="room">
<!-- Tables -->
<div class="table" data-id="0" style="left:120px;top:100px"></div>
<div class="table" data-id="1" style="left:350px;top:100px"></div>
<div class="table" data-id="2" style="left:580px;top:100px"></div>
<div class="table" data-id="3" style="left:120px;top:300px"></div>
<div class="table" data-id="4" style="left:350px;top:300px"></div>
<div class="table" data-id="5" style="left:580px;top:300px"></div>
<!-- Spawn (front door) -->
<div id="spawn" style="position:absolute;left:30px;top:30px;font-size:40px;">🚪</div>
<!-- Server -->
<div id="server">🍽️</div>
<!-- Visual Kitchen -->
<div id="kitchen">🍳</div>
</div>
<div id="sidebar">
<div style="font-size:20px;"><b>Restaurant Rush</b></div>
<div>Customers Served: <span id="served">0</span></div>
<div>Tips Earned: $<span id="tips">0</span></div>
<div id="status"></div>
<button class="btn" id="clearBtn">Clear Selected Item</button>
</div>
</div>
<script>
/* ========= CONSTANTS & GLOBAL STATE ========= */
const MENU = ['🍕','🍔','🍜','🍣','🥞','🌮'];
const tables = Array.from(document.querySelectorAll('.table')).map(el=>new Table(el));
const spawn = document.getElementById('spawn');
const server = document.getElementById('server');
const statusBox = document.getElementById('status');
const servedSpan = document.getElementById('served');
const tipsSpan = document.getElementById('tips');
const clearBtn = document.getElementById('clearBtn');
let serverItem = null; // What the server is carrying
let selectedTable = null; // Where player's next action targets
let queue = []; // Customers waiting at door
let served = 0, tips = 0;
/* ========= CLASSES ========= */
class Table {
constructor(el){
this.el = el;
this.customer = null; // emoji
this.order = null; // emoji
this.isWaiting = false; // waiting for meal?
this.isReady = false; // meal is cooked
this.isEaten = false; // ready for clearing
this.tip = 0; // dollar amount
this.el.addEventListener('click', ()=> setSelected(this));
}
setState(txt){
this.el.textContent = txt;
}
addTip(amount){
tips += amount;
tipsSpan.textContent = tips;
const coin = document.createElement('div');
coin.className='tip-coin';
coin.textContent='$'+amount;
this.el.appendChild(coin);
setTimeout(()=> coin.remove(), 1500);
}
}
class CustomerQueue {
constructor(){
this.spawnRate = 3_500; // ms
setInterval(()=> this.spawn(), this.spawnRate);
}
spawn(){
if(tables.some(t=>!t.customer)){
const emoji = ['👨🍳','👩🍳','👧','👦','👵','👴'][Math.floor(Math.random()*6)];
const cust = document.createElement('div');
cust.textContent = emoji;
cust.className='customer';
spawn.appendChild(cust);
queue.push(cust);
cust.addEventListener('click',()=> this.seat(cust));
}
}
seat(cust){
const target = tables.find(t=>!t.customer);
if(!target) return;
// Move customer to table
const box = spawn.getBoundingClientRect();
cust.style.position='fixed';
cust.style.left = box.left + 10 + 'px';
cust.style.top = box.top + 10 + 'px';
const end = target.el.getBoundingClientRect();
cust.style.transition='all .6s ease';
cust.style.left = end.left + 20 + 'px';
cust.style.top = end.top - 50 + 'px';
// After move, register at table
setTimeout(()=>{
queue = queue.filter(c=> c!==cust);
target.customer = cust.textContent;
target.setState(target.customer);
cust.remove();
// Customer sits at table and waits
setTimeout(()=> { // Think about order
if(!target.customer) return;
target.order = MENU[Math.floor(Math.random()*MENU.length)];
target.isWaiting = true;
statusBox.textContent = 'Table click to send order';
}, 1500);
}, 600);
}
}
/* ========= INTERACTION HELPERS ========= */
function moveServer(targetRect){
server.style.left = targetRect.left + 22 + 'px';
server.style.top = targetRect.top + 2 + 'px';
}
function setSelected(table){
selectedTable = table;
}
clearBtn.addEventListener('click',()=>{
serverItem = null;
server.textContent='🍽️';
});
/* ========= GAME LOOP ========= */
document.body.addEventListener('click', handleClick);
function handleClick(e){
const target = e.target;
// Kitchen click
if(target.closest('#kitchen')){
if(serverItem) return; // already carrying something
if(tables.some(t=>t.isReady)){
const readyTable = tables.find(t=>t.isReady);
serverItem = { type: 'meal', order: readyTable.order };
server.textContent = serverItem.order;
readyTable.isReady=false;
moveServer(target.getBoundingClientRect());
}
}
// Seated customer click
if(selectedTable){
const table = selectedTable;
// Take order -> send to kitchen
if(table.isWaiting && !serverItem){
table.isWaiting=false;
serverItem = { type: 'order', order: table.order };
server.textContent=table.order;
moveServer(table.el.getBoundingClientRect());
// Cancel further action until server submits order
setTimeout(()=>{
if(serverItem?.type==='order' && serverItem.order===table.order){
serverItem = null;
server.textContent='🍽️';
let cookTime = 2000 + Math.random()*3000 |0;
statusBox.textContent = 'Cooking '+table.order+'...';
setTimeout(()=>{
if(!table.customer) return;
table.isReady=true;
statusBox.textContent = 'Pick up meal at kitchen';
}, cookTime);
}
},600);
}
// Deliver the meal
else if(table.order && !table.isEaten && serverItem?.type==='meal' && serverItem.order===table.order){
table.isEaten=true;
serverItem = null;
server.textContent='🍽️';
table.setState(table.customer+'✅');
const eatTime = 3000 + Math.random()*2000 |0;
setTimeout(()=>{
if(!table.customer) return;
// Customer finishes, pays & leaves
const tipAmount = 1 + Math.random()*3 |0;
table.addTip(tipAmount);
served++;
servedSpan.textContent = served;
// Clear table
table.customer=null;
table.order=null;
table.setState('');
selectedTable=null;
}, eatTime);
}
}
}
/* ========= KICK IT OFF ========= */
const custQ = new CustomerQueue();
statusBox.textContent = 'Welcome! Seat customers by clicking them.';
</script>
</body>
</html>
``````html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restaurant Time-Management Game</title>
<style>
body { margin: 0; background: #f0f0f0; display: flex; justify-content: center; align-items: center; height: 100vh; }
canvas { border: 2px solid #333; background: #fff; }
</style>
</head>
<body>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
// Game constants
const TABLE_COUNT = 4;
const CUSTOMER_ARRIVAL_RATE = 5000; // ms
const ORDER_TIME = 3000; // ms to prepare order
const EATING_TIME = 5000; // ms
const PATIENCE_TIME = 15000; // ms before leaving angry
const TABLE_POSITIONS = [
{x: 100, y: 100},
{x: 300, y: 100},
{x: 100, y: 300},
{x: 300, y: 300}
];
const ENTRANCE = {x: 700, y: 300};
const KITCHEN = {x: 700, y: 100};
// Game state
let score = 0;
let customers = []; // Waiting customers at entrance
let tables = Array(TABLE_COUNT).fill().map(() => ({
occupied: false,
state: 'empty', // empty, waiting_order, ordering, waiting_food, eating, done
customer: null,
timer: 0
}));
let kitchenQueue = [];
let selectedCustomer = null;
let lastArrival = Date.now();
// Customer class
class Customer {
constructor() {
this.arrivalTime = Date.now();
this.color = `hsl(${Math.random()*360}, 70%, 50%)`;
}
}
// Draw functions
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw tables
TABLE_POSITIONS.forEach((pos, i) => {
ctx.fillStyle = tables[i].occupied ? '#ccc' : '#eee';
ctx.fillRect(pos.x, pos.y, 100, 100);
ctx.strokeRect(pos.x, pos.y, 100, 100);
if (tables[i].occupied) {
ctx.fillStyle = tables[i].customer.color;
ctx.fillRect(pos.x + 40, pos.y + 40, 20, 20);
ctx.fillStyle = '#000';
ctx.font = '12px Arial';
ctx.fillText(tables[i].state, pos.x + 10, pos.y + 20);
if (tables[i].state === 'waiting_order' || tables[i].state === 'waiting_food') {
const patience = (Date.now() - tables[i].timer) / PATIENCE_TIME;
ctx.fillStyle = `rgb(${255 * patience}, ${255 * (1 - patience)}, 0)`;
ctx.fillRect(pos.x, pos.y + 105, 100 * (1 - patience), 5);
}
}
});
// Draw entrance
ctx.fillStyle = '#aaf';
ctx.fillRect(ENTRANCE.x, ENTRANCE.y, 50, 50);
customers.forEach((cust, i) => {
ctx.fillStyle = cust.color;
ctx.fillRect(ENTRANCE.x + 10, ENTRANCE.y + 10 + i*30, 20, 20);
const patience = (Date.now() - cust.arrivalTime) / PATIENCE_TIME;
ctx.fillStyle = `rgb(${255 * patience}, ${255 * (1 - patience)}, 0)`;
ctx.fillRect(ENTRANCE.x, ENTRANCE.y + 55 + i*30, 50 * (1 - patience), 5);
});
// Draw kitchen
ctx.fillStyle = '#faa';
ctx.fillRect(KITCHEN.x, KITCHEN.y, 50, 50);
kitchenQueue.forEach((order, i) => {
ctx.fillStyle = '#000';
ctx.fillRect(KITCHEN.x + 10, KITCHEN.y + 10 + i*30, 20, 20);
const prep = (Date.now() - order.startTime) / ORDER_TIME;
ctx.fillStyle = '#0f0';
ctx.fillRect(KITCHEN.x, KITCHEN.y + 55 + i*30, 50 * prep, 5);
});
// Score
ctx.fillStyle = '#000';
ctx.font = '20px Arial';
ctx.fillText(`Score: ${score}`, 10, 30);
}
// Update game logic
function update() {
const now = Date.now();
// Customer arrival
if (now - lastArrival > CUSTOMER_ARRIVAL_RATE) {
customers.push(new Customer());
lastArrival = now;
}
// Update tables
tables.forEach(table => {
if (table.occupied) {
if (table.state === 'waiting_order' || table.state === 'waiting_food') {
if (now - table.timer > PATIENCE_TIME) {
table.occupied = false;
table.state = 'empty';
table.customer = null;
score -= 10; // Penalty
}
} else if (table.state === 'eating') {
if (now - table.timer > EATING_TIME) {
table.state = 'done';
}
}
}
});
// Update kitchen
kitchenQueue = kitchenQueue.filter(order => {
if (now - order.startTime > ORDER_TIME) {
return true; // Still waiting to be picked up
}
return true;
});
// Note: Kitchen queue items are removed when delivered
// Remove impatient waiting customers
customers = customers.filter(cust => now - cust.arrivalTime <= PATIENCE_TIME);
}
// Handle clicks
canvas.addEventListener('click', (e) => {
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
// Check entrance for selecting customer
if (x >= ENTRANCE.x && x <= ENTRANCE.x + 50 && y >= ENTRANCE.y && y <= ENTRANCE.y + 50 + customers.length*30) {
if (customers.length > 0) {
selectedCustomer = customers.shift();
}
return;
}
// Check tables for seating or actions
TABLE_POSITIONS.forEach((pos, i) => {
if (x >= pos.x && x <= pos.x + 100 && y >= pos.y && y <= pos.y + 100) {
if (selectedCustomer && !tables[i].occupied) {
tables[i].occupied = true;
tables[i].state = 'waiting_order';
tables[i].customer = selectedCustomer;
tables[i].timer = Date.now();
selectedCustomer = null;
} else if (tables[i].occupied) {
if (tables[i].state === 'waiting_order') {
tables[i].state = 'waiting_food';
tables[i].timer = Date.now();
kitchenQueue.push({tableIndex: i, startTime: Date.now()});
} else if (tables[i].state === 'waiting_food') {
// Check if order ready
const order = kitchenQueue.find(o => o.tableIndex === i);
if (order && Date.now() - order.startTime >= ORDER_TIME) {
tables[i].state = 'eating';
tables[i].timer = Date.now();
kitchenQueue = kitchenQueue.filter(o => o !== order);
}
} else if (tables[i].state === 'done') {
tables[i].occupied = false;
tables[i].state = 'empty';
tables[i].customer = null;
score += 20; // Reward
}
}
}
});
// Check kitchen for picking up (but in this sim, pickup is implicit in delivery click)
});
// Game loop
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
gameLoop();
</script>
</body>
</html>
```<!DOCTYPE html>
<html>
<head>
<title>Restaurant Server Time Management Game</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f5f5dc;
margin: 0;
padding: 20px;
}
.game-container {
display: flex;
flex-direction: column;
gap: 20px;
max-width: 800px;
margin: 0 auto;
}
.restaurant-area {
background-color: #ffffff;
border-radius: 10px;
padding: 15px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.tables-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
margin-bottom: 20px;
}
.table {
height: 100px;
border: 2px solid #333;
border-radius: 5px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
background-color: #8B4513;
color: white;
}
.customer {
background-color: #98FB98;
width: 30px;
height: 30px;
border-radius: 50%;
margin-bottom: 5px;
}
.order-status {
font-size: 12px;
text-align: center;
}
.kitchen {
height: 80px;
border: 2px solid #333;
display: flex;
justify-content: center;
align-items: center;
background-color: #A9A9A9;
margin-bottom: 20px;
}
.order-plate {
width: 40px;
height: 40px;
background-color: white;
border-radius: 50%;
margin: 0 10px;
display: none;
}
.queue-area {
height: 60px;
border: 2px solid #333;
display: flex;
align-items: center;
padding: 0 10px;
background-color: #ADD8E6;
margin-bottom: 20px;
}
.customer-in-queue {
background-color: #98FB98;
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 10px;
}
.controls {
display: flex;
justify-content: space-around;
margin-top: 20px;
}
button {
padding: 10px 20px;
border: none;
border-radius: 5px;
background-color: #4CAF50;
color: white;
cursor: pointer;
font-weight: bold;
}
.stats {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.score {
font-size: 18px;
font-weight: bold;
}
.message {
margin-top: 20px;
text-align: center;
font-weight: bold;
color: #FF4500;
}
</style>
</head>
<body>
<div class="game-container">
<div class="stats">
<div class="score">Score: <span id="score">0</span></div>
<div>Time: <span id="timer">60</span>s</div>
</div>
<div class="restaurant-area">
<h2>Waiting Customers</h2>
<div class="queue-area" id="queue">
<!-- Customers will appear here when waiting -->
</div>
<h2>Dining Area</h2>
<div class="tables-container" id="tables">
<!-- Tables will be generated here -->
</div>
<h2>Kitchen</h2>
<div class="kitchen" id="kitchen">
<div class="order-plate" id="plate1"></div>
<div class="order-plate" id="plate2"></div>
<div class="order-plate" id="plate3"></div>
</div>
<div class="controls">
<button id="seat-btn">Seat Customer</button>
<button id="order-btn">Take Order</button>
<button id="serve-btn">Serve Food</button>
<button id="clear-btn">Clear Table</button>
</div>
</div>
<div class="message" id="message"></div>
</div>
<script>
// Game state
const gameState = {
score: 0,
timeLeft: 60,
tables: [],
queue: [],
kitchenOrders: [],
activeOrders: [],
gameInterval: null,
customerInterval: null,
timerInterval: null
};
// DOM elements
const tablesContainer = document.getElementById('tables');
const queueArea = document.getElementById('queue');
const kitchen = document.getElementById('kitchen');
const scoreDisplay = document.getElementById('score');
const timerDisplay = document.getElementById('timer');
const messageDisplay = document.getElementById('message');
// Initialize tables
function initTables() {
tablesContainer.innerHTML = '';
for (let i = 0; i < 6; i++) {
const table = document.createElement('div');
table.className = 'table';
table.id = `table-${i}`;
table.innerHTML = `<div class="order-status">Table ${i+1}<br>Empty</div>`;
tablesContainer.appendChild(table);
// Initialize game state for tables
gameState.tables.push({
id: i,
element: table,
occupied: false,
customer: null,
order: null
});
}
}
// Generate a random customer
function generateCustomer() {
if (gameState.queue.length < 5) {
const customerId = Date.now();
const customer = {
id: customerId,
patience: 30 + Math.floor(Math.random() * 30), // 30-60 seconds
order: {
mealType: ['burger', 'pizza', 'salad'][Math.floor(Math.random() * 3)],
timeToCook: 5 + Math.floor(Math.random() * 10) // 5-15 seconds
}
};
gameState.queue.push(customer);
updateQueueDisplay();
// Customer patience countdown
customer.patienceTimer = setInterval(() => {
customer.patience--;
if (customer.patience <= 0) {
// Customer leaves if not seated in time
const index = gameState.queue.findIndex(c => c.id === customer.id);
if (index !== -1) {
gameState.queue.splice(index, 1);
updateQueueDisplay();
showMessage('A customer left because they waited too long!');
}
clearInterval(customer.patienceTimer);
}
}, 1000);
}
}
// Update queue display
function updateQueueDisplay() {
queueArea.innerHTML = '';
gameState.queue.forEach(customer => {
const customerElement = document.createElement('div');
customerElement.className = 'customer-in-queue';
customerElement.title = `${customer.order.mealType} (${customer.patience}s patience)`;
queueArea.appendChild(customerElement);
});
}
// Seat a customer
function seatCustomer() {
if (gameState.queue.length > 0) {
const emptyTable = gameState.tables.find(table => !table.occupied);
if (emptyTable) {
const customer = gameState.queue.shift();
clearInterval(customer.patienceTimer);
emptyTable.occupied = true;
emptyTable.customer = customer;
emptyTable.element.innerHTML = `
<div class="customer"></div>
<div class="order-status">Waiting to order</div>
`;
updateQueueDisplay();
} else {
showMessage('No available tables!');
}
} else {
showMessage('No customers waiting!');
}
}
// Take an order
function takeOrder() {
const tableWithWaitingCustomer = gameState.tables.find(table =>
table.occupied && table.customer && !table.order
);
if (tableWithWaitingCustomer) {
tableWithWaitingCustomer.order = tableWithWaitingCustomer.customer.order;
tableWithWaitingCustomer.element.innerHTML = `
<div class="customer"></div>
<div class="order-status">Order: ${tableWithWaitingCustomer.order.mealType}<br>Waiting to cook</div>
`;
// Add to active orders
gameState.activeOrders.push({
tableId: tableWithWaitingCustomer.id,
order: tableWithWaitingCustomer.order,
timeCooked: 0
});
} else {
showMessage('No customers ready to order!');
}
}
// Update kitchen orders
function updateKitchen() {
const plates = document.querySelectorAll('.order-plate');
// Clear plates
plates.forEach(plate => {
plate.style.display = 'none';
plate.textContent = '';
});
// Update active orders and display them
gameState.activeOrders.forEach((activeOrder, index) => {
if (index < plates.length) {
activeOrder.timeCooked++;
const plate = plates[index];
if (activeOrder.timeCooked >= activeOrder.order.timeToCook) {
plate.style.display = 'block';
plate.textContent = activeOrder.order.mealType.charAt(0).toUpperCase();
}
}
});
}
// Serve food
function serveFood() {
const plateToServe = document.querySelector('.order-plate[style*="display: block"]');
if (plateToServe) {
const plateIndex = Array.from(document.querySelectorAll('.order-plate')).indexOf(plateToServe);
const activeOrder = gameState.activeOrders[plateIndex];
if (activeOrder) {
const table = gameState.tables[activeOrder.tableId];
if (table && table.occupied) {
table.element.innerHTML = `
<div class="customer"></div>
<div class="order-status">Eating ${table.order.mealType}<br>${table.customer.patience}s left</div>
`;
// Remove from active orders
gameState.activeOrders.splice(plateIndex, 1);
plateToServe.style.display = 'none';
// Start eating and paying
table.customer.eatingTimer = setInterval(() => {
table.customer.patience--;
if (table.customer.patience <= 0) {
// Customer leaves and scores points
payAndClearTable(table);
gameState.score += 10;
scoreDisplay.textContent = gameState.score;
}
}, 1000);
}
}
} else {
showMessage('No food ready to serve!');
}
}
// Clear a table
function clearTable() {
const tableToClear = gameState.tables.find(table =>
table.occupied && table.order && table.customer.patience <= 0
);
if (tableToClear) {
payAndClearTable(tableToClear);
gameState.score += 10;
scoreDisplay.textContent = gameState.score;
} else {
showMessage('No tables ready to clear!');
}
}
// Helper function to pay and clear a table
function payAndClearTable(table) {
clearInterval(table.customer.eatingTimer);
table.occupied = false;
table.customer = null;
table.order = null;
table.element.innerHTML = `<div class="order-status">Table ${table.id+1}<br>Empty</div>`;
}
// Show message
function showMessage(msg) {
messageDisplay.textContent = msg;
setTimeout(() => {
messageDisplay.textContent = '';
}, 2000);
}
// Game timer
function startTimer() {
gameState.timerInterval = setInterval(() => {
gameState.timeLeft--;
timerDisplay.textContent = gameState.timeLeft;
if (gameState.timeLeft <= 0) {
endGame();
}
}, 1000);
}
// End game
function endGame() {
clearInterval(gameState.customerInterval);
clearInterval(gameState.timerInterval);
clearInterval(gameState.gameInterval);
document.getElementById('seat-btn').disabled = true;
document.getElementById('order-btn').disabled = true;
document.getElementById('serve-btn').disabled = true;
document.getElementById('clear-btn').disabled = true;
showMessage(`Game Over! Final Score: ${gameState.score}`);
}
// Initialize game
function initGame() {
initTables();
gameState.score = 0;
gameState.timeLeft = 60;
scoreDisplay.textContent = '0';
timerDisplay.textContent = '60';
// Reset intervals if they exist
if (gameState.customerInterval) clearInterval(gameState.customerInterval);
if (gameState.timerInterval) clearInterval(gameState.timerInterval);
if (gameState.gameInterval) clearInterval(gameState.gameInterval);
// Setup game loops
gameState.customerInterval = setInterval(generateCustomer, 8000);
gameState.gameInterval = setInterval(updateKitchen, 1000);
startTimer();
// Enable buttons
document.getElementById('seat-btn').disabled = false;
document.getElementById('order-btn').disabled = false;
document.getElementById('serve-btn').disabled = false;
document.getElementById('clear-btn').disabled = false;
}
// Event listeners
document.getElementById('seat-btn').addEventListener('click', seatCustomer);
document.getElementById('order-btn').addEventListener('click', takeOrder);
document.getElementById('serve-btn').addEventListener('click', serveFood);
document.getElementById('clear-btn').addEventListener('click', clearTable);
// Start game
initGame();
</script>
</body>
</html>```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Restaurant Time-Management Game</title>
<style>
body { font-family: sans-serif; background: #f5f5f5; margin: 0; padding: 20px; }
#game { display: flex; }
#tables { display: flex; gap: 10px; }
.table {
width: 120px; height: 120px;
background: #eee; border: 2px solid #ccc; border-radius: 8px;
position: relative; cursor: pointer;
display: flex; align-items: center; justify-content: center;
text-align: center;
user-select: none;
}
.table.empty { background: #fff; }
.table.waitingOrder { background: #ffecb3; }
.table.waitingFood { background: #ffe0b2; }
.table.eating { background: #c8e6c9; }
.table.needsClearing { background: #ef9a9a; }
.table span { position: absolute; bottom: 4px; font-size: 12px; }
#sidebar { margin-left: 20px; }
#sidebar div { margin-bottom: 10px; font-size: 18px; }
#log { margin-top: 20px; height: 150px; overflow-y: auto; background: #fff; padding: 10px; border: 1px solid #ccc; }
</style>
</head>
<body>
<h1>Restaurant Server Game</h1>
<div id="game">
<div id="tables"></div>
<div id="sidebar">
<div>Waiting Customers: <span id="queueCount">0</span></div>
<div>Ready Meals: <span id="readyMeals">0</span></div>
<div>Score: <span id="score">0</span></div>
<div>Click a table to interact based on its state.</div>
</div>
</div>
<div id="log"></div>
<script>
// Game parameters
const NUM_TABLES = 4;
const CUSTOMER_ARRIVAL_CHANCE = 0.3; // per tick
const COOK_TIME = 5; // seconds per order
const EAT_TIME = 8; // seconds per table
// Game state
let queueCount = 0;
let readyMeals = 0;
let score = 0;
// Tables
const tables = [];
// Kitchen orders
const kitchenOrders = [];
const tablesContainer = document.getElementById('tables');
const queueCountEl = document.getElementById('queueCount');
const readyMealsEl = document.getElementById('readyMeals');
const scoreEl = document.getElementById('score');
const logEl = document.getElementById('log');
function log(msg) {
const p = document.createElement('div');
p.textContent = `[${new Date().toLocaleTimeString()}] ${msg}`;
logEl.prepend(p);
}
// Initialize tables UI
for (let i = 0; i < NUM_TABLES; i++) {
const table = {
state: 'empty', // empty, waitingOrder, waitingFood, eating, needsClearing
eatTimer: 0,
el: document.createElement('div')
};
table.el.className = 'table empty';
table.el.innerHTML = `Table ${i+1}<span></span>`;
table.el.addEventListener('click', () => onTableClick(i));
tables.push(table);
tablesContainer.appendChild(table.el);
}
function updateUI() {
queueCountEl.textContent = queueCount;
readyMealsEl.textContent = readyMeals;
scoreEl.textContent = score;
tables.forEach((table, idx) => {
const el = table.el;
el.className = 'table ' + table.state;
const span = el.querySelector('span');
if (table.state === 'waitingFood') {
span.textContent = 'Waiting food';
} else if (table.state === 'eating') {
span.textContent = `Eating: ${table.eatTimer}s`;
} else if (table.state === 'needsClearing') {
span.textContent = 'Ready to clear';
} else if (table.state === 'waitingOrder') {
span.textContent = 'Needs order';
} else {
span.textContent = '';
}
});
}
function onTableClick(i) {
const table = tables[i];
switch (table.state) {
case 'empty':
if (queueCount > 0) {
queueCount--;
table.state = 'waitingOrder';
log(`Seated customer at Table ${i+1}`);
} else {
log(`No customers waiting to be seated.`);
}
break;
case 'waitingOrder':
// take order and send to kitchen
table.state = 'waitingFood';
kitchenOrders.push({ timer: COOK_TIME });
log(`Took order at Table ${i+1}, sent to kitchen.`);
break;
case 'waitingFood':
if (readyMeals > 0) {
readyMeals--;
table.state = 'eating';
table.eatTimer = EAT_TIME;
log(`Delivered meal to Table ${i+1}`);
} else {
log(`No meals ready to deliver.`);
}
break;
case 'needsClearing':
table.state = 'empty';
score++;
log(`Cleared Table ${i+1}. Score +1.`);
break;
default:
// eating: no action
log(`Table ${i+1} is currently eating.`);
}
updateUI();
}
// Game loop tick: 1 second
setInterval(() => {
// new customer arrival
if (Math.random() < CUSTOMER_ARRIVAL_CHANCE) {
queueCount++;
log(`A new customer arrived.`);
}
// kitchen orders
for (let i = kitchenOrders.length - 1; i >= 0; i--) {
kitchenOrders[i].timer--;
if (kitchenOrders[i].timer <= 0) {
readyMeals++;
kitchenOrders.splice(i, 1);
log(`A meal is ready in the kitchen.`);
}
}
// tables eating timers
tables.forEach((table, idx) => {
if (table.state === 'eating') {
table.eatTimer--;
if (table.eatTimer <= 0) {
table.state = 'needsClearing';
log(`Table ${idx+1} finished eating.`);
}
}
});
updateUI();
}, 1000);
// Initial UI
updateUI();
log("Game started.");
</script>
</body>
</html>
```### Time Management Game: Restaurant Server
Below is a simple implementation of the game you described using HTML, CSS, and JavaScript. The game is rendered directly in the browser.
#### Game Description
* The game simulates a restaurant where you control a server.
* Your task is to seat customers, take their orders, deliver food, and clear tables.
* The game ends when all customers have been served and tables are cleared.
#### Code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Server Game</title>
<style>
body {
font-family: Arial, sans-serif;
}
#game-container {
width: 800px;
margin: 40px auto;
text-align: center;
}
.table {
display: inline-block;
width: 100px;
height: 100px;
margin: 10px;
border: 1px solid black;
border-radius: 10px;
background-color: #f0f0f0;
padding: 10px;
}
.customer {
background-color: #ccc;
padding: 5px;
border-radius: 5px;
}
.kitchen {
margin-top: 20px;
padding: 10px;
border: 1px solid black;
border-radius: 10px;
background-color: #f0f0f0;
}
</style>
</head>
<body>
<div id="game-container">
<h1>Restaurant Server Game</h1>
<div id="tables-container"></div>
<div id="kitchen-container" class="kitchen"></div>
<div id="score-container">Score: 0</div>
<button id="start-button">Start Game</button>
</div>
<script>
class Customer {
constructor(id) {
this.id = id;
this.orderTime = Math.floor(Math.random() * 10000) + 5000; // Random order time between 5s and 15s
this.eatingTime = Math.floor(Math.random() * 10000) + 5000; // Random eating time between 5s and 15s
this.orderPlaced = false;
this.foodReady = false;
this.eatingFinished = false;
}
}
class Table {
constructor(id) {
this.id = id;
this.customer = null;
this.element = document.createElement('div');
this.element.classList.add('table');
this.element.innerText = `Table ${id}`;
}
seatCustomer(customer) {
this.customer = customer;
this.element.innerHTML += `<br><span class="customer">Customer ${customer.id}</span>`;
}
clearTable() {
this.customer = null;
this.element.innerHTML = `Table ${this.id}`;
}
}
class Game {
constructor() {
this.tables = [];
this.customers = [];
this.score = 0;
this.kitchen = [];
for (let i = 0; i < 5; i++) {
this.tables.push(new Table(i + 1));
}
this.tablesContainer = document.getElementById('tables-container');
this.kitchenContainer = document.getElementById('kitchen-container');
this.scoreContainer = document.getElementById('score-container');
this.startButton = document.getElementById('start-button');
this.startButton.addEventListener('click', () => this.startGame());
this.tables.forEach(table => {
this.tablesContainer.appendChild(table.element);
});
}
startGame() {
this.startButton.disabled = true;
this.generateCustomers();
this.gameLoop();
}
generateCustomers() {
for (let i = 0; i < 10; i++) {
this.customers.push(new Customer(i + 1));
}
}
gameLoop() {
// Seat customers at available tables
this.customers.forEach(customer => {
if (!customer.orderPlaced) {
const availableTable = this.tables.find(table => table.customer === null);
if (availableTable) {
availableTable.seatCustomer(customer);
customer.orderPlaced = true;
setTimeout(() => {
this.kitchen.push(customer);
this.updateKitchen();
}, customer.orderTime);
}
}
});
// Deliver food from kitchen
this.kitchen.forEach(customer => {
if (!customer.foodReady) {
customer.foodReady = true;
const table = this.tables.find(table => table.customer && table.customer.id === customer.id);
if (table) {
table.element.innerHTML += '<br>Food delivered';
this.score += 10;
this.updateScore();
setTimeout(() => {
customer.eatingFinished = true;
}, customer.eatingTime);
}
}
});
// Clear tables
this.tables.forEach(table => {
if (table.customer && table.customer.eatingFinished) {
table.clearTable();
this.customers = this.customers.filter(customer => customer.id !== table.customer.id);
this.kitchen = this.kitchen.filter(customer => customer.id !== table.customer.id);
this.updateKitchen();
this.score += 20;
this.updateScore();
}
});
if (this.customers.length > 0) {
setTimeout(() => this.gameLoop(), 1000);
} else {
this.gameOver();
}
}
updateKitchen() {
this.kitchenContainer.innerHTML = 'Kitchen: ';
this.kitchen.forEach(customer => {
this.kitchenContainer.innerHTML += `Customer ${customer.id} `;
});
}
updateScore() {
this.scoreContainer.innerText = `Score: ${this.score}`;
}
gameOver() {
alert('Game Over! Your final score is ' + this.score);
this.startButton.disabled = false;
}
}
const game = new Game();
</script>
</body>
</html>
```
### How to Run
1. Save the above code in an HTML file.
2. Open the HTML file in a web browser.
3. Click the "Start Game" button to begin.
### Gameplay
* Customers will be seated at available tables.
* Orders will be placed after a random time between 5s and 15s.
* Food will be delivered from the kitchen after the order is placed.
* Tables will be cleared after the customers finish eating.
* The game ends when all customers have been served and tables are cleared.
### Scoring
* 10 points for delivering food to a customer.
* 20 points for clearing a table.# Restaurant Server Time Management Game
I've created a complete time management game where you manage customers in a restaurant. You'll seat customers, take orders, deliver meals, and clear tables - all within a nostalgic pixel-art style design.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pixel Diner Dash</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a1a2e, #16213e);
color: #fff;
min-height: 100vh;
overflow: hidden;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.game-container {
width: 900px;
max-width: 95%;
background: rgba(10, 15, 35, 0.8);
border-radius: 20px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
padding: 20px;
position: relative;
border: 2px solid #4dffd1;
overflow: hidden;
}
.game-header {
text-align: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid #4dffd1;
}
h1 {
font-size: 2.5rem;
color: #4dffd1;
text-shadow: 0 0 10px rgba(77, 255, 209, 0.7);
margin-bottom: 10px;
font-weight: 800;
}
.game-subtitle {
font-size: 1.2rem;
opacity: 0.8;
}
.stats-container {
display: flex;
justify-content: space-around;
background: rgba(30, 40, 80, 0.7);
padding: 15px;
border-radius: 12px;
margin: 20px 0;
}
.stat {
text-align: center;
}
.stat-value {
font-size: 2.2rem;
font-weight: 700;
color: #ffcc66;
}
.stat-label {
font-size: 1rem;
opacity: 0.7;
}
.game-area {
display: flex;
height: 450px;
gap: 20px;
}
.left-panel {
flex: 1;
background: rgba(25, 35, 65, 0.7);
border-radius: 15px;
padding: 15px;
display: flex;
flex-direction: column;
border: 2px solid #ff7aaa;
}
.panel-title {
text-align: center;
padding-bottom: 10px;
margin-bottom: 15px;
border-bottom: 1px solid #ff7aaa;
color: #ff7aaa;
}
.waiting-area {
flex: 1;
background: rgba(20, 25, 50, 0.6);
border-radius: 10px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 15px;
overflow-y: auto;
}
.table-area {
flex: 2;
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 15px;
background: rgba(25, 35, 65, 0.7);
border-radius: 15px;
padding: 15px;
border: 2px solid #66b3ff;
}
.kitchen-area {
flex: 1;
background: rgba(25, 35, 65, 0.7);
border-radius: 15px;
padding: 15px;
display: flex;
flex-direction: column;
border: 2px solid #ffcc66;
}
.order-queue {
flex: 1;
background: rgba(20, 25, 50, 0.6);
border-radius: 10px;
padding: 10px;
display: flex;
flex-direction: column;
gap: 12px;
overflow-y: auto;
}
/* Customer elements */
.customer {
background: #35478c;
border-radius: 8px;
padding: 12px;
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
transition: all 0.3s;
position: relative;
overflow: hidden;
border: 2px solid #4a64b4;
}
.customer:hover {
transform: translateY(-3px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.customer.ready-to-order:after {
content: '💬';
position: absolute;
top: -8px;
right: -8px;
background: #ff6b6b;
border-radius: 50%;
width: 25px;
height: 25px;
display: flex;
justify-content: center;
align-items: center;
font-size: 14px;
animation: pulse 1.5s infinite;
}
.customer-patience {
height: 5px;
background: #555;
border-radius: 3px;
overflow: hidden;
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
.customer-patience-value {
height: 100%;
background: #4dffd1;
width: 100%;
transition: width 1s linear;
}
.customer-avatar {
width: 50px;
height: 50px;
background: #557;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
}
.customer-info {
flex: 1;
}
.customer-name {
font-weight: 600;
margin-bottom: 3px;
}
.customer-status {
font-size: 0.85rem;
opacity: 0.8;
}
/* Table elements */
.table {
background: #3d4052;
border-radius: 10px;
padding: 15px;
display: flex;
flex-direction: column;
gap: 15px;
border: 3px solid #625c4a;
position: relative;
overflow: hidden;
}
.table-number {
position: absolute;
top: 5px;
left: 5px;
background: #ffcc66;
color: #1a1a2e;
width: 25px;
height: 25px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-weight: 700;
}
.table-status {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 10px;
}
.table-dirty {
color: #aaa;
font-style: italic;
}
.action-btn {
background: #4dffd1;
color: #1a1a2e;
border: none;
padding: 8px 15px;
border-radius: 20px;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
margin-top: 10px;
outline: none;
}
.action-btn:hover {
background: #2ce5b4;
transform: scale(1.05);
}
.action-btn:disabled {
background: #555;
cursor: not-allowed;
transform: none;
}
/* Order elements */
.order {
background: #4c668a;
border-radius: 8px;
padding: 10px;
display: flex;
align-items: center;
gap: 10px;
border-left: 4px solid #66b3ff;
position: relative;
}
.order.ready {
border-left: 4px solid #4dffd1;
animation: highlight 2s infinite;
}
.order-food {
background: #ff9966;
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
}
.order-info {
flex: 1;
}
.order-table {
font-weight: 700;
}
/* Progress bars */
.progress-container {
height: 5px;
background: #555;
border-radius: 3px;
overflow: hidden;
margin-top: 5px;
}
.progress-value {
height: 100%;
background: #66b3ff;
}
/* Kitchen */
.kitchen-chef {
width: 80px;
height: 100px;
background: #555;
margin: 10px auto;
position: relative;
}
/* Tutorial and notifications */
.tutorial-box {
background: rgba(77, 255, 209, 0.1);
border: 1px solid #4dffd1;
border-radius: 8px;
padding: 15px;
margin-top: 20px;
}
.tutorial-title {
color: #4dffd1;
margin-bottom: 10px;
}
.tutorial-steps {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.tutorial-step {
flex: 1;
min-width: 120px;
text-align: center;
padding: 10px;
background: rgba(20, 25, 50, 0.6);
border-radius: 8px;
font-size: 0.9rem;
}
.tutorial-icon {
font-size: 24px;
margin-bottom: 5px;
display: block;
}
.notification {
position: fixed;
bottom: 20px;
right: 20px;
background: #ffcc66;
color: #1a1a2e;
padding: 12px 20px;
border-radius: 8px;
font-weight: 700;
transform: translateY(100px);
opacity: 0;
transition: all 0.3s;
}
.notification.show {
transform: translateY(0);
opacity: 1;
}
/* Animations */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
@keyframes highlight {
0% { box-shadow: 0 0 0 0 rgba(77, 255, 209, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(77, 255, 209, 0); }
100% { box-shadow: 0 0 0 0 rgba(77, 255, 209, 0); }
}
.applause {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
color: white;
z-index: 10;
opacity: 0;
pointer-events: none;
transition: opacity 0.5s;
}
.applause.show {
opacity: 1;
pointer-events: all;
}
.applause h2 {
font-size: 3rem;
color: #ffcc66;
margin-bottom: 20px;
text-shadow: 0 0 20px rgba(255, 204, 102, 0.8);
}
.money-burst {
font-size: 48px;
animation: moneyFall 2s forwards;
}
@keyframes moneyFall {
0% { transform: translateY(-100px) rotate(0deg); opacity: 1; }
100% { transform: translateY(300px) rotate(360deg); opacity: 0; }
}
</style>
</head>
<body>
<div class="game-container">
<div class="game-header">
<h1>PIXEL DINER DASH</h1>
<p class="game-subtitle">Serve customers quickly to maximize your earnings!</p>
</div>
<div class="stats-container">
<div class="stat">
<div class="stat-value" id="money">$0</div>
<div class="stat-label">EARNINGS</div>
</div>
<div class="stat">
<div class="stat-value" id="served">0</div>
<div class="stat-label">CUSTOMERS SERVED</div>
</div>
<div class="stat">
<div class="stat-value" id="time">02:00</div>
<div class="stat-label">TIME LEFT</div>
</div>
<div class="stat">
<div class="stat-value" id="rating">5.0</div>
<div class="stat-label">AVG. RATING</div>
</div>
</div>
<div class="game-area">
<div class="left-panel">
<div class="panel-title">WAITING AREA</div>
<div class="waiting-area" id="waitingArea">
<!-- Customers will appear here -->
</div>
</div>
<div class="table-area" id="tableArea">
<!-- Tables dynamically added -->
</div>
<div class="kitchen-area">
<div class="panel-title">KITCHEN ORDERS</div>
<div class="order-queue" id="orderQueue">
<!-- Orders will appear here -->
</div>
<div class="kitchen-chef"></div>
</div>
</div>
<div class="tutorial-box">
<div class="tutorial-title">HOW TO PLAY</div>
<div class="tutorial-steps">
<div class="tutorial-step">
<span class="tutorial-icon">👥</span>
Seat customers quickly
</div>
<div class="tutorial-step">
<span class="tutorial-icon">💬</span>
Take their orders
</div>
<div class="tutorial-step">
<span class="tutorial-icon">🍔</span>
Deliver the meals
</div>
<div class="tutorial-step">
<span class="tutorial-icon">🧹</span>
Clean tables
</div>
<div class="tutorial-step">
<span class="tutorial-icon">⏱️</span>
Manage time wisely!
</div>
</div>
</div>
<div class="notification" id="notification">+$15 Served successfully!</div>
</div>
<div class="applause" id="applauseScreen">
<h2>Level Complete!</h2>
<div id="finalScore">You earned: $0</div>
<button class="action-btn" id="restartButton">Play Again</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game state
const gameState = {
money: 0,
customersServed: 0,
timeLeft: 120, // 2 minutes
rating: 5.0,
gameActive: true,
tables: [
{ id: 1, status: 'empty', customerId: null, order: null, ready: false },
{ id: 2, status: 'empty', customerId: null, order: null, ready: false },
{ id: 3, status: 'empty', customerId: null, order: null, ready: false },
{ id: 4, status: 'empty', customerId: null, order: null, ready: false },
{ id: 5, status: 'empty', customerId: null, order: null, ready: false },
{ id: 6, status: 'empty', customerId: null, order: null, ready: false }
],
customers: [],
nextCustomerId: 1,
orders: [],
kitchenOrders: [],
nextOrderId: 1
};
// Food items
const menuItems = [
{ name: 'Burger', icon: '🍔', price: 12, prepTime: 20 },
{ name: 'Pizza', icon: '🍕', price: 18, prepTime: 25 },
{ name: 'Taco', icon: '🌮', price: 10, prepTime: 15 },
{ name: 'Sushi', icon: '🍣', price: 22, prepTime: 30 },
{ name: 'Pasta', icon: '🍝', price: 16, prepTime: 22 },
{ name: 'Salad', icon: '🥗', price: 14, prepTime: 18 }
];
// Customer data
const customerAvatars = ['👨', '👩', '👨🦰', '👩🦰', '👴', '👵', '👨🦱', '👩🦱'];
const customerNames = ['Alex', 'Sam', 'Taylor', 'Jordan', 'Casey', 'Morgan', 'Riley', 'Drew', 'Pat', 'Quinn'];
// DOM elements
const waitingArea = document.getElementById('waitingArea');
const tableArea = document.getElementById('tableArea');
const orderQueue = document.getElementById('orderQueue');
const moneyDisplay = document.getElementById('money');
const servedDisplay = document.getElementById('served');
const timeDisplay = document.getElementById('time');
const ratingDisplay = document.getElementById('rating');
const notification = document.getElementById('notification');
const applauseScreen = document.getElementById('applauseScreen');
const finalScore = document.getElementById('finalScore');
const restartButton = document.getElementById('restartButton');
// Initialize game
function initGame() {
// Start timers
setInterval(gameTimer, 1000);
setInterval(spawnCustomer, 5000);
setInterval(customerActions, 15000);
setInterval(kitchenWork, 2000);
// Render tables
renderTables();
// Start with two customers
spawnCustomer();
setTimeout(spawnCustomer, 2000);
}
// Function to spawn a new customer
function spawnCustomer() {
if (!gameState.gameActive) return;
if (gameState.customers.length >= 5) return; // Max 5 waiting
const customer = {
id: gameState.nextCustomerId++,
name: customerNames[Math.floor(Math.random() * customerNames.length)],
avatar: customerAvatars[Math.floor(Math.random() * customerAvatars.length)],
patience: 100,
order: null,
isOrdering: false,
isEating: false
};
gameState.customers.push(customer);
renderCustomers();
}
// Render customers in waiting area
function renderCustomers() {
waitingArea.innerHTML = '';
gameState.customers.forEach(customer => {
const customerEl = document.createElement('div');
customerEl.className = 'customer';
customerEl.dataset.id = customer.id;
customerEl.innerHTML = `
<div class="customer-avatar">${customer.avatar}</div>
<div class="customer-info">
<div class="customer-name">${customer.name}</div>
<div class="customer-status">Waiting to be seated</div>
</div>
<div class="customer-patience">
<div class="customer-patience-value" style="width: ${customer.patience}%"></div>
</div>
`;
customerEl.addEventListener('click', () => handleCustomerClick(customer.id));
waitingArea.appendChild(customerEl);
});
}
// Render tables
function renderTables() {
tableArea.innerHTML = '';
gameState.tables.forEach(table => {
const tableEl = document.createElement('div');
tableEl.className = 'table';
tableEl.dataset.id = table.id;
let statusContent = '';
let actionBtn = '';
if (table.status === 'occupied') {
const customer = gameState.customers.find(c => c.id === table.customerId);
if (customer) {
if (customer.isOrdering) {
statusContent = `
<div class="customer-avatar">${customer.avatar}</div>
<div class="customer-info">
<div class="customer-name">${customer.name}</div>
<div class="customer-status">Ready to order</div>
</div>
`;
actionBtn = '<button class="action-btn take-order-btn">Take Order</button>';
} else if (table.ready) {
statusContent = `
<div class="customer-avatar">${customer.avatar}</div>
<div class="customer-info">
<div class="customer-name">${customer.name}</div>
<div class="customer-status">Meal is ready!</div>
</div>
<div class="customer-food">${table.order?.icon || '🍽️'}</div>
`;
actionBtn = '<button class="action-btn deliver-btn">Deliver Food</button>';
} else {
statusContent = `
<div class="customer-avatar">${customer.avatar}</div>
<div class="customer-info">
<div class="customer-name">${customer.name}</div>
<div class="customer-status">Waiting for food</div>
</div>
<div class="progress-container">
<div class="progress-value" style="width: ${Math.random() * 30 + 70}%"></div>
</div>
`;
}
}
} else if (table.status === 'dirty') {
statusContent = '<div class="table-dirty">Dirty table<br>Needs cleaning</div>';
actionBtn = '<button class="action-btn clean-btn">Clean Table</button>';
} else {
statusContent = '<div class="table-status">Empty table<br>Ready for customer</div>';
}
tableEl.innerHTML = `
<div class="table-number">${table.id}</div>
<div class="table-status">${statusContent}</div>
${actionBtn}
`;
if (actionBtn) {
if (table.status === 'occupied' && customer?.isOrdering) {
tableEl.querySelector('.take-order-btn').addEventListener('click', () => takeOrder(table.id));
} else if (table.status === 'occupied' && table.ready) {
tableEl.querySelector('.deliver-btn').addEventListener('click', () => deliverFood(table.id));
} else if (table.status === 'dirty') {
tableEl.querySelector('.clean-btn').addEventListener('click', () => cleanTable(table.id));
}
}
tableArea.appendChild(tableEl);
});
}
// Render kitchen orders
function renderKitchen() {
orderQueue.innerHTML = '';
gameState.kitchenOrders.forEach(order => {
const orderEl = document.createElement('div');
orderEl.className = `order ${order.completed ? 'ready' : ''}`;
orderEl.dataset.id = order.id;
orderEl.innerHTML = `
<div class="order-food">${order.item.icon}</div>
<div class="order-info">
<div class="order-name">${order.item.name}</div>
<div class="order-table">Table #${order.tableId}</div>
</div>
<div class="progress-container">
<div class="progress-value" style="width: ${order.progress}%"></div>
</div>
`;
orderQueue.appendChild(orderEl);
});
}
// Handle customer click - seat customer if there's an empty table
function handleCustomerClick(customerId) {
const emptyTable = gameState.tables.find(table => table.status === 'empty');
if (!emptyTable) {
showNotification('No empty tables available!');
return;
}
const customer = gameState.customers.find(c => c.id === customerId);
if (!customer) return;
// Remove from waiting area
gameState.customers = gameState.customers.filter(c => c.id !== customerId);
// Add to table
emptyTable.status = 'occupied';
emptyTable.customerId = customerId;
// Set ordering to start after 3 seconds
setTimeout(() => {
customer.isOrdering = true;
renderTables();
}, 3000);
showNotification('Customer seated at table #' + emptyTable.id);
renderCustomers();
renderTables();
}
// Take order from a table
function takeOrder(tableId) {
const table = gameState.tables.find(t => t.id === tableId);
if (!table || table.status !== 'occupied') return;
const customer = gameState.customers.find(c => c.id === table.customerId);
if (!customer) return;
// Create an order
const foodItem = menuItems[Math.floor(Math.random() * menuItems.length)];
const order = {
id: gameState.nextOrderId++,
tableId: tableId,
item: foodItem,
completed: false,
progress: 0
};
// Add to kitchen orders
gameState.kitchenOrders.push(order);
// Update customer state
customer.isOrdering = false;
table.order = order;
showNotification('Order taken: ' + foodItem.name + ' for table #' + tableId);
renderTables();
renderKitchen();
}
// Kitchen work - progress orders
function kitchenWork() {
if (!gameState.gameActive) return;
gameState.kitchenOrders.forEach(order => {
if (!order.completed) {
order.progress += Math.random() * 20; // Random progress increase
if (order.progress >= 100) {
order.progress = 100;
order.completed = true;
// Mark table as ready
const table = gameState.tables.find(t => t.id === order.tableId);
if (table && table.status === 'occupied') {
table.ready = true;
renderTables();
}
showNotification('Order ready for table #' + order.tableId);
}
}
});
renderKitchen();
}
// Deliver food to table
function deliverFood(tableId) {
const table = gameState.tables.find(t => t.id === tableId);
if (!table || !table.ready) return;
const customer = gameState.customers.find(c => c.id === table.customerId);
if (!customer) return;
const order = table.order;
if (!order) return;
// Remove order from kitchen
gameState.kitchenOrders = gameState.kitchenOrders.filter(o => o.id !== order.id);
// Handle payment and stats update
const tip = (5 + Math.floor(Math.random() * 6)) / 10; // tip multiplier 0.5-1.0
const payment = Math.round(order.item.price * tip);
gameState.money += payment;
gameState.customersServed++;
moneyDisplay.textContent = '$' + gameState.money;
servedDisplay.textContent = gameState.customersServed;
// Update rating (random between 3.8 and 5.0)
gameState.rating = parseFloat((4.5 + Math.random() * 0.5).toFixed(1));
ratingDisplay.textContent = gameState.rating;
showNotification('+$' + payment + ' Table #' + tableId + ' paid!');
// Customer starts eating, then leaves after 5-8 seconds
customer.isEating = true;
table.ready = false;
setTimeout(() => {
// Customer leaves
table.status = 'dirty';
gameState.customers = gameState.customers.filter(c => c.id !== customer.id);
renderTables();
}, 5000 + Math.random() * 3000);
renderKitchen();
renderTables();
}
// Clean table
function cleanTable(tableId) {
const table = gameState.tables.find(t => t.id === tableId);
if (!table || table.status !== 'dirty') return;
table.status = 'empty';
table.customerId = null;
table.order = null;
table.ready = false;
showNotification('Table #' + tableId + ' cleaned and ready!');
renderTables();
}
// Game timer
function gameTimer() {
if (!gameState.gameActive) return;
gameState.timeLeft--;
const minutes = Math.floor(gameState.timeLeft / 60);
const seconds = gameState.timeLeft % 60;
timeDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
if (gameState.timeLeft <= 0) {
endGame();
}
}
// Customer actions (reduce patience, etc.)
function customerActions() {
if (!gameState.gameActive) return;
gameState.customers.forEach(customer => {
customer.patience -= Math.floor(Math.random() * 10 + 5);
if (customer.patience <= 0) {
// Customer leaves if patience runs out
gameState.customers = gameState.customers.filter(c => c.id !== customer.id);
gameState.rating = parseFloat(Math.max(1, gameState.rating - 0.2).toFixed(1));
ratingDisplay.textContent = gameState.rating;
if (gameState.rating <= 3.0) {
showNotification('⚠️ Customer left! Rating decreased');
}
}
});
renderCustomers();
}
// Show notification
function showNotification(message) {
notification.textContent = message;
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
}, 3000);
}
// End game
function endGame() {
gameState.gameActive = false;
finalScore.textContent = 'You earned: $' + gameState.money;
applauseScreen.classList.add('show');
// Create money burst effect
for (let i = 0; i < 15; i++) {
const money = document.createElement('div');
money.className = 'money-burst';
money.textContent = '💵';
money.style.left = Math.random() * 80 + 10 + '%';
money.style.animationDelay = i * 0.1 + 's';
applauseScreen.appendChild(money);
}
}
// Restart game
restartButton.addEventListener('click', () => {
location.reload();
});
// Start the game
initGame();
});
</script>
</body>
</html>
```
## Game Features
This "Pixel Diner Dash" game includes:
1. **Core Gameplay Loop**:
- Seat customers at tables
- Take food orders
- Deliver prepared meals
- Clear tables after customers leave
2. **Game Elements**:
- Real-time time management and scoring
- Customer patience system
- 6 tables to manage
- Kitchen order queue
- Economic system with earnings and tips
- Customer ratings
3. **User Interface**:
- Clean pixel art inspired design
- Real-time stat tracking
- Visual progress indicators
- Customer avatars and animations
- Feedback notifications
- End-game screen with earnings summary
4. **Game Mechanics**:
- 120-second game timer
- Random customer generation
- Order preparation with progress bars
- Table cleaning mechanic
- Tip system based on service speed
The game is fully playable and challenges you to manage multiple tasks efficiently - just like a real restaurant server!```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restaurant Rush</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
h1 {
text-align: center;
margin-top: 10px;
}
#game {
display: flex;
justify-content: center;
align-items: flex-start;
padding: 20px;
}
#tables-container {
display: grid;
grid-template-columns: repeat(2, 100px);
gap: 10px;
}
.table {
width: 100px;
height: 100px;
border: 2px solid;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
background-color: #f5f5f5;
transition: background-color 0.3s;
}
.available { border-color: green; background-color: #e0ffe0; }
.waiting { border-color: red; background-color: #ffe0e0; }
.order-taken { border-color: blue; background-color: #e0f0ff; }
.food-ready { border-color: orange; background-color: #fff0e0; }
.delivering { border-color: purple; background-color: #f0e0ff; }
#kitchen {
margin-left: 40px;
padding: 20px 40px;
border: 2px solid black;
border-radius: 10px;
background-color: #cccccc;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.score {
text-align: center;
margin: 10px 0;
}
.instructions {
text-align: center;
font-size: 14px;
color: #555;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="score"><strong>Score:</strong> <span id="score">0</span></div>
<div class="instructions">Click tables to take orders, then click again to deliver food</div>
<div id="game">
<div id="tables-container"></div>
<div id="kitchen">Kitchen</div>
</div>
<script>
const tablesContainer = document.getElementById('tables-container');
const kitchen = document.getElementById('kitchen');
const scoreDisplay = document.getElementById('score');
let score = 0;
const tables = [];
const foods = ['Burger', 'Pizza', 'Sushi', 'Pasta', 'Salad'];
// Initialize tables
for (let i = 0; i < 4; i++) {
const table = document.createElement('div');
table.className = 'table available';
tablesContainer.appendChild(table);
tables.push({
element: table,
status: 'available',
order: null
});
}
function updateScore() {
scoreDisplay.textContent = score;
}
function getRandomOrder() {
return foods[Math.floor(Math.random() * foods.length)];
}
function spawnCustomer() {
const available = tables.find(t => t.status === 'available');
if (available) {
available.status = 'waiting';
available.element.className = 'table waiting';
available.element.textContent = 'Customer';
}
}
function takeOrder(table) {
if (table.status === 'waiting') {
table.status = 'order-taken';
table.element.className = 'table order-taken';
table.element.textContent = 'Order Taken';
table.order = getRandomOrder();
setTimeout(() => {
table.status = 'food-ready';
table.element.className = 'table food-ready';
table.element.textContent = 'Deliver';
}, 3000);
}
}
function deliverFood(table) {
if (table.status === 'food-ready') {
table.status = 'delivering';
table.element.className = 'table delivering';
table.element.textContent = 'Eating...';
setTimeout(() => {
table.status = 'available';
table.element.className = 'table available';
table.element.textContent = '';
score++;
updateScore();
}, 4000);
}
}
// Customer arrival every 3-6 seconds
setInterval(() => {
if (Math.random() > 0.3) spawnCustomer();
}, 3000);
// Table click handler
tablesContainer.addEventListener('click', (e) => {
const table = tables.find(t => t.element === e.target);
if (!table) return;
if (table.status === 'waiting') {
takeOrder(table);
} else if (table.status === 'food-ready') {
deliverFood(table);
}
});
// Kitchen visual effect on hover (optional)
kitchen.addEventListener('mouseenter', () => {
kitchen.style.backgroundColor = '#bbbbbb';
});
kitchen.addEventListener('mouseleave', () => {
kitchen.style.backgroundColor = '#cccccc';
});
</script>
</body>
</html>
``````html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Rush - Time Management Game</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}
.game-container {
max-width: 1200px;
margin: 0 auto;
background-color: white;
border-radius: 10px;
padding: 20px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 10px;
background-color: #2c3e50;
color: white;
border-radius: 5px;
}
.score {
font-size: 18px;
font-weight: bold;
}
.timer {
font-size: 16px;
}
.restaurant-area {
display: grid;
grid-template-columns: 200px 1fr 200px;
gap: 20px;
margin-bottom: 20px;
}
.waiting-area {
background-color: #ecf0f1;
border-radius: 5px;
padding: 15px;
}
.dining-area {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 15px;
background-color: #f8f9fa;
padding: 20px;
border-radius: 5px;
min-height: 400px;
}
.kitchen {
background-color: #e8f4fd;
border-radius: 5px;
padding: 15px;
}
.customer {
background-color: #3498db;
color: white;
padding: 8px;
margin: 5px 0;
border-radius: 5px;
cursor: pointer;
text-align: center;
transition: all 0.3s ease;
}
.customer:hover {
background-color: #2980b9;
transform: scale(1.05);
}
.customer.angry {
background-color: #e74c3c;
}
.table {
background-color: #8b4513;
border-radius: 10px;
padding: 15px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
min-height: 100px;
display: flex;
flex-direction: column;
justify-content: center;
position: relative;
}
.table.empty {
background-color: #d2b48c;
border: 2px dashed #8b4513;
}
.table.occupied {
background-color: #8b4513;
color: white;
}
.table.needs-order {
background-color: #f39c12;
color: white;
animation: pulse 1s infinite;
}
.table.waiting-food {
background-color: #9b59b6;
color: white;
}
.table.ready-to-clear {
background-color: #27ae60;
color: white;
animation: pulse 1s infinite;
}
.table:hover {
transform: scale(1.05);
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.food-item {
background-color: #27ae60;
color: white;
padding: 8px;
margin: 5px 0;
border-radius: 5px;
cursor: pointer;
text-align: center;
transition: all 0.3s ease;
}
.food-item:hover {
background-color: #219a52;
transform: scale(1.05);
}
.patience-bar {
width: 100%;
height: 8px;
background-color: #ecf0f1;
border-radius: 4px;
margin-top: 5px;
overflow: hidden;
}
.patience-fill {
height: 100%;
background-color: #27ae60;
transition: all 0.3s ease;
border-radius: 4px;
}
.patience-fill.medium {
background-color: #f39c12;
}
.patience-fill.low {
background-color: #e74c3c;
}
.section-title {
font-weight: bold;
margin-bottom: 10px;
color: #2c3e50;
}
.game-over {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white;
padding: 40px;
border-radius: 10px;
box-shadow: 0 8px 16px rgba(0,0,0,0.3);
text-align: center;
z-index: 1000;
}
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
z-index: 999;
}
button {
background-color: #3498db;
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 10px;
}
button:hover {
background-color: #2980b9;
}
.instructions {
background-color: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
border-left: 4px solid #3498db;
}
</style>
</head>
<body>
<div class="game-container">
<div class="header">
<div class="score">Score: <span id="score">0</span></div>
<h1>Restaurant Rush</h1>
<div class="timer">Time: <span id="time">180</span>s</div>
</div>
<div class="instructions">
<strong>How to Play:</strong> Click customers to seat them → Click tables to take orders → Click prepared food to deliver → Click finished tables to clear them
</div>
<div class="restaurant-area">
<div class="waiting-area">
<div class="section-title">Waiting Customers</div>
<div id="waiting-customers"></div>
</div>
<div class="dining-area">
<div class="table empty" data-table="0">
<div>Table 1</div>
<div>Empty</div>
</div>
<div class="table empty" data-table="1">
<div>Table 2</div>
<div>Empty</div>
</div>
<div class="table empty" data-table="2">
<div>Table 3</div>
<div>Empty</div>
</div>
<div class="table empty" data-table="3">
<div>Table 4</div>
<div>Empty</div>
</div>
<div class="table empty" data-table="4">
<div>Table 5</div>
<div>Empty</div>
</div>
<div class="table empty" data-table="5">
<div>Table 6</div>
<div>Empty</div>
</div>
</div>
<div class="kitchen">
<div class="section-title">Ready Orders</div>
<div id="ready-orders"></div>
</div>
</div>
</div>
<script>
class RestaurantGame {
constructor() {
this.score = 0;
this.timeLeft = 180;
this.gameRunning = true;
this.selectedCustomer = null;
this.selectedFood = null;
this.customers = [];
this.tables = [];
this.readyOrders = [];
this.customerNames = ['Alice', 'Bob', 'Charlie', 'Diana', 'Eve', 'Frank', 'Grace', 'Henry'];
this.dishes = ['Burger', 'Pizza', 'Pasta', 'Salad', 'Steak', 'Fish', 'Soup', 'Sandwich'];
this.initializeTables();
this.bindEvents();
this.startGameLoop();
this.spawnCustomer();
}
initializeTables() {
for (let i = 0; i < 6; i++) {
this.tables.push({
id: i,
status: 'empty', // empty, occupied, needs-order, waiting-food, ready-to-clear
customer: null,
order: null,
patience: 100,
maxPatience: 100
});
}
}
bindEvents() {
document.getElementById('waiting-customers').addEventListener('click', (e) => {
if (e.target.classList.contains('customer')) {
this.selectCustomer(parseInt(e.target.dataset.customerId));
}
});
document.querySelector('.dining-area').addEventListener('click', (e) => {
if (e.target.closest('.table')) {
const tableId = parseInt(e.target.closest('.table').dataset.table);
this.handleTableClick(tableId);
}
});
document.getElementById('ready-orders').addEventListener('click', (e) => {
if (e.target.classList.contains('food-item')) {
this.selectFood(parseInt(e.target.dataset.orderId));
}
});
}
selectCustomer(customerId) {
// Clear previous selections
document.querySelectorAll('.customer').forEach(el => el.style.border = 'none');
this.selectedCustomer = customerId;
this.selectedFood = null;
const customerEl = document.querySelector(`[data-customer-id="${customerId}"]`);
if (customerEl) {
customerEl.style.border = '3px solid #f39c12';
}
// Clear food selection visual
document.querySelectorAll('.food-item').forEach(el => el.style.border = 'none');
}
selectFood(orderId) {
// Clear previous selections
document.querySelectorAll('.food-item').forEach(el => el.style.border = 'none');
this.selectedFood = orderId;
this.selectedCustomer = null;
const foodEl = document.querySelector(`[data-order-id="${orderId}"]`);
if (foodEl) {
foodEl.style.border = '3px solid #f39c12';
}
// Clear customer selection visual
document.querySelectorAll('.customer').forEach(el => el.style.border = 'none');
}
handleTableClick(tableId) {
const table = this.tables[tableId];
if (table.status === 'empty' && this.selectedCustomer !== null) {
this.seatCustomer(tableId, this.selectedCustomer);
} else if (table.status === 'needs-order') {
this.takeOrder(tableId);
} else if (table.status === 'waiting-food' && this.selectedFood !== null) {
this.deliverFood(tableId, this.selectedFood);
} else if (table.status === 'ready-to-clear') {
this.clearTable(tableId);
}
}
seatCustomer(tableId, customerId) {
const customer = this.customers.find(c => c.id === customerId);
const table = this.tables[tableId];
if (customer && table.status === 'empty') {
table.status = 'needs-order';
table.customer = customer;
table.patience = 100;
table.maxPatience = 100;
// Remove customer from waiting area
this.customers = this.customers.filter(c => c.id !== customerId);
this.selectedCustomer = null;
this.updateDisplay();
this.addScore(10);
}
}
takeOrder(tableId) {
const table = this.tables[tableId];
if (table.status === 'needs-order') {
const dish = this.dishes[Math.floor(Math.random() * this.dishes.length)];
table.order = dish;
table.status = 'waiting-food';
table.patience = 150;
table.maxPatience = 150;
// Add order to kitchen queue (will be ready after some time)
setTimeout(() => {
this.readyOrders.push({
id: Date.now(),
dish: dish,
tableId: tableId,
customer: table.customer.name
});
this.updateDisplay();
}, Math.random() * 3000 + 2000); // 2-5 seconds
this.updateDisplay();
this.addScore(15);
}
}
deliverFood(tableId, orderId) {
const table = this.tables[tableId];
const order = this.readyOrders.find(o => o.id === orderId);
if (table.status === 'waiting-food' && order && order.tableId === tableId) {
table.status = 'ready-to-clear';
table.patience = 100;
table.maxPatience = 100;
// Remove order from ready orders
this.readyOrders = this.readyOrders.filter(o => o.id !== orderId);
this.selectedFood = null;
// Customer will finish eating after some time
setTimeout(() => {
if (table.status === 'ready-to-clear') {
table.patience = 80; // Start getting impatient for clearing
table.maxPatience = 80;
}
}, Math.random() * 4000 + 3000); // 3-7 seconds
this.updateDisplay();
this.addScore(25);
}
}
clearTable(tableId) {
const table = this.tables[tableId];
if (table.status === 'ready-to-clear') {
table.status = 'empty';
table.customer = null;
table.order = null;
table.patience = 100;
table.maxPatience = 100;
this.updateDisplay();
this.addScore(20);
}
}
spawnCustomer() {
if (!this.gameRunning) return;
const name = this.customerNames[Math.floor(Math.random() * this.customerNames.length)];
const customer = {
id: Date.now(),
name: name,
patience: 100,
maxPatience: 100,
angry: false
};
this.customers.push(customer);
this.updateDisplay();
// Schedule next customer
setTimeout(() => this.spawnCustomer(), Math.random() * 4000 + 2000); // 2-6 seconds
}
updatePatience() {
// Update waiting customers patience
this.customers.forEach(customer => {
customer.patience -= 0.5;
if (customer.patience <= 0) {
customer.angry = true;
this.addScore(-10);
// Remove angry customer after a while
setTimeout(() => {
this.customers = this.customers.filter(c => c.id !== customer.id);
this.updateDisplay();
}, 2000);
}
});
// Update table patience
this.tables.forEach(table => {
if (table.status !== 'empty') {
table.patience -= 0.3;
if (table.patience <= 0) {
// Customer leaves angry
this.addScore(-30);
table.status = 'empty';
table.customer = null;
table.order = null;
table.patience = 100;
table.maxPatience = 100;
}
}
});
}
updateDisplay() {
// Update customers
const waitingArea = document.getElementById('waiting-customers');
waitingArea.innerHTML = '';
this.customers.forEach(customer => {
const customerEl = document.createElement('div');
customerEl.className = `customer ${customer.angry ? 'angry' : ''}`;
customerEl.dataset.customerId = customer.id;
customerEl.innerHTML = `
<div>${customer.name}</div>
<div class="patience-bar">
<div class="patience-fill ${customer.patience < 30 ? 'low' : customer.patience < 60 ? 'medium' : ''}"
style="width: ${customer.patience}%"></div>
</div>
`;
waitingArea.appendChild(customerEl);
});
// Update tables
this.tables.forEach(table => {
const tableEl = document.querySelector(`[data-table="${table.id}"]`);
tableEl.className = `table ${table.status}`;
let content = `<div>Table ${table.id + 1}</div>`;
switch (table.status) {
case 'empty':
content += '<div>Empty</div>';
break;
case 'needs-order':
content += `<div>${table.customer.name}</div><div>Needs Order</div>`;
break;
case 'waiting-food':
content += `<div>${table.customer.name}</div><div>Ordered: ${table.order}</div>`;
break;
case 'ready-to-clear':
content += `<div>${table.customer.name}</div><div>Finished Eating</div>`;
break;
}
if (table.status !== 'empty') {
content += `
<div class="patience-bar">
<div class="patience-fill ${table.patience < 30 ? 'low' : table.patience < 60 ? 'medium' : ''}"
style="width: ${(table.patience / table.maxPatience) * 100}%"></div>
</div>
`;
}
tableEl.innerHTML = content;
});
// Update ready orders
const readyArea = document.getElementById('ready-orders');
readyArea.innerHTML = '';
this.readyOrders.forEach(order => {
const orderEl = document.createElement('div');
orderEl.className = 'food-item';
orderEl.dataset.orderId = order.id;
orderEl.innerHTML = `
<div>${order.dish}</div>
<div>for ${order.customer}</div>
<div>Table ${order.tableId + 1}</div>
`;
readyArea.appendChild(orderEl);
});
// Update score and time
document.getElementById('score').textContent = this.score;
document.getElementById('time').textContent = this.timeLeft;
}
addScore(points) {
this.score += points;
if (this.score < 0) this.score = 0;
}
startGameLoop() {
const gameLoop = setInterval(() => {
if (!this.gameRunning) {
clearInterval(gameLoop);
return;
}
this.timeLeft--;
this.updatePatience();
this.updateDisplay();
if (this.timeLeft <= 0) {
this.endGame();
clearInterval(gameLoop);
}
}, 1000);
}
endGame() {
this.gameRunning = false;
const overlay = document.createElement('div');
overlay.className = 'overlay';
const gameOver = document.createElement('div');
gameOver.className = 'game-over';
gameOver.innerHTML = `
<h2>Time's Up!</h2>
<p>Final Score: ${this.score}</p>
<p>${this.getScoreMessage()}</p>
<button onclick="location.reload()">Play Again</button>
`;
document.body.appendChild(overlay);
document.body.appendChild(gameOver);
}
getScoreMessage() {
if (this.score >= 1000) return "Outstanding! You're a master server!";
if (this.score >= 750) return "Excellent work! Customers love you!";
if (this.score >= 500) return "Good job! You're getting the hang of it!";
if (this.score >= 250) return "Not bad! Keep practicing!";
return "Room for improvement! Try to serve customers faster!";
}
}
// Start the game when the page loads
window.addEventListener('load', () => {
new RestaurantGame();
});
</script>
</body>
</html>
```
This is a fully functional restaurant time management game that includes:
**Core Features:**
- **Customer Management**: Customers spawn automatically and wait to be seated
- **Table System**: 6 tables that cycle through states (empty → seated → order taken → waiting for food → eating → ready to clear)
- **Order System**: Take orders, kitchen prepares food, deliver to correct table
- **Patience System**: Visual patience bars for both waiting customers and seated customers
- **Scoring**: Points for seating (+10), taking orders (+15), delivering food (+25), clearing tables (+20), penalties for angry customers
**Game Mechanics:**
- Click customers to select them, then click empty tables to seat them
- Click tables with seated customers to take their orders
- Kitchen automatically prepares orders (2-5 seconds)
- Click prepared food, then click the correct table to deliver
- Click tables when customers finish eating to clear them
- Customers get impatient if ignored too long
- 3-minute timer with final score evaluation
**Visual Design:**
- Color-coded table states with animations
- Patience bars that change color as they decrease
- Responsive layout with clear visual feedback
- Professional restaurant theme with intuitive controls
The game creates an engaging time-pressure experience where players must balance multiple tasks efficiently to maximize their score!# Restaurant Time Management Game
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Time Management</title>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f5f5f5;
margin: 0;
padding: 0;
overflow: hidden;
}
#game-container {
width: 800px;
height: 600px;
margin: 20px auto;
position: relative;
background-color: #fff;
box-shadow: 0 0 10px rgba(0,0,0,0.2);
overflow: hidden;
}
#restaurant {
width: 100%;
height: 450px;
background-color: #f9e4b7;
position: relative;
border-bottom: 2px solid #8b4513;
}
.table {
width: 80px;
height: 80px;
background-color: #8b4513;
border-radius: 50%;
position: absolute;
cursor: pointer;
}
.table::after {
content: "";
position: absolute;
width: 60px;
height: 60px;
background-color: #cd853f;
border-radius: 50%;
top: 10px;
left: 10px;
}
.table-number {
position: absolute;
width: 20px;
height: 20px;
background-color: white;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
font-size: 12px;
font-weight: bold;
top: 30px;
left: 30px;
}
.customer {
width: 30px;
height: 30px;
background-color: #3498db;
border-radius: 50%;
position: absolute;
z-index: 5;
}
.customer.waiting {
background-color: #e74c3c;
}
.customer.seated {
top: 25px;
left: 25px;
}
.customer.ordered {
background-color: #f39c12;
}
.customer.served {
background-color: #2ecc71;
}
.customer.finished {
background-color: #95a5a6;
}
#kitchen {
width: 200px;
height: 100px;
background-color: #ecf0f1;
position: absolute;
bottom: 200px;
right: 20px;
border: 2px solid #34495e;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#kitchen-label {
position: absolute;
top: 5px;
font-weight: bold;
}
#orders-queue {
display: flex;
margin-top: 15px;
}
.order {
width: 25px;
height: 25px;
background-color: #f39c12;
margin: 0 5px;
border-radius: 5px;
cursor: pointer;
}
#waiting-area {
position: absolute;
left: 20px;
top: 20px;
width: 60px;
height: 200px;
background-color: #dfe6e9;
border: 2px solid #636e72;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 5px;
}
#controls {
display: flex;
justify-content: space-between;
padding: 10px;
background-color: #34495e;
color: white;
height: 130px;
}
#stats {
display: flex;
flex-direction: column;
width: 200px;
}
.stat {
margin: 5px 0;
}
#actions {
display: flex;
flex-direction: column;
justify-content: center;
}
button {
margin: 5px 0;
padding: 8px 15px;
background-color: #3498db;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
}
button:hover {
background-color: #2980b9;
}
.player {
width: 40px;
height: 40px;
background-color: #9b59b6;
border-radius: 50%;
position: absolute;
z-index: 10;
transition: all 0.3s ease;
}
.plate {
width: 20px;
height: 20px;
background-color: #f1c40f;
border-radius: 50%;
position: absolute;
top: 10px;
left: 10px;
display: none;
}
#message {
width: 100%;
text-align: center;
padding: 10px 0;
background-color: #2c3e50;
color: white;
}
#game-over {
position: absolute;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 100;
}
#game-over h2 {
color: white;
font-size: 2.5em;
margin-bottom: 20px;
}
#final-score {
color: #f1c40f;
font-size: 2em;
margin-bottom: 30px;
}
#restart-btn {
padding: 10px 20px;
font-size: 1.2em;
background-color: #e74c3c;
}
</style>
</head>
<body>
<div id="game-container">
<div id="restaurant">
<div id="waiting-area"></div>
<div id="kitchen">
<div id="kitchen-label">Kitchen</div>
<div id="orders-queue"></div>
</div>
<div class="player" id="player">
<div class="plate" id="plate"></div>
</div>
</div>
<div id="message">Welcome to Restaurant Rush! Seat customers and serve them to earn money.</div>
<div id="controls">
<div id="stats">
<div class="stat">Time: <span id="time">2:00</span></div>
<div class="stat">Score: $<span id="score">0</span></div>
<div class="stat">Customers Served: <span id="customers-served">0</span></div>
<div class="stat">Tips: $<span id="tips">0</span></div>
</div>
<div id="actions">
<button id="start-btn">Start Game</button>
</div>
</div>
<div id="game-over">
<h2>Game Over!</h2>
<div>Your earnings: <span id="final-score">$0</span></div>
<button id="restart-btn">Play Again</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
// Game elements
const restaurant = document.getElementById('restaurant');
const player = document.getElementById('player');
const plate = document.getElementById('plate');
const kitchenElement = document.getElementById('kitchen');
const ordersQueue = document.getElementById('orders-queue');
const waitingArea = document.getElementById('waiting-area');
const message = document.getElementById('message');
const startBtn = document.getElementById('start-btn');
const gameOverScreen = document.getElementById('game-over');
const restartBtn = document.getElementById('restart-btn');
const finalScore = document.getElementById('final-score');
// Stats elements
const timeElement = document.getElementById('time');
const scoreElement = document.getElementById('score');
const customersServedElement = document.getElementById('customers-served');
const tipsElement = document.getElementById('tips');
// Game state
const tables = [];
const customers = [];
let gameInProgress = false;
let timer = 120; // 2 minutes
let score = 0;
let customersServed = 0;
let tips = 0;
let timerInterval;
let customerGenerationInterval;
let playerHasPlate = false;
let playerHasOrder = false;
let currentCustomerId = 0;
// Table positions
const tablePositions = [
{ x: 150, y: 100 },
{ x: 300, y: 100 },
{ x: 450, y: 100 },
{ x: 150, y: 300 },
{ x: 300, y: 300 },
{ x: 450, y: 300 },
];
// Initialize game
function initializeGame() {
// Create tables
tablePositions.forEach((position, index) => {
const table = document.createElement('div');
table.className = 'table';
table.style.left = `${position.x}px`;
table.style.top = `${position.y}px`;
table.dataset.id = index;
const tableNumber = document.createElement('div');
tableNumber.className = 'table-number';
tableNumber.textContent = index + 1;
table.appendChild(tableNumber);
restaurant.appendChild(table);
tables.push({
element: table,
id: index,
x: position.x,
y: position.y,
isOccupied: false,
customer: null,
state: 'empty' // empty, seated, ordered, served, finished
});
table.addEventListener('click', () => handleTableClick(index));
});
// Set initial player position
player.style.left = '400px';
player.style.top = '225px';
// Set event listeners for movement
document.addEventListener('keydown', handlePlayerMovement);
// Add click listener for kitchen
kitchenElement.addEventListener('click', handleKitchenClick);
}
// Start game
function startGame() {
gameInProgress = true;
startBtn.disabled = true;
// Reset game state
timer = 120;
score = 0;
customersServed = 0;
tips = 0;
updateStats();
// Start timer
timerInterval = setInterval(() => {
timer--;
updateStats();
if (timer <= 0) {
endGame();
}
}, 1000);
// Start customer generation
customerGenerationInterval = setInterval(generateCustomer, 5000);
message.textContent = "Game started! Seat customers and take their orders.";
}
// End game
function endGame() {
gameInProgress = false;
clearInterval(timerInterval);
clearInterval(customerGenerationInterval);
// Show game over screen
gameOverScreen.style.display = 'flex';
finalScore.textContent = `$${score}`;
}
// Reset game
function resetGame() {
// Clear all customers
customers.forEach(customer => {
if (customer.element && customer.element.parentNode) {
customer.element.parentNode.removeChild(customer.element);
}
});
customers.length = 0;
customerGenerationInterval = null;
// Reset tables
tables.forEach(table => {
table.isOccupied = false;
table.customer = null;
table.state = 'empty';
});
// Clear waiting area
while (waitingArea.firstChild) {
waitingArea.removeChild(waitingArea.firstChild);
}
// Clear orders queue
while (ordersQueue.firstChild) {
ordersQueue.removeChild(ordersQueue.firstChild);
}
// Reset player state
playerHasPlate = false;
playerHasOrder = false;
plate.style.display = 'none';
// Reset UI
startBtn.disabled = false;
gameOverScreen.style.display = 'none';
message.textContent = "Welcome to Restaurant Rush! Seat customers and serve them to earn money.";
}
// Update game stats display
function updateStats() {
const minutes = Math.floor(timer / 60);
const seconds = timer % 60;
timeElement.textContent = `${minutes}:${seconds < 10 ? '0' : ''}${seconds}`;
scoreElement.textContent = score;
customersServedElement.textContent = customersServed;
tipsElement.textContent = tips;
}
// Generate a new customer
function generateCustomer() {
if (!gameInProgress) return;
// Create a new customer element
const customerElement = document.createElement('div');
customerElement.className = 'customer waiting';
// Add to waiting area
waitingArea.appendChild(customerElement);
const customer = {
id: currentCustomerId++,
element: customerElement,
state: 'waiting',
patience: 100,
orderTime: null,
serveTime: null
};
customers.push(customer);
// Start decreasing patience
const patienceInterval = setInterval(() => {
customer.patience -= 1;
// Update customer appearance based on patience
if (customer.patience < 30) {
customerElement.style.opacity = '0.6';
}
if (customer.patience < 10) {
customerElement.style.opacity = '0.3';
}
// Customer leaves if patience runs out
if (customer.patience <= 0) {
if (customer.state === 'waiting') {
// Remove from waiting area
if (customerElement.parentNode) {
customerElement.parentNode.removeChild(customerElement);
}
message.textContent = "A customer left because they waited too long!";
// Penalize score
score -= 5;
updateStats();
// Remove customer from array
const index = customers.indexOf(customer);
if (index > -1) {
customers.splice(index, 1);
}
} else if (customer.state === 'seated' || customer.state === 'ordered') {
// Customer leaves from table
const table = tables.find(t => t.customer && t.customer.id === customer.id);
if (table) {
clearTable(table.id);
message.textContent = "A customer left angry! They waited too long for service.";
score -= 10;
updateStats();
}
}
clearInterval(patienceInterval);
}
}, 1000);
}
// Seat a customer at a table
function seatCustomer(tableId) {
const table = tables[tableId];
if (table.isOccupied) {
message.textContent = "This table is already occupied!";
return;
}
// Find first waiting customer
const waitingCustomer = customers.find(c => c.state === 'waiting');
if (!waitingCustomer) {
message.textContent = "There are no customers waiting to be seated.";
return;
}
// Update customer state
waitingCustomer.state = 'seated';
waitingCustomer.element.className = 'customer seated';
waitingCustomer.patience = 100; // Reset patience when seated
// Move customer to table
if (waitingCustomer.element.parentNode) {
waitingCustomer.element.parentNode.removeChild(waitingCustomer.element);
}
table.element.appendChild(waitingCustomer.element);
table.isOccupied = true;
table.customer = waitingCustomer;
table.state = 'seated';
message.textContent = `Customer seated at table ${tableId + 1}. Take their order!`;
score += 2; // Small bonus for seating a customer
updateStats();
}
// Take customer order
function takeOrder(tableId) {
const table = tables[tableId];
if (!table.isOccupied || table.state !== 'seated') {
message.textContent = "No seated customer to take an order from!";
return;
}
// Update customer state
table.customer.state = 'ordered';
table.customer.element.className = 'customer ordered';
table.state = 'ordered';
// Create order in kitchen
const order = document.createElement('div');
order.className = 'order';
order.dataset.tableId = tableId;
order.dataset.customerId = table.customer.id;
ordersQueue.appendChild(order);
table.customer.orderTime = new Date().getTime();
message.textContent = `Order taken from table ${tableId + 1}. The kitchen is preparing it.`;
}
// Pick up a ready order from the kitchen
function pickUpOrder(orderId) {
const order = document.querySelectorAll('.order')[orderId];
if (!order) return;
const tableId = parseInt(order.dataset.tableId);
// Update player state
playerHasPlate = true;
playerHasOrder = true;
player.dataset.targetTableId = tableId;
plate.style.display = 'block';
// Remove order from queue
ordersQueue.removeChild(order);
message.textContent = `Food picked up for table ${tableId + 1}. Deliver it!`;
}
// Deliver order to table
function deliverOrder(tableId) {
const table = tables[tableId];
if (!playerHasPlate || !playerHasOrder) {
message.textContent = "You don't have an order to deliver!";
return;
}
if (!table.isOccupied || table.state !== 'ordered') {
message.textContent = "This table doesn't have an order to deliver!";
return;
}
if (parseInt(player.dataset.targetTableId) !== tableId) {
message.textContent = "This order is for another table!";
return;
}
// Update customer state
table.customer.state = 'served';
table.customer.element.className = 'customer served';
table.state = 'served';
table.customer.serveTime = new Date().getTime();
// Calculate service time and bonus
const serviceTime = (table.customer.serveTime - table.customer.orderTime) / 1000;
let serviceBonus = 0;
if (serviceTime < 30) {
serviceBonus = 10; // Fast service bonus
message.textContent = `Order delivered to table ${tableId + 1}. Fast service! +$10 bonus`;
} else if (serviceTime < 60) {
serviceBonus = 5; // Good service bonus
message.textContent = `Order delivered to table ${tableId + 1}. Good service! +$5 bonus`;
} else {
message.textContent = `Order delivered to table ${tableId + 1}.`;
}
// Update score
score += 15 + serviceBonus;
tips += serviceBonus;
// Reset player state
playerHasPlate = false;
playerHasOrder = false;
plate.style.display = 'none';
delete player.dataset.targetTableId;
// Start eating timer
setTimeout(() => {
if (table.customer && table.state === 'served') {
table.customer.state = 'finished';
table.customer.element.className = 'customer finished';
table.state = 'finished';
message.textContent = `Customer at table ${tableId + 1} finished eating. Clear the table!`;
}
}, 10000);
updateStats();
}
// Clear table after customer finishes
function clearTable(tableId) {
const table = tables[tableId];
if (!table.isOccupied) {
message.textContent = "This table is already empty!";
return;
}
if (table.state !== 'finished') {
message.textContent = "The customer isn't finished eating yet!";
return;
}
// Remove customer element
if (table.customer.element.parentNode) {
table.customer.element.parentNode.removeChild(table.customer.element);
}
// Update customer count
customersServed++;
// Update table state
table.isOccupied = false;
table.customer = null;
table.state = 'empty';
message.textContent = `Table ${tableId + 1} cleared and ready for new customers!`;
// Update score
score += 5;
updateStats();
// Remove customer from array
const index = customers.findIndex(c => c.id === table.customer?.id);
if (index > -1) {
customers.splice(index, 1);
}
}
// Handle clicking on a table
function handleTableClick(tableId) {
if (!gameInProgress) return;
const table = tables[tableId];
// Action depends on table state
switch (table.state) {
case 'empty':
seatCustomer(tableId);
break;
case 'seated':
takeOrder(tableId);
break;
case 'ordered':
if (playerHasPlate && playerHasOrder) {
deliverOrder(tableId);
} else {
message.textContent = "The order isn't ready yet!";
}
break;
case 'finished':
clearTable(tableId);
break;
default:
break;
}
}
// Handle clicking on the kitchen
function handleKitchenClick() {
if (!gameInProgress) return;
if (playerHasPlate) {
message.textContent = "You're already carrying a dish!";
return;
}
// Find ready orders
const orders = document.querySelectorAll('.order');
if (orders.length === 0) {
message.textContent = "No orders ready in the kitchen!";
return;
}
pickUpOrder(0); // Pick up the first order in the queue
}
// Handle player movement
function handlePlayerMovement(e) {
if (!gameInProgress) return;
const step = 10;
let newX = parseInt(player.style.left) || 400;
let newY = parseInt(player.style.top) || 225;
switch (e.key) {
case 'ArrowUp':
case 'w':
newY = Math.max(0, newY - step);
break;
case 'ArrowDown':
case 's':
newY = Math.min(restaurant.clientHeight - player.clientHeight, newY + step);
break;
case 'ArrowLeft':
case 'a':
newX = Math.max(0, newX - step);
break;
case 'ArrowRight':
case 'd':
newX = Math.min(restaurant.clientWidth - player.clientWidth, newX + step);
break;
}
player.style.left = `${newX}px`;
player.style.top = `${newY}px`;
// Check collision with tables
tables.forEach(table => {
const tableRect = table.element.getBoundingClientRect();
const playerRect = player.getBoundingClientRect();
// Simple collision detection
if (
playerRect.left < tableRect.right &&
playerRect.right > tableRect.left &&
playerRect.top < tableRect.bottom &&
playerRect.bottom > tableRect.top
) {
// Player is near the table, trigger interaction based on key press
if (e.key === ' ' || e.key === 'e') {
handleTableClick(table.id);
}
}
});
// Check collision with kitchen
const kitchenRect = kitchenElement.getBoundingClientRect();
const playerRect = player.getBoundingClientRect();
if (
playerRect.left < kitchenRect.right &&
playerRect.right > kitchenRect.left &&
playerRect.top < kitchenRect.bottom &&
playerRect.bottom > kitchenRect.top
) {
// Player is near the kitchen, trigger interaction based on key press
if (e.key === ' ' || e.key === 'e') {
handleKitchenClick();
}
}
}
// Event listeners for buttons
startBtn.addEventListener('click', startGame);
restartBtn.addEventListener('click', resetGame);
// Initialize the game
initializeGame();
// Instructions to player
message.textContent = "Use arrow keys or WASD to move. Click on tables to interact or press SPACE/E when near.";
});
</script>
</body>
</html>
```
This is a complete restaurant time management game where you play as a server. Here's how to play:
1. Click "Start Game" to begin
2. Use arrow keys or WASD to move your character (purple circle)
3. Customers will appear in the waiting area (left side)
4. Click on an empty table to seat a customer
5. Click on a seated customer to take their order
6. Once an order appears in the kitchen, click the kitchen to pick it up
7. Deliver the order to the correct table
8. After customers finish eating, clear their table
9. Earn money for each successful action
10. Manage your time efficiently to maximize earnings
The game features:
- 6 tables to manage
- Customer patience meters
- Time-based service bonuses
- Kitchen order system
- 2-minute time limit
Try to earn as much money as possible before time runs out!```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Restaurant Time-Management Game</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
margin: 0;
padding: 20px;
}
#restaurant {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
margin-bottom: 20px;
}
.table {
width: 100%;
height: 100px;
background-color: #fff;
border: 2px solid #ccc;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
cursor: pointer;
}
.available {
background-color: #90ee90; /* Green for available */
}
.occupied {
background-color: #add8e6; /* Light blue for occupied */
}
.ordering {
background-color: #ffd700; /* Yellow for ordering */
}
.eating {
background-color: #ffcccb; /* Light red for eating */
}
.finished {
background-color: #d3d3d3; /* Gray for finished */
}
#status {
margin-bottom: 10px;
font-weight: bold;
}
button {
padding: 10px 15px;
margin-right: 10px;
font-size: 14px;
}
</style>
</head>
<body>
<h1>Restaurant Time-Management Game</h1>
<div id="status">Welcome! Customers will arrive soon. Click on tables to interact.</div>
<div id="restaurant">
<!-- 6 tables for simplicity -->
<div class="table available" data-id="1">Table 1 (Available)</div>
<div class="table available" data-id="2">Table 2 (Available)</div>
<div class="table available" data-id="3">Table 3 (Available)</div>
<div class="table available" data-id="4">Table 4 (Available)</div>
<div class="table available" data-id="5">Table 5 (Available)</div>
<div class="table available" data-id="6">Table 6 (Available)</div>
</div>
<div>
<button id="seatCustomer">Seat Customer</button>
<button id="takeOrder">Take Order</button>
<button id="deliverFood">Deliver Food</button>
<button id="clearTable">Clear Table</button>
</div>
<script>
// Game state variables
const tables = Array.from(document.querySelectorAll('.table')).map(table => ({
element: table,
id: table.getAttribute('data-id'),
state: 'available', // States: available, occupied, ordering, eating, finished
customer: null
}));
let selectedTable = null; // Track the currently selected table
let gameInterval = null; // For game loop
// Start the game loop
function startGame() {
gameInterval = setInterval(gameTick, 5000); // Every 5 seconds, simulate time passing
}
function gameTick() {
// Simulate incoming customers or progress
tables.forEach(table => {
if (table.state === 'occupied' && Math.random() > 0.7) {
table.state = 'ordering'; // Customer wants to order
table.element.className = 'table ordering';
table.element.innerText = `Table ${table.id} (Ordering)`;
} else if (table.state === 'ordering' && Math.random() > 0.7) {
table.state = 'eating'; // Food is prepared and delivered
table.element.className = 'table eating';
table.element.innerText = `Table ${table.id} (Eating)`;
} else if (table.state === 'eating' && Math.random() > 0.5) {
table.state = 'finished'; // Customer finished
table.element.className = 'table finished';
table.element.innerText = `Table ${table.id} (Finished)`;
}
});
updateStatus();
}
// Handle table clicks
tables.forEach(table => {
table.element.addEventListener('click', () => {
selectedTable = table;
document.getElementById('status').innerText = `Selected: Table ${table.id} (${table.state})`;
});
});
// Button event handlers
document.getElementById('seatCustomer').addEventListener('click', () => {
if (selectedTable && selectedTable.state === 'available') {
selectedTable.state = 'occupied';
selectedTable.element.className = 'table occupied';
selectedTable.element.innerText = `Table ${selectedTable.id} (Occupied)`;
selectedTable.customer = { name: 'Customer ' + Math.floor(Math.random() * 100) }; // Simple customer
updateStatus();
} else {
alert('No available table selected!');
}
});
document.getElementById('takeOrder').addEventListener('click', () => {
if (selectedTable && selectedTable.state === 'occupied') {
selectedTable.state = 'ordering';
selectedTable.element.className = 'table ordering';
selectedTable.element.innerText = `Table ${selectedTable.id} (Ordering)`;
updateStatus();
} else {
alert('Select an occupied table first!');
}
});
document.getElementById('deliverFood').addEventListener('click', () => {
if (selectedTable && selectedTable.state === 'ordering') {
selectedTable.state = 'eating';
selectedTable.element.className = 'table eating';
selectedTable.element.innerText = `Table ${selectedTable.id} (Eating)`;
updateStatus();
} else {
alert('Select a table that is ordering first!');
}
});
document.getElementById('clearTable').addEventListener('click', () => {
if (selectedTable && selectedTable.state === 'finished') {
selectedTable.state = 'available';
selectedTable.element.className = 'table available';
selectedTable.element.innerText = `Table ${selectedTable.id} (Available)`;
selectedTable.customer = null;
updateStatus();
} else {
alert('Select a finished table first!');
}
});
function updateStatus() {
document.getElementById('status').innerText = `Game Status: ${tables.filter(t => t.state === 'available').length} tables available. Select a table to interact.`;
}
// Initialize the game
startGame();
</script>
</body>
</html>
```