📄 Calc-rpn2-code.txt
<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>RPN Scientific Calculator</title>
<style>
* { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
body { background:#030712; display:flex; align-items:center; justify-content:center; min-height:100vh; font-family:'Courier New',monospace; padding:8px; }
.calc { width:100%; max-width:380px; background:#111827; border-radius:16px; padding:12px; position:relative; }
.top { display:flex; justify-content:space-between; align-items:center; margin-bottom:8px; padding:0 4px; }
.title { color:#9ca3af; font-size:11px; letter-spacing:2px; }
.angles { display:flex; gap:4px; }
.angles button { padding:2px 8px; border-radius:4px; font-size:11px; font-weight:bold; border:none; cursor:pointer; transition:.2s; }
.angles button.off { background:#374151; color:#9ca3af; }
.angles button.on { background:#0d9488; color:#fff; }
.display { background:#030712; border-radius:12px; padding:12px; margin-bottom:8px; border:1px solid #1f2937; }
.srow { display:flex; justify-content:space-between; align-items:baseline; padding:2px 0; }
.srow.x .lbl { color:#f87171; font-size:11px; }
.srow.x .val { color:#facc15; font-size:18px; font-weight:bold; }
.srow.n .lbl { color:#4b5563; font-size:11px; }
.srow.n .val { color:#9ca3af; font-size:13px; }
.val { text-align:right; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; margin-left:16px; flex:1; }
.mems { display:flex; gap:8px; flex-wrap:wrap; margin-top:4px; padding-top:4px; border-top:1px solid #1f2937; }
.mems span { color:#0e4f4f; font-size:11px; }
.pending { color:#22d3ee; font-size:12px; text-align:center; margin-top:4px; animation:pulse 1s infinite; }
@keyframes pulse { 0%,100%{opacity:1} 50%{opacity:.4} }
.grid { display:grid; grid-template-columns:repeat(5,1fr); gap:4px; margin-bottom:4px; }
.grid button { border:none; border-radius:8px; font-family:'Courier New',monospace; font-size:11px; font-weight:600; padding:12px 0; cursor:pointer; transition:.15s; user-select:none; }
.grid button:active { transform:scale(.93); }
.sc { background:#374151; color:#e5e7eb; } .sc:hover { background:#4b5563; }
.nm { background:#4b5563; color:#fff; font-size:14px; } .nm:hover { background:#6b7280; }
.oa { background:#92400e; color:#fef3c7; } .oa:hover { background:#b45309; }
.rd { background:#7f1d1d; color:#fecaca; } .rd:hover { background:#991b1b; }
.gn { background:#166534; color:#bbf7d0; } .gn:hover { background:#15803d; }
.tl { background:#0f766e; color:#fff; } .tl:hover { background:#0d9488; }
.cy { background:#374151; color:#67e8f9; } .cy:hover { background:#4b5563; }
.overlay { position:absolute; inset:0; background:rgba(0,0,0,.65); border-radius:16px; display:flex; align-items:center; justify-content:center; z-index:10; }
.mpanel { background:#1f2937; border-radius:12px; padding:16px; border:1px solid #374151; }
.mpanel p { color:#22d3ee; font-size:13px; font-weight:bold; text-align:center; margin-bottom:10px; }
.mpanel .mg { display:grid; grid-template-columns:repeat(5,1fr); gap:8px; }
.mpanel .mg button { width:44px; height:44px; border-radius:8px; font-family:'Courier New',monospace; font-weight:bold; font-size:14px; border:none; cursor:pointer; transition:.15s; }
.mpanel .mg button:active { transform:scale(.92); }
.mpanel .mg button.empty { background:#374151; color:#fff; }
.mpanel .mg button.empty:hover { background:#4b5563; }
.mpanel .mg button.used { background:#115e59; color:#ccfbf1; }
.mpanel .mg button.used:hover { background:#0f766e; }
.mpanel .hint { color:#6b7280; font-size:11px; text-align:center; margin-top:10px; }
.hidden { display:none; }
</style>
</head>
<body>
<div class="calc" id="calc">
<div class="top">
<span class="title">RPN SCIENTIFIC</span>
<div class="angles" id="angles"></div>
</div>
<div class="display" id="display"></div>
<div class="grid" id="sci"></div>
<div class="grid" id="extra"></div>
<div class="grid" id="main"></div>
<div class="overlay hidden" id="overlay" onclick="cancelPending()">
<div class="mpanel" onclick="event.stopPropagation()">
<p id="mpTitle"></p>
<div class="mg" id="mpGrid"></div>
<div class="hint">tocca fuori per annullare</div>
</div>
</div>
</div>
<script>
var S = { stack:[0,0,0,0], input:'', active:false, lift:true, angle:'DEG', mem:Array(10).fill(0), pending:null };
function fmt(n) {
if(n==null||isNaN(n)) return 'Error';
if(!isFinite(n)) return n>0?'∞':'-∞';
if(n===0) return '0';
var a=Math.abs(n);
if(Number.isInteger(n)&&a<1e12) return n.toString();
if(a>=1e12||a<1e-4) return n.toExponential(11).replace(/\.?0+(e)/,'$1');
var s=n.toPrecision(12);
if(s.indexOf('.')>=0) s=s.replace(/0+$/,'').replace(/\.$/,'');
return s;
}
function toR(v){ return S.angle==='DEG'?v*Math.PI/180:S.angle==='GRA'?v*Math.PI/200:v; }
function fromR(v){ return S.angle==='DEG'?v*180/Math.PI:S.angle==='GRA'?v*200/Math.PI:v; }
function X(){ return S.active?parseFloat(S.input||'0'):S.stack[0]; }
function act(a) {
var x=S.stack[0],y=S.stack[1],z=S.stack[2],t=S.stack[3];
if(S.pending) {
if(a.type==='DIGIT') {
var r=parseInt(a.val);
if(r>=0&&r<=9) {
if(S.pending==='STO') {
S.mem[r]=X();
if(S.active){S.stack[0]=X();S.input='';S.active=false;S.lift=true;}
} else if(S.pending==='RCL') {
var v=S.mem[r];
if(S.active) S.stack=[v,X(),S.stack[1],S.stack[2]];
else if(S.lift) S.stack=[v,x,y,z];
else S.stack=[v,y,z,t];
S.input='';S.active=false;S.lift=true;
}
}
S.pending=null; render(); return;
}
if(a.type==='CANCEL'||a.type==='ESC'){S.pending=null;render();return;}
S.pending=null;
}
switch(a.type) {
case 'DIGIT':
if(!S.active){
var sk=S.lift?[x,x,y,z]:[x,y,z,t];
S.stack=sk;S.input=a.val;S.active=true;S.lift=false;
} else S.input+=a.val;
break;
case 'DOT':
if(!S.active){
var sk2=S.lift?[x,x,y,z]:[x,y,z,t];
S.stack=sk2;S.input='0.';S.active=true;S.lift=false;
} else if(S.input.indexOf('.')<0) S.input+='.';
break;
case 'ENTER':
if(S.active){var v2=X();S.stack=[v2,v2,S.stack[1],S.stack[2]];S.input='';S.active=false;S.lift=false;}
else{S.stack=[x,x,y,z];S.lift=false;}
break;
case 'BINOP': {
var rx=S.active?parseFloat(S.input||'0'):x;
var ry=S.active?S.stack[1]:y;
var s2=S.active?S.stack[2]:z;
var s3=S.active?S.stack[3]:t;
var res;
switch(a.op){
case'+':res=ry+rx;break;case'-':res=ry-rx;break;
case'*':res=ry*rx;break;case'/':res=rx===0?NaN:ry/rx;break;
case'pow':res=Math.pow(ry,rx);break;case'mod':res=rx===0?NaN:ry%rx;break;
default:res=NaN;
}
S.stack=[res,s2,s3,s3];S.input='';S.active=false;S.lift=true;
break;
}
case 'UNARY': {
var v3=X();
if(S.active){S.stack[0]=v3;S.stack=[v3,S.stack[1],S.stack[2],S.stack[3]];}
var rr;
switch(a.op){
case'sin':rr=Math.sin(toR(v3));break;case'cos':rr=Math.cos(toR(v3));break;
case'tan':rr=Math.tan(toR(v3));break;case'asin':rr=fromR(Math.asin(v3));break;
case'acos':rr=fromR(Math.acos(v3));break;case'atan':rr=fromR(Math.atan(v3));break;
case'sqrt':rr=v3<0?NaN:Math.sqrt(v3);break;case'sq':rr=v3*v3;break;
case'inv':rr=v3===0?NaN:1/v3;break;case'ln':rr=v3<=0?NaN:Math.log(v3);break;
case'log':rr=v3<=0?NaN:Math.log10(v3);break;case'exp':rr=Math.exp(v3);break;
case'pow10':rr=Math.pow(10,v3);break;
case'fact':if(v3<0||!Number.isInteger(v3)||v3>170)rr=NaN;else{rr=1;for(var i=2;i<=v3;i++)rr*=i;}break;
case'rnd':rr=parseFloat(v3.toPrecision(12));break;
default:rr=NaN;
}
if(['sin','cos','tan'].indexOf(a.op)>=0&&typeof rr==='number'&&Math.abs(rr)<5e-15)rr=0;
S.stack[0]=rr;S.input='';S.active=false;S.lift=true;
break;
}
case 'CHS':
if(S.active){
if(S.input.indexOf('e')>=0){var pp=S.input.split('e');S.input=pp[0]+'e'+(pp[1]&&pp[1][0]==='-'?pp[1].slice(1):'-'+(pp[1]||''));}
else if(S.input[0]==='-')S.input=S.input.slice(1);
else if(S.input&&S.input!=='0')S.input='-'+S.input;
} else {S.stack[0]=-x;S.lift=true;}
break;
case 'CONST': {
var vc=a.val==='pi'?Math.PI:Math.E;
if(S.active)S.stack=[vc,X(),S.stack[1],S.stack[2]];
else if(S.lift)S.stack=[vc,x,y,z];
else S.stack=[vc,y,z,t];
S.input='';S.active=false;S.lift=true;
break;
}
case 'CLX':
if(S.active){S.input='';S.active=false;S.lift=false;}
else{S.stack[0]=0;S.lift=false;}
break;
case 'ESC':
if(S.active){S.input='';S.active=false;S.lift=false;}
else{S.stack[0]=0;S.lift=false;}
break;
case 'DROP':
if(S.active)S.stack=[S.stack[1],S.stack[2],S.stack[3],0];
else S.stack=[y,z,t,0];
S.input='';S.active=false;S.lift=true;
break;
case 'SWAP':
if(S.active){var vs=X();S.stack=[S.stack[1],vs,S.stack[2],S.stack[3]];}
else S.stack=[y,x,z,t];
S.input='';S.active=false;S.lift=true;
break;
case 'ROLL':
if(S.active){var vr=X();S.stack=[S.stack[1],S.stack[2],S.stack[3],vr];}
else S.stack=[y,z,t,x];
S.input='';S.active=false;S.lift=true;
break;
case 'BS':
if(S.active&&S.input.length>0){
var ni=S.input.slice(0,-1);
if(!ni||ni==='-'){S.input='';S.active=false;S.lift=false;}
else S.input=ni;
} else {S.stack[0]=0;S.lift=false;}
break;
case 'EEX':
if(!S.active){
var sk3=S.lift?[x,x,y,z]:[x,y,z,t];
S.stack=sk3;S.input='1e';S.active=true;S.lift=false;
} else if(S.input.indexOf('e')<0)S.input=(S.input||'1')+'e';
break;
case 'ANGLE': S.angle=a.val; break;
case 'STO': S.pending='STO'; break;
case 'RCL': S.pending='RCL'; break;
case 'RAND': {
var vn=Math.random();
if(S.active)S.stack=[vn,X(),S.stack[1],S.stack[2]];
else if(S.lift)S.stack=[vn,x,y,z];
else S.stack=[vn,y,z,t];
S.input='';S.active=false;S.lift=true;
break;
}
}
render();
}
function cancelPending(){ S.pending=null; render(); }
function render() {
var dX = S.active ? (S.input||'0')+'│' : fmt(S.stack[0]);
var rows = [
{n:'4',v:fmt(S.stack[3]),x:false},{n:'3',v:fmt(S.stack[2]),x:false},
{n:'2',v:fmt(S.stack[1]),x:false},{n:'1',v:dX,x:true}
];
var h='';
rows.forEach(function(r){
h+='<div class="srow '+(r.x?'x':'n')+'"><span class="lbl">'+r.n+' :</span><span class="val">'+r.v+'</span></div>';
});
var used=[];
for(var i=0;i<10;i++) if(S.mem[i]!==0) used.push(i);
if(used.length>0){
h+='<div class="mems">';
used.forEach(function(i){h+='<span>M'+i+'='+fmt(S.mem[i]).slice(0,10)+'</span>';});
h+='</div>';
}
if(S.pending) h+='<div class="pending">'+S.pending+' ▸ registro 0–9</div>';
document.getElementById('display').innerHTML=h;
// angles
var ab='';
['DEG','RAD','GRA'].forEach(function(m){
ab+='<button class="'+(S.angle===m?'on':'off')+'" onclick="act({type:\'ANGLE\',val:\''+m+'\'})">'+m+'</button>';
});
document.getElementById('angles').innerHTML=ab;
// overlay
var ov=document.getElementById('overlay');
if(S.pending){
ov.classList.remove('hidden');
document.getElementById('mpTitle').textContent=S.pending+' ▸ Registro';
var mg='';
for(var j=0;j<10;j++){
mg+='<button class="'+(S.mem[j]!==0?'used':'empty')+'" onclick="act({type:\'DIGIT\',val:\''+j+'\'})">'+j+'</button>';
}
document.getElementById('mpGrid').innerHTML=mg;
} else ov.classList.add('hidden');
}
function makeBtn(parent,label,action,cls){
var b=document.createElement('button');
b.textContent=label;b.className=cls;
b.onclick=function(){act(action);};
document.getElementById(parent).appendChild(b);
}
// scientific row
var sci=[
['SIN',{type:'UNARY',op:'sin'},'sc'],['COS',{type:'UNARY',op:'cos'},'sc'],['TAN',{type:'UNARY',op:'tan'},'sc'],['√x',{type:'UNARY',op:'sqrt'},'sc'],['x²',{type:'UNARY',op:'sq'},'sc'],
['SIN⁻¹',{type:'UNARY',op:'asin'},'sc'],['COS⁻¹',{type:'UNARY',op:'acos'},'sc'],['TAN⁻¹',{type:'UNARY',op:'atan'},'sc'],['yˣ',{type:'BINOP',op:'pow'},'sc'],['1/x',{type:'UNARY',op:'inv'},'sc'],
['LN',{type:'UNARY',op:'ln'},'sc'],['LOG',{type:'UNARY',op:'log'},'sc'],['eˣ',{type:'UNARY',op:'exp'},'sc'],['10ˣ',{type:'UNARY',op:'pow10'},'sc'],['N!',{type:'UNARY',op:'fact'},'sc'],
['π',{type:'CONST',val:'pi'},'sc'],['e',{type:'CONST',val:'e'},'sc'],['RND',{type:'UNARY',op:'rnd'},'sc'],['EEX',{type:'EEX'},'sc'],['+/−',{type:'CHS'},'sc']
];
sci.forEach(function(b){makeBtn('sci',b[0],b[1],b[2]);});
// extra row (cyan)
var extra=[
['RAN#',{type:'RAND'},'cy'],['STO',{type:'STO'},'cy'],['RCL',{type:'RCL'},'cy'],['MOD',{type:'BINOP',op:'mod'},'cy'],['R↓',{type:'ROLL'},'cy']
];
extra.forEach(function(b){makeBtn('extra',b[0],b[1],b[2]);});
// main
var main=[
['7',{type:'DIGIT',val:'7'},'nm'],['8',{type:'DIGIT',val:'8'},'nm'],['9',{type:'DIGIT',val:'9'},'nm'],['÷',{type:'BINOP',op:'/'},'oa'],['⌫',{type:'BS'},'rd'],
['4',{type:'DIGIT',val:'4'},'nm'],['5',{type:'DIGIT',val:'5'},'nm'],['6',{type:'DIGIT',val:'6'},'nm'],['×',{type:'BINOP',op:'*'},'oa'],['CLx',{type:'CLX'},'rd'],
['1',{type:'DIGIT',val:'1'},'nm'],['2',{type:'DIGIT',val:'2'},'nm'],['3',{type:'DIGIT',val:'3'},'nm'],['−',{type:'BINOP',op:'-'},'oa'],['SWAP',{type:'SWAP'},'gn'],
['0',{type:'DIGIT',val:'0'},'nm'],['.',{type:'DOT'},'nm'],['ENTER',{type:'ENTER'},'tl'],['+',{type:'BINOP',op:'+'},'oa'],['DROP',{type:'DROP'},'gn']
];
main.forEach(function(b){makeBtn('main',b[0],b[1],b[2]);});
// keyboard
document.addEventListener('keydown',function(e){
var k=e.key;
if(k>='0'&&k<='9') act({type:'DIGIT',val:k});
else if(k==='.') act({type:'DOT'});
else if(k==='Enter'){e.preventDefault();act({type:'ENTER'});}
else if(k==='+') act({type:'BINOP',op:'+'});
else if(k==='-') act({type:'BINOP',op:'-'});
else if(k==='*') act({type:'BINOP',op:'*'});
else if(k==='/'){e.preventDefault();act({type:'BINOP',op:'/'});}
else if(k==='Backspace') act({type:'BS'});
else if(k==='Escape') act({type:'ESC'});
});
render();
</script>
</body>
</html>
® Ricerca indipendente di monseppe2