ฝึกคำนวณIP
IP Subnetting Lab
`}
function showEl(id){document.getElementById(id).classList.remove('hidden')}
function hideEl(id){document.getElementById(id).classList.add('hidden')}
/* ════════════════════════════════════════
DIFF CARDS
════════════════════════════════════════ */
document.querySelectorAll('.diff-card').forEach(b=>{
b.addEventListener('click',()=>{
document.querySelectorAll('.diff-card').forEach(x=>x.classList.remove('sel'));
b.classList.add('sel'); difficulty=b.dataset.d;
});
});
/* ════════════════════════════════════════
GENERATE QUESTIONS
════════════════════════════════════════ */
function generateQuestions(){
const pools=[
{net:'192.168.1.0',cidr:24,subs:4,name:'Office Network'},
{net:'192.168.10.0',cidr:24,subs:8,name:'Department'},
{net:'10.0.0.0',cidr:24,subs:4,name:'Branch'},
{net:'172.16.0.0',cidr:24,subs:2,name:'Floor'},
{net:'192.168.100.0',cidr:24,subs:4,name:'Building'},
{net:'192.168.50.0',cidr:24,subs:8,name:'Campus Zone'},
{net:'10.10.0.0',cidr:22,subs:4,name:'Campus'},
{net:'172.20.0.0',cidr:22,subs:8,name:'Site HQ'},
{net:'192.168.200.0',cidr:24,subs:4,name:'Data Center'},
{net:'10.0.0.0',cidr:16,subs:4,name:'Region'},
{net:'172.30.0.0',cidr:22,subs:16,name:'Enterprise'},
{net:'10.20.0.0',cidr:24,subs:4,name:'Factory'},
];
const pool=difficulty==='easy'?pools.slice(0,6):difficulty==='med'?pools.slice(3,9):pools.slice(6);
questions=[];
const used=new Set();
while(questions.length<5){
let idx=ri(0,pool.length-1);
if(used.has(idx)&&pool.length>5)continue;
used.add(idx);
const p=pool[idx];
const bitsNeeded=Math.ceil(Math.log2(p.subs));
const newCidr=p.cidr+bitsNeeded;
const subSize=Math.pow(2,32-newCidr);
const baseNum=ip2n(p.net);
const subnets=[];
for(let s=0;ss.classList.remove('active'));document.getElementById(id).classList.add('active')}
/* ════════════════════════════════════════
LOAD QUESTION
════════════════════════════════════════ */
function loadQuestion(){
const q=questions[currentQ];
currentStep=1;currentSubnetIdx=0;subnetAnswers=[];machineData={};hintUsed=false;questionDone=false;
document.getElementById('hud-q').textContent=`${currentQ+1}/5`;
document.getElementById('prog-fill').style.width=((currentQ+1)/5*100)+'%';
document.getElementById('prog-pct').textContent=((currentQ+1)/5*100).toFixed(0)+'%';
document.getElementById('q-title').textContent=q.title;
document.getElementById('q-network').textContent=q.network+'/'+q.cidr;
document.getElementById('q-subs').textContent=q.subsNeeded+' subnets';
document.getElementById('q-origmask').textContent=q.mask;
document.getElementById('q-tags').innerHTML=`${q.bitsNeeded} bits ยืม ${q.subnets[0].hosts} hosts/subnet`;
renderNetVis(q);
renderAssignMachines(q);
buildStepTrail();
setupStep1(q);
['step2','step3','step4','step5','step6','step6-done'].forEach(id=>document.getElementById(id).classList.add('hidden'));
showEl('step1');
['s2-fb','s3-fb','s4-fb','s5-fb','s6-fb'].forEach(id=>document.getElementById(id).innerHTML='');
document.getElementById('assign-fb').innerHTML='';
hideEl('btn-next');hideEl('btn-finish');
switchTab('calc');
buildStepTrail();
}
/* ════════════════════════════════════════
NET VIS
════════════════════════════════════════ */
function renderNetVis(q){
const vis=document.getElementById('net-vis');vis.innerHTML='';
q.subnets.forEach((s,i)=>{
const c=SUB_COLORS[i%SUB_COLORS.length];
const d=document.createElement('div');d.className='sub-blk pending';d.id='sblk-'+i;
d.style.cssText=`background:${c.bg};border-color:${c.border};color:${c.text}`;
d.textContent=`แผนก${i+1}: ${s.network}/${s.cidr}`;d.title=`${s.first}${s.last}`;
vis.appendChild(d);
});
}
/* ════════════════════════════════════════
STEP TRAIL
════════════════════════════════════════ */
const stepLabels=['ตาราง Bit','Binary Mask','หา n','CIDR ใหม่','Hosts','IP Range'];
function buildStepTrail(){
const trail=document.getElementById('step-trail');trail.innerHTML='';
stepLabels.forEach((lbl,i)=>{
const sn=i+1;
const node=document.createElement('div');node.className='step-node';
const circ=document.createElement('div');circ.className='step-circle';circ.id='sc-'+sn;circ.textContent=sn;
if(sn{
const sn=i+1;
const circ=document.getElementById('sc-'+sn);const line=document.getElementById('sl-'+sn);
if(!circ)return;
circ.className='step-circle';
if(sn{
const th=document.createElement('th');th.textContent=v;head.appendChild(th);
const td=document.createElement('td');td.innerHTML=``;body.appendChild(td);
});
// Show which bits are 1 for the last octet of the ORIGINAL mask
const lastOctetDec=parseInt(q.mask.split('.')[3]);
const bin=toBin(lastOctetDec);
Array.from(body.children).forEach((td,i)=>{td.querySelector('.bit-cell').textContent=bin[i];td.querySelector('.bit-cell').style.color=bin[i]==='1'?'var(--cyan)':'var(--text3)';});
}
function goStep(n){
currentStep=n;
for(let i=1;i<=6;i++) document.getElementById('step'+i)?.classList.add('hidden');
hideEl('step6-done');
showEl('step'+n);
updateStepTrail();
document.getElementById('step'+n)?.scrollIntoView({behavior:'smooth',block:'nearest'});
}
/* ════════════════════════════════════════
STEP 2 Binary of original mask
════════════════════════════════════════ */
function setupStep2(){
const q=questions[currentQ];
document.getElementById('s2-cidr-show').textContent='/'+q.cidr;
document.getElementById('s2-mask-show').textContent=q.mask;
const lastOctetDec=parseInt(q.mask.split('.')[3]);
const prefix=q.mask.split('.').slice(0,3).map(x=>toBin(parseInt(x))).join('.')+'.';
document.getElementById('s2-prefix').textContent=prefix;
document.getElementById('s2-last-octet').value='';
document.getElementById('s2-fb').innerHTML='';
}
function checkStep2(){
const q=questions[currentQ];
const lastOctetDec=parseInt(q.mask.split('.')[3]);
const correct=toBin(lastOctetDec);
const got=document.getElementById('s2-last-octet').value.trim();
if(got===correct){
setFb('s2-fb','ok',`✔ ถูกต้อง! ${correct} = ${lastOctetDec} ทศนิยม`);
score+=10;document.getElementById('hud-score').textContent=score;
setTimeout(()=>goStep(3),700);
} else {
setFb('s2-fb','err',`✘ ไม่ถูกต้อง กรอก: "${got}" ถูกต้องคือ "${correct}"\n💡 ${lastOctetDec}₁₀ = ${correct}₂`);
}
}
/* ════════════════════════════════════════
STEP 3 Bits to borrow (n)
════════════════════════════════════════ */
function setupStep3(){
const q=questions[currentQ];
document.getElementById('s3-subs-needed').textContent=q.subsNeeded;
document.getElementById('s3-n-answer').textContent=q.bitsNeeded;
const opts=document.getElementById('s3-options');opts.innerHTML='';
// generate wrong options
const correct=q.bitsNeeded;
const choices=new Set([correct]);
while(choices.size<4){const w=ri(Math.max(1,correct-2),correct+2);choices.add(w);}
const arr=Array.from(choices).sort((a,b)=>a-b);
arr.forEach(v=>{
const opt=document.createElement('label');opt.className='radio-opt';
opt.innerHTML=` n = ${v} (2${v} = ${Math.pow(2,v)})`;
opt.addEventListener('click',()=>{document.querySelectorAll('.radio-opt').forEach(x=>x.classList.remove('selected'));opt.classList.add('selected');checkStep3(v);});
opts.appendChild(opt);
});
document.getElementById('s3-fb').innerHTML='';
hideEl('s3-next');
}
function checkStep3(val){
const q=questions[currentQ];
if(parseInt(val)===q.bitsNeeded){
setFb('s3-fb','ok',`✔ ถูกต้อง! 2${q.bitsNeeded} = ${Math.pow(2,q.bitsNeeded)} ≥ ${q.subsNeeded} subnets`);
score+=15;document.getElementById('hud-score').textContent=score;
showEl('s3-next');
} else {
setFb('s3-fb','err',`✘ ไม่ถูกต้อง 2${val} = ${Math.pow(2,val)} ต้องการ ≥ ${q.subsNeeded}`);
}
}
/* ════════════════════════════════════════
STEP 4 New CIDR & Mask
════════════════════════════════════════ */
function setupStep4(){
const q=questions[currentQ];
document.getElementById('s4-orig-cidr').textContent=q.cidr;
document.getElementById('s4-new-cidr').textContent=q.newCidr;
const newLastDec=parseInt(cidrMask(q.newCidr).split('.')[3]);
const prefix=cidrMask(q.newCidr).split('.').slice(0,3).map(x=>toBin(parseInt(x))).join('.')+'.';
document.getElementById('s4-prefix').textContent=prefix;
['s4-cidr-input','s4-mask-input','s4-last-octet'].forEach(id=>document.getElementById(id).value='');
document.getElementById('s4-fb').innerHTML='';
}
function checkStep4(){
const q=questions[currentQ];
const cidrIn=document.getElementById('s4-cidr-input').value.trim().replace('/','');
const maskIn=document.getElementById('s4-mask-input').value.trim();
const binIn=document.getElementById('s4-last-octet').value.trim();
const newLastDec=parseInt(cidrMask(q.newCidr).split('.')[3]);
const correctBin=toBin(newLastDec);
const cidrOk=parseInt(cidrIn)===q.newCidr||cidrIn===('/'+q.newCidr);
const maskOk=maskIn===cidrMask(q.newCidr);
const binOk=binIn===correctBin;
const lines=[];
if(cidrOk)lines.push(`✔ CIDR: /${q.newCidr}`); else lines.push(`✘ CIDR: กรอก "${cidrIn}" → ถูก: /${q.newCidr}`);
if(maskOk)lines.push(`✔ Mask: ${cidrMask(q.newCidr)}`); else lines.push(`✘ Mask: กรอก "${maskIn}" → ถูก: ${cidrMask(q.newCidr)}`);
if(binOk)lines.push(`✔ Binary: ${correctBin}`); else lines.push(`✘ Binary: กรอก "${binIn}" → ถูก: ${correctBin} (=${newLastDec})`);
const allOk=cidrOk&&maskOk&&binOk;
setFb('s4-fb',allOk?'ok':'err',lines.join('
')); if(allOk){score+=20;document.getElementById('hud-score').textContent=score;setTimeout(()=>goStep(5),700);} } /* ════════════════════════════════════════ STEP 5 Hosts ════════════════════════════════════════ */ function setupStep5(){ const q=questions[currentQ]; document.getElementById('s5-h').textContent=q.hostBits; document.getElementById('s5-hosts').textContent=q.subnets[0].hosts; ['s5-h-input','s5-hosts-input'].forEach(id=>document.getElementById(id).value=''); document.getElementById('s5-fb').innerHTML=''; } function checkStep5(){ const q=questions[currentQ]; const hIn=document.getElementById('s5-h-input').value.trim(); const hostsIn=document.getElementById('s5-hosts-input').value.trim(); const hOk=parseInt(hIn)===q.hostBits; const hostsOk=parseInt(hostsIn)===q.subnets[0].hosts; const lines=[]; if(hOk)lines.push(`✔ h = ${q.hostBits} (host bits)`); else lines.push(`✘ h: กรอก "${hIn}" → ถูก: ${q.hostBits}`); if(hostsOk)lines.push(`✔ Hosts = 2${q.hostBits} − 2 = ${q.subnets[0].hosts}`); else lines.push(`✘ Hosts: กรอก "${hostsIn}" → ถูก: ${q.subnets[0].hosts}`); setFb('s5-fb',hOk&&hostsOk?'ok':'err',lines.join('
')); if(hOk&&hostsOk){score+=15;document.getElementById('hud-score').textContent=score;setTimeout(()=>goStep(6),700);} } /* ════════════════════════════════════════ STEP 6 Subnet Ranges ════════════════════════════════════════ */ function setupStep6(){ const q=questions[currentQ]; document.getElementById('s6-current-num').textContent=currentSubnetIdx+1; document.getElementById('s6-total-num').textContent=q.subnets.length; document.getElementById('s6-block').textContent=q.subnets[0].blockSize; document.getElementById('s6-mask-ref').textContent=cidrMask(q.newCidr)+'/'+q.newCidr; ['s6-net','s6-first','s6-last','s6-bcast','s6-smask'].forEach(id=>document.getElementById(id).value=''); document.getElementById('s6-fb').innerHTML=''; hideEl('s6-hint-box'); hintUsed=false; updateProgressTags(); } function updateProgressTags(){ const q=questions[currentQ]; const cont=document.getElementById('s6-progress-tags');cont.innerHTML=''; q.subnets.forEach((_,i)=>{ const span=document.createElement('span');span.className='tag '+(icurrentSubnetIdx?'0.3':'1'; span.textContent=`แผนก${i+1}`;cont.appendChild(span); }); } function showHint6(){ hintUsed=true; const s=questions[currentQ].subnets[currentSubnetIdx]; const hb=document.getElementById('s6-hint-box'); hb.innerHTML=`⚡ คำใบ้: Network=${s.network} | First=${s.first} | Last=${s.last} | Broadcast=${s.broadcast} (−50% คะแนน)`; showEl('s6-hint-box'); } function checkStep6(){ const q=questions[currentQ]; const s=q.subnets[currentSubnetIdx]; const net=document.getElementById('s6-net').value.trim(); const first=document.getElementById('s6-first').value.trim(); const last=document.getElementById('s6-last').value.trim(); const bcast=document.getElementById('s6-bcast').value.trim(); const smask=document.getElementById('s6-smask').value.trim(); let pts=0;const lines=[]; const chk=(got,correct,label)=>{ if(got===correct){pts+=8;lines.push(`✔ ${label}: ${got}`);} else lines.push(`✘ ${label}: "${got}" → ถูก: ${correct}`); }; chk(net,s.network,'Network Address'); chk(first,s.first,'First Usable IP'); chk(last,s.last,'Last Usable IP'); chk(bcast,s.broadcast,'Broadcast'); chk(smask,s.mask,'Subnet Mask'); const earned=hintUsed?Math.floor(pts*.5):pts; score+=earned;document.getElementById('hud-score').textContent=score; const ok=pts===40; setFb('s6-fb',ok?'ok':pts>0?'info':'err',lines.join('
')+`
+${earned} pts${hintUsed?' (hint −50%)':''}`); // Mark vis block const blk=document.getElementById('sblk-'+currentSubnetIdx); if(blk){blk.classList.remove('pending');blk.classList.add('done');} subnetAnswers.push({idx:currentSubnetIdx,ok,pts:earned,s}); currentSubnetIdx++; if(currentSubnetIdx>=q.subnets.length){ setTimeout(showStep6Done,800); } else { document.getElementById('s6-current-num').textContent=currentSubnetIdx+1; setTimeout(()=>{setupStep6();},800); } } function skipSubnet6(){ const q=questions[currentQ]; const s=q.subnets[currentSubnetIdx]; subnetAnswers.push({idx:currentSubnetIdx,ok:false,pts:0,s}); const blk=document.getElementById('sblk-'+currentSubnetIdx);if(blk)blk.classList.add('done'); currentSubnetIdx++; if(currentSubnetIdx>=q.subnets.length) showStep6Done(); else{document.getElementById('s6-current-num').textContent=currentSubnetIdx+1;setupStep6();} } function showStep6Done(){ hideEl('step6'); const q=questions[currentQ]; let html=''; subnetAnswers.forEach((a,i)=>{ const c=SUB_COLORS[i%SUB_COLORS.length]; html+=`
`;
});
document.getElementById('s6-summary').innerHTML=html;
showEl('step6-done');
}
/* ════════════════════════════════════════
SHOW NEXT BTN (after subnetting done)
════════════════════════════════════════ */
function showNextBtn(){
allResults.push({q:questions[currentQ],answers:subnetAnswers,machines:JSON.parse(JSON.stringify(machineData))});
if(currentQ<4)showEl('btn-next');
else showEl('btn-finish');
}
/* ════════════════════════════════════════
ASSIGN MACHINES
════════════════════════════════════════ */
function renderAssignMachines(q){
const cont=document.getElementById('assign-machines');cont.innerHTML='';
q.subnets.forEach((s,i)=>{
const mac1=genMac(),mac2=genMac();
machineData['server_'+i]={mac:mac1};machineData['client_'+i]={mac:mac2};
const c=SUB_COLORS[i%SUB_COLORS.length];
const wrap=document.createElement('div');wrap.className='machine-wrap';
wrap.style.borderColor=c.border;
wrap.innerHTML=`
`;
cont.appendChild(wrap);
});
}
function checkAssign(){
const q=questions[currentQ];let totalPts=0;
q.subnets.forEach((s,i)=>{
const srvIp=document.getElementById(`srv-ip-${i}`)?.value.trim();
const srvMask=document.getElementById(`srv-mask-${i}`)?.value.trim();
const srvGw=document.getElementById(`srv-gw-${i}`)?.value.trim();
const cliIp=document.getElementById(`cli-ip-${i}`)?.value.trim();
const cliMask=document.getElementById(`cli-mask-${i}`)?.value.trim();
const srvNum=ip2n(srvIp||'0.0.0.0'),cliNum=ip2n(cliIp||'0.0.0.0');
const netNum=ip2n(s.network),bcastNum=ip2n(s.broadcast);
const srvOk=srvNum>netNum&&srvNumnetNum&&cliNumแผนก${i+1}: Server ${srvOk?'✔':'✘'} | Client ${cliOk?'✔':'✘'} | Mask ${maskOk1&&maskOk2?'✔':'✘'} → +${pts} pts`;
});
score+=totalPts;document.getElementById('hud-score').textContent=score;
document.getElementById('assign-fb').innerHTML=`
IP
SUBNET LAB
NETWORK ENGINEER TRAINING SIMULATION v3.0
SYSTEM ONLINE
╔══════════════════════════════════════════════╗
║ STEP 1: คำนวณ Bits ที่ต้องยืม ║
║ STEP 2: หา New CIDR & Subnet Mask ║
║ STEP 3: คำนวณจำนวน Hosts/Subnet ║
║ STEP 4: กรอก IP Range แต่ละ Subnet ║
║ STEP 5: กำหนด IP ให้ Server & Client ║
╚══════════════════════════════════════════════╝
║ STEP 1: คำนวณ Bits ที่ต้องยืม ║
║ STEP 2: หา New CIDR & Subnet Mask ║
║ STEP 3: คำนวณจำนวน Hosts/Subnet ║
║ STEP 4: กรอก IP Range แต่ละ Subnet ║
║ STEP 5: กำหนด IP ให้ Server & Client ║
╚══════════════════════════════════════════════╝
IP SUBNETTING LAB
เรียนรู้แบบ step-by-step เหมือนคิดบนกระดาษ
// OPERATOR INIT
▶ เริ่มปฏิบัติการ
ชื่อผู้ปฏิบัติการ
ระดับความยาก
🟢
EASY
/24 networks
🟡
MEDIUM
/22/24
🔴
HARD
/16/24
Operator
Mission1/5
LevelEASY
Score0
// MISSION
Network
Subnets
Original Mask
// STEP 1 ตารางค่า Bit
อ้างอิงค่าบิต (Octet สุดท้าย)
💡 ตารางนี้แสดงค่าของแต่ละบิตในออกเตตสุดท้าย ใช้อ้างอิงตลอดการคำนวณ
ถัดไป →
✔ เสร็จสิ้น Subnetting
// IP ASSIGNMENT
กำหนด IP, Subnet Mask, Default Gateway ให้ Server และ Client
✔ บันทึกและตรวจสอบ
▶ โจทย์ถัดไป
🏆 ดูผลคะแนน
0
/ 500
// MISSION REPORT
📋 Export รายงาน
↺ เล่นใหม่
')); if(allOk){score+=20;document.getElementById('hud-score').textContent=score;setTimeout(()=>goStep(5),700);} } /* ════════════════════════════════════════ STEP 5 Hosts ════════════════════════════════════════ */ function setupStep5(){ const q=questions[currentQ]; document.getElementById('s5-h').textContent=q.hostBits; document.getElementById('s5-hosts').textContent=q.subnets[0].hosts; ['s5-h-input','s5-hosts-input'].forEach(id=>document.getElementById(id).value=''); document.getElementById('s5-fb').innerHTML=''; } function checkStep5(){ const q=questions[currentQ]; const hIn=document.getElementById('s5-h-input').value.trim(); const hostsIn=document.getElementById('s5-hosts-input').value.trim(); const hOk=parseInt(hIn)===q.hostBits; const hostsOk=parseInt(hostsIn)===q.subnets[0].hosts; const lines=[]; if(hOk)lines.push(`✔ h = ${q.hostBits} (host bits)`); else lines.push(`✘ h: กรอก "${hIn}" → ถูก: ${q.hostBits}`); if(hostsOk)lines.push(`✔ Hosts = 2${q.hostBits} − 2 = ${q.subnets[0].hosts}`); else lines.push(`✘ Hosts: กรอก "${hostsIn}" → ถูก: ${q.subnets[0].hosts}`); setFb('s5-fb',hOk&&hostsOk?'ok':'err',lines.join('
')); if(hOk&&hostsOk){score+=15;document.getElementById('hud-score').textContent=score;setTimeout(()=>goStep(6),700);} } /* ════════════════════════════════════════ STEP 6 Subnet Ranges ════════════════════════════════════════ */ function setupStep6(){ const q=questions[currentQ]; document.getElementById('s6-current-num').textContent=currentSubnetIdx+1; document.getElementById('s6-total-num').textContent=q.subnets.length; document.getElementById('s6-block').textContent=q.subnets[0].blockSize; document.getElementById('s6-mask-ref').textContent=cidrMask(q.newCidr)+'/'+q.newCidr; ['s6-net','s6-first','s6-last','s6-bcast','s6-smask'].forEach(id=>document.getElementById(id).value=''); document.getElementById('s6-fb').innerHTML=''; hideEl('s6-hint-box'); hintUsed=false; updateProgressTags(); } function updateProgressTags(){ const q=questions[currentQ]; const cont=document.getElementById('s6-progress-tags');cont.innerHTML=''; q.subnets.forEach((_,i)=>{ const span=document.createElement('span');span.className='tag '+(icurrentSubnetIdx?'0.3':'1'; span.textContent=`แผนก${i+1}`;cont.appendChild(span); }); } function showHint6(){ hintUsed=true; const s=questions[currentQ].subnets[currentSubnetIdx]; const hb=document.getElementById('s6-hint-box'); hb.innerHTML=`⚡ คำใบ้: Network=${s.network} | First=${s.first} | Last=${s.last} | Broadcast=${s.broadcast} (−50% คะแนน)`; showEl('s6-hint-box'); } function checkStep6(){ const q=questions[currentQ]; const s=q.subnets[currentSubnetIdx]; const net=document.getElementById('s6-net').value.trim(); const first=document.getElementById('s6-first').value.trim(); const last=document.getElementById('s6-last').value.trim(); const bcast=document.getElementById('s6-bcast').value.trim(); const smask=document.getElementById('s6-smask').value.trim(); let pts=0;const lines=[]; const chk=(got,correct,label)=>{ if(got===correct){pts+=8;lines.push(`✔ ${label}: ${got}`);} else lines.push(`✘ ${label}: "${got}" → ถูก: ${correct}`); }; chk(net,s.network,'Network Address'); chk(first,s.first,'First Usable IP'); chk(last,s.last,'Last Usable IP'); chk(bcast,s.broadcast,'Broadcast'); chk(smask,s.mask,'Subnet Mask'); const earned=hintUsed?Math.floor(pts*.5):pts; score+=earned;document.getElementById('hud-score').textContent=score; const ok=pts===40; setFb('s6-fb',ok?'ok':pts>0?'info':'err',lines.join('
')+`
+${earned} pts${hintUsed?' (hint −50%)':''}`); // Mark vis block const blk=document.getElementById('sblk-'+currentSubnetIdx); if(blk){blk.classList.remove('pending');blk.classList.add('done');} subnetAnswers.push({idx:currentSubnetIdx,ok,pts:earned,s}); currentSubnetIdx++; if(currentSubnetIdx>=q.subnets.length){ setTimeout(showStep6Done,800); } else { document.getElementById('s6-current-num').textContent=currentSubnetIdx+1; setTimeout(()=>{setupStep6();},800); } } function skipSubnet6(){ const q=questions[currentQ]; const s=q.subnets[currentSubnetIdx]; subnetAnswers.push({idx:currentSubnetIdx,ok:false,pts:0,s}); const blk=document.getElementById('sblk-'+currentSubnetIdx);if(blk)blk.classList.add('done'); currentSubnetIdx++; if(currentSubnetIdx>=q.subnets.length) showStep6Done(); else{document.getElementById('s6-current-num').textContent=currentSubnetIdx+1;setupStep6();} } function showStep6Done(){ hideEl('step6'); const q=questions[currentQ]; let html=''; subnetAnswers.forEach((a,i)=>{ const c=SUB_COLORS[i%SUB_COLORS.length]; html+=`
แผนกที่ ${i+1}
${a.pts} pts
Network Address${a.s.network}
First Usable IP${a.s.first}
Last Usable IP${a.s.last}
Broadcast Address${a.s.broadcast}
Subnet Mask${a.s.mask}/${a.s.cidr}
SERVER
MAC: ${mac1}
IP Address
Subnet Mask
Default Gateway
CLIENT PC
MAC: ${mac2}
IP Address
Subnet Mask
Default Gateway
+${totalPts} pts จากการกำหนด IP
`;
// update last result's machines
if(allResults.length>0)allResults[allResults.length-1].machines=JSON.parse(JSON.stringify(machineData));
}
/* ══════_