HP-65 Calculator Simulator (1974)
<<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HP-65 Calculator Simulator (1974)</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
margin: 0;
}
.calculator {
width: 340px;
background-color: #333;
border-radius: 10px;
padding: 20px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
}
.display {
background-color: #a5a58d;
color: #222;
padding: 15px 10px;
text-align: right;
font-family: 'Courier New', monospace;
font-size: 24px;
margin-bottom: 15px;
border-radius: 5px;
position: relative;
overflow: hidden;
}
.display-memory {
position: absolute;
top: 5px;
left: 10px;
font-size: 12px;
color: #555;
}
.display-register {
position: absolute;
top: 5px;
right: 10px;
font-size: 12px;
color: #555;
}
.keys {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
}
.key {
background-color: #444;
color: white;
border: none;
border-radius: 5px;
padding: 12px 0;
font-size: 16px;
cursor: pointer;
transition: background-color 0.2s;
position: relative;
}
.key:hover {
background-color: #555;
}
.key:active {
background-color: #666;
}
.key.function {
background-color: #555;
}
.key.enter {
background-color: #8b0000;
grid-column: span 2;
}
.key.enter:hover {
background-color: #a00000;
}
.key.secondary {
position: absolute;
top: 3px;
left: 3px;
font-size: 10px;
color: #ccc;
}
.card-reader {
background-color: #222;
height: 30px;
margin-top: 15px;
border-radius: 3px;
position: relative;
overflow: hidden;
}
.card-slot {
position: absolute;
width: 80%;
height: 5px;
background-color: #444;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.brand {
text-align: center;
color: #ccc;
margin-top: 10px;
font-size: 14px;
}
</style>
</head>
<body>
<div class="calculator">
<div class="brand">HEWLETT-PACKARD</div>
<div class="display">
<div class="display-memory" id="memory-indicator"></div>
<div class="display-register" id="register-indicator"></div>
<div id="display-value">0.</div>
</div>
<div class="keys">
<!-- Row 1 -->
<button class="key function" onclick="handleFunction('f1')">
<span class="secondary">A</span>
f<span>I</span>
</button>
<button class="key function" onclick="handleFunction('f2')">
<span class="secondary">B</span>
f<span>II</span>
</button>
<button class="key function" onclick="handleFunction('f3')">
<span class="secondary">C</span>
f<span>III</span>
</button>
<button class="key function" onclick="handleFunction('f4')">
<span class="secondary">D</span>
f<span>IV</span>
</button>
<button class="key function" onclick="handleFunction('f5')">
<span class="secondary">E</span>
f<span>V</span>
</button>
<!-- Row 2 -->
<button class="key" onclick="handleKey('7')">7</button>
<button class="key" onclick="handleKey('8')">8</button>
<button class="key" onclick="handleKey('9')">9</button>
<button class="key" onclick="handleOperation('divide')">÷</button>
<button class="key" onclick="handleOperation('multiply')">×</button>
<!-- Row 3 -->
<button class="key" onclick="handleKey('4')">4</button>
<button class="key" onclick="handleKey('5')">5</button>
<button class="key" onclick="handleKey('6')">6</button>
<button class="key" onclick="handleOperation('subtract')">-</button>
<button class="key" onclick="handleOperation('chs')">CHS</button>
<!-- Row 4 -->
<button class="key" onclick="handleKey('1')">1</button>
<button class="key" onclick="handleKey('2')">2</button>
<button class="key" onclick="handleKey('3')">3</button>
<button class="key" onclick="handleOperation('add')">+</button>
<button class="key" onclick="handleOperation('eex')">EEX</button>
<!-- Row 5 -->
<button class="key" onclick="handleKey('0')">0</button>
<button class="key" onclick="handleKey('.')">.</button>
<button class="key" onclick="handleOperation('clx')">CLX</button>
<button class="key enter" onclick="handleOperation('enter')">ENTER</button>
<!-- Row 6 -->
<button class="key" onclick="handleOperation('rcl')">
<span class="secondary">GTO</span>
RCL
</button>
<button class="key" onclick="handleOperation('sto')">
<span class="secondary">LBL</span>
STO
</button>
<button class="key" onclick="handleOperation('r↓')">R↓</button>
<button class="key" onclick="handleOperation('x⇄y')">x⇄y</button>
<button class="key" onclick="handleOperation('clr')">CLR</button>
</div>
<div class="card-reader">
<div class="card-slot"></div>
</div>
<div class="brand">HP-65</div>
</div>
<script>
// Calculator state
const state = {
display: '0.',
stack: [0, 0, 0, 0],
memory: {},
lastOperation: null,
enteringNumber: false,
decimalEntered: false,
scientificNotation: false,
exponent: 0,
fShift: false
};
// DOM elements
const displayElement = document.getElementById('display-value');
const memoryIndicator = document.getElementById('memory-indicator');
const registerIndicator = document.getElementById('register-indicator');
// Update the display
function updateDisplay() {
displayElement.textContent = state.display;
// Update memory indicator if any registers are used
const usedRegisters = Object.keys(state.memory).length;
memoryIndicator.textContent = usedRegisters > 0 ? 'MEM' : '';
// Update register stack indicator
registerIndicator.textContent = `X:${state.stack[0].toFixed(2)} Y:${state.stack[1].toFixed(2)}`;
}
// Handle number input
function handleKey(key) {
if (!state.enteringNumber) {
state.display = key === '.' ? '0.' : key;
state.enteringNumber = true;
state.decimalEntered = key === '.';
state.scientificNotation = false;
} else {
if (key === '.') {
if (!state.decimalEntered) {
state.display += '.';
state.decimalEntered = true;
}
} else {
if (state.display === '0' && key === '0') return;
if (state.display === '0') state.display = key;
else state.display += key;
}
}
updateDisplay();
}
// Handle operations
function handleOperation(op) {
const x = parseFloat(state.display);
switch (op) {
case 'enter':
state.stack.unshift(x);
state.stack.pop();
state.enteringNumber = false;
state.decimalEntered = false;
state.scientificNotation = false;
break;
case 'add':
if (state.lastOperation === 'enter') {
const y = state.stack[1];
state.stack[0] = y + x;
} else {
const y = state.stack[0];
state.stack[0] = y + x;
}
state.display = state.stack[0].toString();
state.enteringNumber = false;
break;
case 'subtract':
if (state.lastOperation === 'enter') {
const y = state.stack[1];
state.stack[0] = y - x;
} else {
const y = state.stack[0];
state.stack[0] = y - x;
}
state.display = state.stack[0].toString();
state.enteringNumber = false;
break;
case 'multiply':
if (state.lastOperation === 'enter') {
const y = state.stack[1];
state.stack[0] = y * x;
} else {
const y = state.stack[0];
state.stack[0] = y * x;
}
state.display = state.stack[0].toString();
state.enteringNumber = false;
break;
case 'divide':
if (state.lastOperation === 'enter') {
const y = state.stack[1];
state.stack[0] = y / x;
} else {
const y = state.stack[0];
state.stack[0] = y / x;
}
state.display = state.stack[0].toString();
state.enteringNumber = false;
break;
case 'chs':
state.display = (-parseFloat(state.display)).toString();
break;
case 'clx':
state.display = '0.';
state.enteringNumber = false;
state.decimalEntered = false;
break;
case 'clr':
state.display = '0.';
state.stack = [0, 0, 0, 0];
state.memory = {};
state.enteringNumber = false;
state.decimalEntered = false;
break;
case 'eex':
state.scientificNotation = true;
state.exponent = 0;
state.display = state.display + 'E';
break;
case 'r↓':
state.stack.push(state.stack.shift());
state.display = state.stack[0].toString();
break;
case 'x⇄y':
const temp = state.stack[0];
state.stack[0] = state.stack[1];
state.stack[1] = temp;
state.display = state.stack[0].toString();
break;
case 'sto':
if (state.fShift) {
// LBL operation (label for programming)
// Not implemented in this simple version
} else {
// STO operation
const register = prompt('Enter register number (0-9):');
if (register !== null && /^[0-9]$/.test(register)) {
state.memory[register] = parseFloat(state.display);
}
}
state.fShift = false;
break;
case 'rcl':
if (state.fShift) {
// GTO operation (go to label)
// Not implemented in this simple version
} else {
// RCL operation
const register = prompt('Enter register number (0-9):');
if (register !== null && /^[0-9]$/.test(register) && state.memory[register] !== undefined) {
state.display = state.memory[register].toString();
state.enteringNumber = false;
}
}
state.fShift = false;
break;
}
state.lastOperation = op;
updateDisplay();
}
// Handle function keys
function handleFunction(fn) {
state.fShift = true;
// In a full implementation, these would handle programming functions
alert(`Function ${fn} pressed. Programming functions not implemented in this simulator.`);
}
// Initialize display
updateDisplay();
// Keyboard support
document.addEventListener('keydown', (e) => {
const key = e.key;
if (/[0-9]/.test(key)) {
handleKey(key);
} else if (key === '.') {
handleKey('.');
} else if (key === '+' || key === '-' || key === '*' || key === '/') {
const opMap = {
'+': 'add',
'-': 'subtract',
'*': 'multiply',
'/': 'divide'
};
handleOperation(opMap[key]);
} else if (key === 'Enter') {
handleOperation('enter');
} else if (key === 'Escape') {
handleOperation('clx');
}
});
</script>
</body>
</html>
Comments
Post a Comment