icoa-cli 2.19.649 → 2.19.650
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/ai4ctf.js +1 -1
- package/dist/commands/battle.js +1 -1
- package/dist/commands/ctf4ai-demo.js +1 -1
- package/dist/commands/ctf4vla.js +1 -1
- package/dist/commands/duck.js +1 -1
- package/dist/commands/exam.js +1 -1
- package/dist/commands/learn.js +1 -1
- package/dist/lib/learn-cup.js +1 -1
- package/dist/lib/learn-i18n.js +1 -1
- package/dist/lib/learn-pvp.js +1 -1
- package/dist/lib/learn-render.js +1 -1
- package/package.json +1 -1
package/dist/commands/ctf4vla.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(b,d){const P=a0d,f=b();while(!![]){try{const h=parseInt(P(0x92))/(0x29*-0x7b+0x203*0x1+-0x7*-0x287)*(parseInt(P(0xd9))/(-0x13af+0x10c+0x12a5))+parseInt(P(0x72))/(-0x795+0xe*-0x1ae+-0xb*-0x2d4)+-parseInt(P(0x9a))/(-0x1666+-0x1*0x10f+0x3*0x7d3)+parseInt(P(0xd4))/(-0x197a+-0x5*0x72f+-0x7*-0x8c6)+parseInt(P(0x9f))/(0x706+0x1900+-0x40*0x80)*(parseInt(P(0x8e))/(-0x502*0x3+-0x8a9*0x3+0x65*0x68))+parseInt(P(0xb5))/(-0x70a+-0x9e*-0x9+-0x1*-0x184)*(parseInt(P(0xac))/(-0x1d*-0x2a+-0x51*-0x9+-0x143*0x6))+parseInt(P(0xbe))/(-0x11f3+0x26ef+-0x2fe*0x7)*(-parseInt(P(0xb4))/(-0x3*-0xb7+0xbc7+-0xde1*0x1));if(h===d)break;else f['push'](f['shift']());}catch(j){f['push'](f['shift']());}}}(a0b,0x3afff+-0x4c592+0x5e*0x1370));import a0m from'chalk';import{readFileSync as a0q,existsSync as a0v}from'node:fs';import{resolve as a0w,join as a0x}from'node:path';import{spawn as a0y}from'node:child_process';import{logCommand as a0z}from'../lib/logger.js';import{getExamState as a0A,saveExamState as a0B}from'../lib/exam-state.js';import{printError as a0C}from'../lib/ui.js';let c=null,g=!(0xad*0xa+0x9f1*-0x1+-0x44*-0xc);export function isCtf4VlaActive(){return g;}export function enterCtf4Vla(b){const Q=a0d,d=a0A();if(!d)return a0C(Q(0xca)),!(0xdc+0x262a+-0x2705);const f=d[Q(0x82)]['find'](h=>h[Q(0x91)]===b);return f?Q(0xa1)!==f[Q(0xcc)]?(a0C('Q'+b+Q(0x100)),!(0x1*-0x25ff+0xa12*0x1+0x1bee)):(c={'qNum':b,'question':f,'baselineSeen':!(-0x5*0x533+-0xdb+0x19*0x113),'probesUsed':0x0,'startedAt':Date[Q(0xde)]()},g=!(-0x217*-0x1+0x2*0x689+-0xf29),(function(){const R=Q;if(!c)return;const h=c[R(0xad)],j=(a0A()?.[R(0xb8)]||{})[c[R(0xef)]];console['log'](),console[R(0x75)](a0m[R(0x99)][R(0xf6)]('\x20\x20═══\x20CTF4EAI\x20—\x20Q'+c['qNum']+':\x20'+(h['category']||'EAI')+R(0x9d))),j&&console['log'](a0m['gray']('\x20\x20Current\x20answer:\x20')+a0m[R(0xf3)](j)+a0m['gray'](R(0xd3))),console[R(0x75)](),console['log'](a0m['cyan']('\x20\x20┌────────────────────────────────────────────────────')),console[R(0x75)](a0m[R(0xf6)](R(0xab))+a0m[R(0x99)]['white']('Q'+c[R(0xef)]+R(0xa8)+(h['category']||'EAI')+R(0x74)+(h['points']||-0x194f+0x2261+-0x90c)+R(0xaf))),console[R(0x75)](a0m[R(0xf6)](R(0xe0)));for(const k of String(h['text']||'')[R(0xa2)]('\x0a')){const m=k[R(0xed)]>0x181+0x16b4+-0x17f5?k[R(0xd7)](-0x1963+0xa03+0xf60,-0x1e50*-0x1+0x1d16+-0x41*0xe9)+'...':k;console[R(0x75)](a0m[R(0xf6)](R(0xab))+a0m[R(0xd2)](m));}console[R(0x75)](a0m[R(0xf6)]('\x20\x20│')),console['log'](a0m[R(0xf6)](R(0xab))+a0m[R(0x71)]('Full\x20question:\x20\x20')+a0m[R(0xd2)](R(0x76)+c[R(0xef)])),console['log'](a0m[R(0xf6)](R(0xab))+a0m[R(0x71)](R(0xc7))),console[R(0x75)](a0m[R(0xf6)]('\x20\x20└────────────────────────────────────────────────────')),console[R(0x75)](),console[R(0x75)](a0m['bold']['white'](R(0xd8))),console['log'](),console[R(0x75)](a0m[R(0x99)]['green'](R(0xba))+a0m['gray']('\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20show\x20default-instruction\x20action')),console[R(0x75)](a0m[R(0x99)][R(0xb2)](R(0xfe))+a0m['gray'](R(0x8f))),console[R(0x75)](a0m[R(0x99)][R(0xb2)](R(0xfa))+a0m[R(0x71)](R(0xc6))),console[R(0x75)](a0m[R(0x99)][R(0xb2)](R(0xa6))+a0m['gray'](R(0xfb))),console['log'](a0m[R(0x99)][R(0xb2)](R(0xa4))+a0m[R(0x71)](R(0xbb))),console['log'](a0m[R(0x71)](R(0xd5))+a0m[R(0x71)](R(0xfc))),console[R(0x75)](a0m['gray'](R(0x8a))+a0m[R(0x71)](R(0xa0))),console[R(0x75)]();}()),!(-0x244d+-0x16a2+0x3aef)):(a0C('Question\x20'+b+'\x20not\x20in\x20current\x20exam.'),!(0x1*-0x1acf+-0x14d2+0x2fa2));}function u(b,d){const S=a0d,f=b[S(0xbd)](),h=/\b(release|drop|let\s*go|open\s+gripper|stop)\b/i['test'](f);/\b(red|rojo|赤い|红)\b/i[S(0xa7)](f)&&/\b(pick|grab|grasp|抓|取)\b/i['test'](f);let j=0x1345+0x119a+0x24df*-0x1+0.95,k=[-0xb09+-0x23b*-0xd+-0x11f6+0.31,0x610+-0x1539+-0x1*-0xf29+0.12,0x90f+0xe32+-0x1741+0.45],m=S(0xb9);return-0x1*0x5ad+-0x3*0x2bd+0x21*0x6d===d?h&&(j=-0xe5c*0x2+0x16f*0x9+0x1*0xfd1+0.04+(-0x1db6+0x11*0x95+0x13d1+0.02)*Math[S(0xe4)](),k=[0x975*-0x1+-0x1*-0x13a+0x83b+0.31,0xf70*-0x1+0x1*-0x1763+0x26d3+0.12,-0x81f+-0x1e2e+-0x264d*-0x1+0.45],m=S(0xe2)+j[S(0xf1)](-0xeb*-0x25+-0x1791+-0xa64)+S(0xb0)):-0x1*-0xcde+0x1e5b+0xe5a*-0x3===d&&/\b(purple|transparent|invisible|orange)\b/i[S(0xa7)](f)&&(j=0x625*0x3+-0x4*0x1f1+-0xaab+0.5,k=[-0x25b*-0x2+0x275*-0x9+-0x1ef*-0x9+0.001,-0x1*0x1ec1+-0x2b*-0xb1+-0x1*-0x106,0x1*0x3f2+0x10b8+-0x14aa+0.001],m=S(0xd1)),{'gripper':j,'xyz':k,'flagCondition':0x495+0xec1+-0x132d===d&&j<0x22df+-0x1724+-0x15*0x8f+0.1||-0x56d*0x1+0x1b6f+0x1*-0x15d7===d&&Math[S(0xf7)](k[-0x2ba*-0xd+0x2127+-0x4499]**(-0x1*-0xcf6+0xd10+-0x4a*0x5a)+k[0x1c67+-0x30f+0xd*-0x1f3]**(-0xe*0x148+-0x4e+0x40*0x49)+k[0x1b1*0x3+-0x1256*0x1+-0x2b*-0x4f]**(0x2*-0xb45+-0x23*-0x4d+0x11*0xb5))<-0x1f91+0x65c+0x1935+0.05,'description':m};}function a0d(a,b){a=a-(0x101e+0x1a6b+-0x2a1a);const c=a0b();let d=c[a];if(a0d['GWdnvh']===undefined){var e=function(i){const j='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let l='',m='';for(let n=0x1a4f+-0xd*0x8c+0x3d7*-0x5,o,p,q=-0x1d*-0x7+0x2385*0x1+-0x2450;p=i['charAt'](q++);~p&&(o=n%(-0x138d+0x1*-0x1ae3+0x1*0x2e74)?o*(0x2007+-0xdbf+-0x2*0x904)+p:p,n++%(0x1*-0x42f+0x1*0x150d+-0x10da))?l+=String['fromCharCode'](0x74d+0x54c+-0x6*0x1ef&o>>(-(0x119*-0xc+-0x198+0xec6)*n&-0x1365*0x2+-0x1963+0x4033)):-0x1e50*-0x1+0x1d16+-0x2*0x1db3){p=j['indexOf'](p);}for(let r=-0x244d+-0x16a2+0x3aef,s=l['length'];r<s;r++){m+='%'+('00'+l['charCodeAt'](r)['toString'](0x1*-0x1acf+-0x14d2+0x2fb1))['slice'](-(0x1345+0x119a+0x24dd*-0x1));}return decodeURIComponent(m);};a0d['TewgZd']=e,a0d['bnDkQE']={},a0d['GWdnvh']=!![];}const f=c[-0xb09+-0x23b*-0xd+-0x11f6],g=a+f,h=a0d['bnDkQE'][g];return!h?(d=a0d['TewgZd'](d),a0d['bnDkQE'][g]=d):d=h,d;}function a0b(){const Z=['mJa2mZm5nNPTEwDYDG','ChjVyMvZvxnLza','C2LTia','iokvKokvKokvKa','C3vIBwL0ia','nLDfCMzluW','icaGicaGicaGicaGicaGicaGihjLDhvYBIb0BYbTywLUig1LBNuGkgjVB3qGC2nYzwvUksdIGjqGD29YA3mGyw55D2HLCMu','DMXH','C3bSAxq','ue9tva','icaGihnPBq','l3nPBq','icaGihn1yM1PDcbjq09bEY4UlN0','DgvZDa','icbB','zgv0ywnOzwq','ihjLy29YzgvKoIa','icdILiiG','oxHICevVtq','CxvLC3rPB24','AwnVys1ZAw0TCq','ihb0CW','ksWGyxjTigHVBgrZihbVC2L0Aw9U','ktOG','z3jLzw4','BM9KztPMCW','mJmXuMXNyxrm','ndK4ntq0rvnWD2j1','yw5ZD2vYx3n1yM1PDhrLza','yMfZzwXPBMvtzwvU','yw5ZD2vYCW','z3jPChbLCIbJBg9ZAw5Nig9UihjLzcbJDxaGyxqGkdaUmZeSidaUmtiSidaUnduP','icaGigjHC2vSAw5L','icaGicaGicaGicaGicaGicaGicbYzxbSyxKGy3vYCMvUDcbHy3rPB24GAw4GtxvkB0nVicHHDxrVlw9Wzw5Zie1qncK','icbuCNKGB25Lig9MoIa','Dg9mB3DLCKnHC2u','mJe4mdCWvfjKr3fV','Aw1Hz2uGywnJzxb0zwqGyNv0ig5VigfJDgLVBIbKCMLMDcbKzxrLy3rLza','Ahr0Chm6lY9WCMfJDgLJzs5Py29HmJaYnI5HDq','icbby3rPB246ia','zgvZy3jPChrPB24','z3jPChbLCIbJBg9ZAw5Nigf0icGTmc4YocWGmc4XmIWGmc40nsKG4OcuifrbuKDfvcbtseLgveveihrVihjPz2H0ihnPzguGkgTUAwzLkq','sunpqxT2BgfFChjVBxb0x2LUAMvJDh0','l2fWAs9HAs92BgeV','icaGicaGicaGicb1CgXVywqGBw9KAwzPzwqGAw1Hz2uGkgfKDMvYC2fYAwfSihbHDgnOkq','rMXHzYbMB3jTyxq6icaGieLdt0f7lI4UFq','icdINjmGqw5ZD2vYigzVCIbr','y3rMnhzSyq','tM8GzxHHBsbPBIbWCM9NCMvZCY4GuNvUigbLEgfTidX0B2TLBJ5GigzPCNn0lG','icbjq09blvzmqsbHy3rPB246ia','DhLWzq','y29UDgLUDwu','EgrNlw9Wzw4','C3vJy2vZCW','BM8GAw1Hz2uGDxbSB2fKzwqG4OcuigjHC2vSAw5LigfJDgLVBIbYzxr1CM5Lza','yxjTigHLC2L0yxrPBMCSig5VignSzwfYihrHCMDLDcaOFhX4ExP8FcdIIyGGmcK','D2HPDgu','icHZDwjTAxqGywDHAw4GDg8Gy2HHBMDLkq','mJG0nteZnvjmC0zXBW','icaGigv4Axq','C3rKAw8','C2XPy2u','icbiB3CGDg8Gyxr0ywnRihrOAxmGvKXb','mta0ntzktKjVv28','lM1Wna','DMLHign0zJr2Bge','sunpqxT5B3vYx2zSywD9','ChvZAa','BM93','DhjPBq','icdILii','y3rMnhzSytOG','z3jPChbLCIbpuevosu5hicG','ugLJAYb1Ccb0AguGCMvKign1Ca','CMfUzg9T','sunpqs1wteeGywn0Aw9UoIa','sunpqxTWyxrJAf9YzwrPCMvJDh0','D2LUmZi','icbszxr1CM5Lzcb0BYbLEgfTlG','zxHPDa','Bwf0y2G','sunpqxTIywnRzg9VCL90CMLNz2vYFq','icdINjmG','BgvUz3rO','icbgBgfNigzVCM1HDdOG','Cu51Bq','B3bLBG','Dg9gAxHLza','sunpqxT1BMTUB3DUFq','EwvSBg93','C3rHCNq','ihrVihjLy29Yzcb5B3vYigfUC3DLCI4','y3LHBG','C3fYDa','icbpCgvUAw5NigLUihLVDxiGzgvMyxvSDcb2AwrLBYbWBgf5zxiUlI4','yMfZzwXPBMuGlYbWCM9IzsaIlI4UiIaVigLTywDLidXWyxrOpIaVigHPBNqGys9Il2mGlYbZDwjTAxqGsunpqxSUlI59ic8GzxHPDa','icaGigLTywDLidXWyxrOpG','icaGicaGihn1yM1PDcb5B3vYigzSywC','icaGicaGicaGicaGicaGicaGihjLDhvYBIb0BYbLEgfT','C3rYAw5NAwz5','icaGihbYB2jLici8Aw5ZDhj1y3rPB24+iG','zMXHz0nVBMrPDgLVBG','igLZig5VDcbHifzmqsbJAgfSBgvUz2uU','BwvZC2fNzq','CxvPDa','l3rTCa','z3jHEq','otqZnZq2CKjLt2nL','Bxa0x2i2na','xsaGWRCG','Bg9N','zxHHBsbXia','yxbWBgLJyxrPB24VANnVBG','zgf0yq','icbszw5KzxiGzMfPBgvKicG','icdIHPiG','sunpqxTHy3rPB25FAMfPBgjYzwfRFq','ywn0Aw9U','icdINjmGv2LUignVBMrPDgLVBIbTzxqHicbgBgfNoIa','zNjVBq','x2XHC3rr','y29TBwfUza','icaI','CxvLC3rPB25Z','CMvWBgfJzq','icbtAw0GzxjYB3i6ia','icbezwzHDwX0igLUC3rYDwn0Aw9UoIa','q29UDgvUDc1uExbL','EhL6','y3rMngvHAq','iIbSB29RCYbSAwTLigfUie1dusbSzxr0zxiSig5VDcbHigzSywCU','icaGig1LBNu','CgXHDgzVCM0','igfUC3DLCIb1CgrHDgvKoIa','lI4VBgLIl2nVDw50zg93BI5QCW','mJa5mZu3nhH2qvvuBq','icb0zxn0igeGy3vZDg9TigLUC3rYDwn0Aw9U','icdINjmGuq','BNvTyMvY','mJrrCgHYDfq','Aw50zxjHy3rPB25Z','ANnVBG','sunpqxT2BgfFy29UzNvZzwr9','z3jPChbLCG','yMfZzty0','C3rHCNrZv2L0Aa','yM9Sza'];a0b=function(){return Z;};return a0b();}function p(b){const T=a0d;return-0x1*-0x244a+0x8e*-0x16+-0x17ed===b?T(0xc4):0x1*0x251d+-0x1f5b+-0x4*0x166===b?T(0xe6):0xd50+0x1347+-0x19f*0x14===b?T(0x95):0x27*-0x1d+0x24ac*0x1+-0x2015===b?T(0x7b):-0x3b*-0x5+0xc0*-0x16+0xf86*0x1===b?T(0xeb):T(0xf2);}export async function handleCtf4VlaMessage(h){const U=a0d;if(!c)return U(0xe9);const j=h[U(0xdf)](),k=j[U(0xbd)]();if(a0z(U(0xe1)+j),U(0xe9)===k||'back'===k||U(0x6f)===k)return g=!(-0x6*-0x5a7+0x1406+-0x35ef),c=null,console[U(0x75)](),console[U(0x75)](a0m[U(0x71)](U(0xe8))),console[U(0x75)](),U(0xe9);if('sim'===k||k[U(0x98)](U(0x9c)))return await async function(x,z){const V=U,A=(process.env.ICOA_SERVER_URL?.[V(0x83)](/\/+$/,'')||V(0xc0))+V(0xc5)+x+V(0xa5);console[V(0x75)]();const {fetchWithCountdown:B}=await import(V(0x8d));try{const C={};C[V(0x86)]=V(0x77);const D={};D[V(0x7c)]=z??null;const E=fetch(A,{'method':V(0xa3),'headers':C,'body':JSON[V(0xfd)](D),'signal':AbortSignal['timeout'](-0x56bd+-0xb5c7+0x181b4)}),F=await B(E);if(!F['ok']){const M=await F['text']()['catch'](()=>'');return void console[V(0x75)](a0m[V(0xf3)](V(0x79)+F['status']+V(0xb1)+M['slice'](0x10fd+0x7b3+-0x18b0,0x137b+0x196b+-0x2c6e)));}const G=await F[V(0x94)]();if(!G[V(0xcf)]||!G[V(0x78)]?.['mp4_b64'])return void console[V(0x75)](a0m[V(0xf3)]('\x20\x20Renderer\x20returned\x20no\x20video\x20(MuJoCo\x20unavailable\x20on\x20backend).'));const H=process.env.TMPDIR||V(0x70),I=a0x(H,V(0xae)+x+'-'+Date['now']()+V(0xda)),{writeFileSync:J}=await import(V(0xb3));J(I,Buffer[V(0x7e)](G[V(0x78)][V(0x73)],V(0x97))),console[V(0x75)](a0m[V(0xb2)](V(0xec))+a0m[V(0x71)]('Rendered.')),G['data'][V(0xc2)]&&console[V(0x75)](a0m['gray'](V(0xc1))+a0m['white'](G[V(0x78)][V(0xc2)]));const K='darwin'===process[V(0x8b)]?V(0xf0):V(0xe7)===process[V(0x8b)]?V(0xf4):V(0xce),L={};L[V(0xd6)]='ignore',L[V(0xa9)]=!(-0x205e+0x8+0x2056),K?(a0y(K,[I],L)['unref'](),console[V(0x75)](a0m['gray'](V(0xf8)))):console['log'](a0m['gray']('\x20\x20Open\x20the\x20file\x20above\x20in\x20your\x20video\x20player.'));}catch(N){const O=N instanceof Error?N[V(0x101)]:String(N);console[V(0x75)](a0m[V(0xf3)](V(0x84)+O));}}(c[U(0xef)]),'continue';if('baseline'===k){const x=c[U(0xad)]['baselineInstruction']||U(0xe3),z=u(x,c['qNum']);return c[U(0xb7)]=!(0x20e*-0x2+-0xc7e*-0x3+-0x215e),console['log'](),console[U(0x75)](a0m['gray'](U(0x85))+a0m[U(0xd2)]('\x22'+x+'\x22')),console[U(0x75)](a0m['gray'](U(0xcb))+a0m[U(0xd2)](z[U(0xc2)])),console[U(0x75)](),U(0xcd);}const q=j['match'](/^probe\s+["']?(.+?)["']?\s*$/i);if(q){c[U(0x9b)]+=0x1d6d+-0x281*0x1+0x8f9*-0x3;const A=u(q[0x2168+-0x1be7+0x80*-0xb],c[U(0xef)]);if(console['log'](),console[U(0x75)](a0m[U(0x71)](U(0x7a))+a0m[U(0xf6)](U(0xe5))+a0m[U(0xd2)](A['description'])),A['flagCondition']){const B=p(c['qNum']);console[U(0x75)](),console[U(0x75)](a0m[U(0x99)][U(0xb2)]('\x20\x20✓\x20Win\x20condition\x20met!\x20\x20Flag:\x20')+a0m[U(0x99)][U(0xf3)](B)),console[U(0x75)](a0m[U(0x71)]('\x20\x20Type\x20')+a0m[U(0x99)][U(0xb2)](U(0x9e)+B)+a0m['gray'](U(0xf5)));}else console[U(0x75)](a0m[U(0x71)]('\x20\x20(no\x20win\x20yet\x20—\x20keep\x20iterating)'));return console[U(0x75)](),U(0xcd);}const v=j[U(0xea)](/^image\s+(.+)$/i);if(v){const C=function(D,E){const W=U,F={};F['gripper']=0.95,F['xyz']=[0x86c+-0x855+-0x17+0.31,0xdbc+0xe46+0xf*-0x1de+0.12,0x1*0x106c+-0x217d*-0x1+-0x3*0x10a3+0.45],F[W(0xff)]=!(0x5d9+-0xb83+0x5ab),F['description']=W(0xd0);if(!a0v(D))return F;const G=a0q(D)[W(0xed)],H={};H['gripper']=0.9,H['xyz']=[-(0x665*0x5+0xa9f*0x3+0x2*-0x1feb+0.28),-0x1c4c+0x1d3e+-0xf2+0.12,0x2*0x1246+0x23f+-0x26cb+0.45],H[W(0xff)]=!(-0x1*-0x3a8+0x1*0x2465+0x1*-0x280d),H[W(0xc2)]=W(0xc3);const I={};return I[W(0x96)]=0.95,I[W(0x87)]=[-0xd64+-0x2*0x60d+0x197e+0.31,-0x8ee*0x2+0x159c+0x50*-0xc+0.12,-0x1*0xf93+-0x13*0x5f+0x16a0+0.45],I[W(0xff)]=!(0xd*-0x16f+0x2*-0x4e9+0x1c76),I[W(0xc2)]=W(0xbf),-0x27d*-0xe+0x11e8+-0x3494===E&&G>-0x570+-0x25*-0x1b+0x589?H:I;}(a0w(v[-0xb*0x4c+0xa3*0x2f+-0x1aa8][U(0xdf)]()),c[U(0xef)]);if(console[U(0x75)](),console[U(0x75)](a0m['gray']('\x20\x20Uploading\x20image...')),console[U(0x75)](a0m['gray'](U(0x7a))+a0m[U(0xf6)](U(0xe5))+a0m[U(0xd2)](C[U(0xc2)])),C[U(0xff)]){const D=p(c[U(0xef)]);console[U(0x75)](),console[U(0x75)](a0m[U(0x99)][U(0xb2)](U(0x7d))+a0m[U(0x99)][U(0xf3)](D));}return console['log'](),U(0xcd);}const w=j[U(0xea)](/^submit\s+(.+)/i);if(w){let E=w[0x47*-0x16+0x11*-0x1cf+0x24da]['trim']();if(/^submit\s+/i[U(0xa7)](E)&&(E=E[U(0x83)](/^submit\s+/i,'')[U(0xdf)]()),E=E[U(0x83)](/^["'`]+|["'`]+$/g,'')[U(0xdf)](),/^[A-Da-d]$/['test'](E))return console[U(0x75)](),console[U(0x75)](a0m[U(0xf3)](U(0x81)+E+U(0x89))),console['log'](a0m[U(0x71)](U(0xee))+a0m['green'](U(0xdc))),console[U(0x75)](),U(0xcd);const F=a0A();if(!F)return'exit';const G=F['answers'][c[U(0xef)]];return F[U(0x93)]||(F[U(0x93)]=[]),F[U(0x93)][U(0xdd)]({'ts':new Date()['toISOString'](),'q':c[U(0xef)],'type':G?'answer_changed':U(0xb6),'input':E,'result':U(0xdb)}),F[U(0xb8)][c[U(0xef)]]=E,F[U(0x7f)]=c['qNum']+(0xbe6+0x2*-0xd3+-0xa3f*0x1)<=0x7*-0x36d+-0x1c6f*0x1+0x3497?c[U(0xef)]+(-0xef3+0x7*-0xea+0x6*0x38f):c['qNum'],a0B(F),console[U(0x75)](),G?console[U(0x75)](a0m[U(0xb2)](U(0x90)+c['qNum']+U(0x8c))+a0m[U(0xf3)](E)):console[U(0x75)](a0m[U(0xb2)][U(0x99)](U(0xc8)+c['qNum']+U(0xaa)+E)),console[U(0x75)](a0m['gray']('\x20\x20(Correctness\x20shown\x20after\x20final\x20exam\x20submit.)')),console[U(0x75)](),U(0xcd);}return console[U(0x75)](),console[U(0x75)](a0m[U(0x71)](U(0xbc))+a0m[U(0xd2)](U(0xf9))),console[U(0x75)](),U(0xcd);}export function registerCtf4VlaCommand(b){const X=a0d;b[X(0x80)](X(0x88))['alias'](X(0xc9))[X(0xc2)]('Enter\x20the\x20Embodied\x20AI\x20security\x20challenge\x20(Paper\x20D,\x20Q41-Q45)')[X(0x7c)](()=>{const Y=X,d=a0A();if(!d)return void a0C(Y(0xca));const f=d[Y(0x7f)]||0x248c*0x1+-0x1*0x6df+0x4*-0x761;enterCtf4Vla(f>=0x1a3*0x7+0x8d9+-0x1425&&f<=-0x3*-0x35f+0x486*-0x5+0xcae?f:-0x1b46+0x1*-0x21e9+0x8*0x7ab);});}
|
|
1
|
+
(function(b,d){const P=a0d,f=b();while(!![]){try{const h=parseInt(P(0x204))/(-0x193b+0x18eb+-0x51*-0x1)*(-parseInt(P(0x1c5))/(0x2140+0xccf+-0x2e0d))+-parseInt(P(0x1b7))/(-0x1289*0x2+0x3*-0x928+0x5*0xce9)*(-parseInt(P(0x1c9))/(-0x5cd+0x308+0x2c9*0x1))+parseInt(P(0x1e1))/(-0x769*0x4+0x19fb*-0x1+-0x3*-0x128c)+-parseInt(P(0x209))/(0xdd*0x12+0x1*0x1d41+-0x2cc5)*(-parseInt(P(0x201))/(-0x1a59+0x73f*0x3+0x4a3))+-parseInt(P(0x1d3))/(-0xf9+0x1*-0x851+0x952)*(parseInt(P(0x1f6))/(-0x59*-0x57+-0x67f*0x1+-0x17b7))+parseInt(P(0x1ad))/(0x501+0x1f2+-0x3d*0x1d)*(parseInt(P(0x1c8))/(-0x1a23*-0x1+0x119*-0xe+-0xaba))+-parseInt(P(0x1a9))/(0x10fe+-0xc57+0x3*-0x189)*(parseInt(P(0x214))/(-0x54f+-0x1a1a+0x1f76));if(h===d)break;else f['push'](f['shift']());}catch(j){f['push'](f['shift']());}}}(a0b,0x31ad4+0x2ad56+0xe*-0x3d77));import a0m from'chalk';import{readFileSync as a0q,existsSync as a0v}from'node:fs';import{resolve as a0w,join as a0x}from'node:path';import{spawn as a0y}from'node:child_process';import{logCommand as a0z}from'../lib/logger.js';import{getExamState as a0A,saveExamState as a0B}from'../lib/exam-state.js';import{printError as a0C}from'../lib/ui.js';let c=null,g=!(0x4a9+0x9*-0x453+0x2243);export function isCtf4VlaActive(){return g;}export function enterCtf4Vla(b){const Q=a0d,d=a0A();if(!d)return a0C(Q(0x1cd)),!(-0x741*0x2+-0x9*0x25+0x1fa*0x8);const f=d[Q(0x1eb)][Q(0x1e4)](h=>h[Q(0x1c6)]===b);return f?Q(0x20f)!==f['type']?(a0C('Q'+b+'\x20is\x20not\x20a\x20VLA\x20challenge.'),!(-0xd2+0x5f9*-0x2+0x1d3*0x7)):(c={'qNum':b,'question':f,'baselineSeen':!(0x1*-0x201d+0x2*0x17b+-0xe94*-0x2),'probesUsed':0x0,'startedAt':Date[Q(0x1a5)]()},g=!(0x803+-0x2ed*-0xb+0x5be*-0x7),(function(){const R=Q;if(!c)return;const h=c[R(0x1d7)],j=(a0A()?.['answers']||{})[c[R(0x1ef)]];console['log'](),console['log'](a0m[R(0x1f2)][R(0x20a)](R(0x21a)+c[R(0x1ef)]+':\x20'+(h[R(0x1e5)]||R(0x1aa))+R(0x1a7))),j&&console['log'](a0m[R(0x192)](R(0x199))+a0m[R(0x1ca)](j)+a0m[R(0x192)](R(0x197))),console[R(0x1e9)](),console['log'](a0m[R(0x20a)](R(0x1c2))),console[R(0x1e9)](a0m['cyan'](R(0x1d0))+a0m[R(0x1f2)][R(0x1ff)]('Q'+c[R(0x1ef)]+R(0x1ee)+(h[R(0x1e5)]||R(0x1aa))+R(0x1d9)+(h['points']||0x1edd+-0x5*-0x567+-0x1*0x39da)+R(0x1f7))),console[R(0x1e9)](a0m['cyan'](R(0x19e)));for(const k of String(h[R(0x1d8)]||'')['split']('\x0a')){const m=k['length']>-0x23d6+-0x205f+0x4475?k[R(0x1f0)](-0x1*-0xc82+-0x1*0x67f+-0x3*0x201,0x1*0x782+0x5*-0x6d+-0x5e*0xe)+'...':k;console[R(0x1e9)](a0m[R(0x20a)](R(0x1d0))+a0m[R(0x1ff)](m));}console[R(0x1e9)](a0m['cyan']('\x20\x20│')),console[R(0x1e9)](a0m['cyan'](R(0x1d0))+a0m['gray'](R(0x1a3))+a0m[R(0x1ff)](R(0x1b8)+c[R(0x1ef)])),console[R(0x1e9)](a0m[R(0x20a)](R(0x1d0))+a0m[R(0x192)]('Flag\x20format:\x20\x20\x20\x20ICOA{...}')),console[R(0x1e9)](a0m[R(0x20a)](R(0x1fb))),console[R(0x1e9)](),console['log'](a0m[R(0x1f2)]['white'](R(0x1f5))),console[R(0x1e9)](),console[R(0x1e9)](a0m[R(0x1f2)][R(0x1ba)](R(0x213))+a0m['gray'](R(0x1e3))),console[R(0x1e9)](a0m[R(0x1f2)]['green']('\x20\x20\x20\x20probe\x20\x22<instruction>\x22')+a0m[R(0x192)]('\x20\x20test\x20a\x20custom\x20instruction')),console[R(0x1e9)](a0m[R(0x1f2)][R(0x1ba)]('\x20\x20\x20\x20image\x20<path>')+a0m['gray'](R(0x1db))),console[R(0x1e9)](a0m[R(0x1f2)][R(0x1ba)](R(0x1cf))+a0m['gray'](R(0x1e6))),console[R(0x1e9)](a0m['bold'][R(0x1ba)]('\x20\x20\x20\x20sim')+a0m[R(0x192)](R(0x219))),console[R(0x1e9)](a0m[R(0x192)](R(0x1dc))+a0m['gray'](R(0x1fd))),console[R(0x1e9)](a0m['gray'](R(0x1d2))+a0m[R(0x192)](R(0x1af))),console[R(0x1e9)]();}()),!(0x185b+0xc*-0x122+-0xac3)):(a0C(Q(0x217)+b+Q(0x18c)),!(-0x3*-0xa5b+0x243*-0x2+-0x56*0x4f));}function a0d(a,b){a=a-(-0x930+0x3d*-0x19+0x10ae);const c=a0b();let d=c[a];if(a0d['LQmdTD']===undefined){var e=function(i){const j='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let l='',m='';for(let n=-0x2004*0x1+-0x1881+0xd*0x459,o,p,q=-0x270f+-0x741*0x2+-0x15*-0x28d;p=i['charAt'](q++);~p&&(o=n%(0xd10+0x1fd8+-0x2ce4)?o*(0xa7*0x2+0x1e3f+0x1*-0x1f4d)+p:p,n++%(0x9*0x87+0x12ca+0x7d7*-0x3))?l+=String['fromCharCode'](-0x15bd+0x49c*0x7+0x131*-0x8&o>>(-(-0x1772+-0x1*-0x18be+-0x14a)*n&-0x205f+-0x1488+-0x1*-0x34ed)):-0x1*-0x270d+-0x1*0x24f+-0x1*0x24be){p=j['indexOf'](p);}for(let r=0x17*0x19c+-0xc*-0x5+-0x10*0x254,s=l['length'];r<s;r++){m+='%'+('00'+l['charCodeAt'](r)['toString'](-0x5a9*0x3+-0x3*-0x186+-0x1*-0xc79))['slice'](-(-0x1421*-0x1+0x1f53+-0x3372));}return decodeURIComponent(m);};a0d['rvTmSo']=e,a0d['fLcNCW']={},a0d['LQmdTD']=!![];}const f=c[0x1eb3+0xbbf+-0x2a72],g=a+f,h=a0d['fLcNCW'][g];return!h?(d=a0d['rvTmSo'](d),a0d['fLcNCW'][g]=d):d=h,d;}function u(b,d){const S=a0d,f=b[S(0x218)](),h=/\b(release|drop|let\s*go|open\s+gripper|stop)\b/i[S(0x1f8)](f);/\b(red|rojo|赤い|红)\b/i['test'](f)&&/\b(pick|grab|grasp|抓|取)\b/i['test'](f);let j=0x25*-0x101+-0x246f+0x4994+0.95,k=[-0x3*0x65+-0x19d4+0x1b03+0.31,-0x27d*-0xa+-0x1*0x1082+-0x860+0.12,-0xd71+0x2b5*-0x5+-0x6*-0x47f+0.45],m=S(0x1b0);return 0x197f+-0x36+-0x1920===d?h&&(j=-0x2581+0x15*-0x1+0x2596+0.04+(0x862+0x1129+-0x198b+0.02)*Math['random'](),k=[0x9*0xfd+-0x2f*0xc9+0xef*0x1e+0.31,0xe06+0x1af*0xd+-0x23e9+0.12,0x8*-0x290+0x353*-0x1+-0x141*-0x13+0.45],m=S(0x18a)+j[S(0x1ec)](0x19c3+0xe*0x1f3+-0x350b*0x1)+S(0x1d6)):-0x4*0x1a9+-0x1b8*0x4+0xdaf===d&&/\b(purple|transparent|invisible|orange)\b/i[S(0x1f8)](f)&&(j=0x15aa+0x1960+-0x2f0a+0.5,k=[0x1f*0xfe+-0x2566+0x6a4+0.001,0x2*-0x114e+0xad*-0x1d+-0x3635*-0x1,-0x2*-0xdb9+-0x35*0x81+-0xbd+0.001],m='arm\x20hesitating,\x20no\x20clear\x20target\x20(||xyz||\x20≈\x200)'),{'gripper':j,'xyz':k,'flagCondition':-0x2691+0x13a7+0x1313===d&&j<-0x23cc+0x79+-0x1*-0x2353+0.1||0x1f1d+0x8b0+0xd36*-0x3===d&&Math['sqrt'](k[-0x112f*0x1+-0x214c+0x327b]**(0x1258+-0x11*-0x137+-0x26fd*0x1)+k[0x33*-0xb4+-0x1074+0x1*0x3451]**(0x1*-0x6d9+0x2234+-0x1b59)+k[-0x19d*-0xb+0xb83*-0x1+-0x63a]**(0x1e57+-0x472+0x3*-0x8a1))<0x26*0xe6+-0x3*0x226+-0x1bb2+0.05,'description':m};}function a0b(){const Y=['DMXH','sunpqxT5B3vYx2zSywD9','CgXHDgzVCM0','q29UDgvUDc1uExbL','icaGigjHC2vSAw5L','mJm0DgTyEvz4','icbtAw0GzxjYB3i6ia','ue9tva','uxvLC3rPB24G','Dg9mB3DLCKnHC2u','icaGicaGicaGicaGicaGicaGicbYzxbSyxKGy3vYCMvUDcbHy3rPB24GAw4GtxvkB0nVicHHDxrVlw9Wzw5Zie1qncK','icdILzdILzdILzaGq1rgnevbssdIGjqGuq','icbpCgvUAw5NigLUihLVDxiGzgvMyxvSDcb2AwrLBYbWBgf5zxiUlI4','AwDUB3jL','y29TBwfUza','z3jPChbLCIbpuevosu5hicG','Dg9ju09tDhjPBMC','ig5VDcbPBIbJDxjYzw50igv4yw0U','zxHPDa','yMfZzty0','BM9KztPMCW','C3rYAw5NAwz5','AwnVys1ZAw0TCq','z3jHEq','zNjVBq','sunpqxT2BgfFy29UzNvZzwr9','Aw50zxjHy3rPB25Z','EhL6','icHZDwjTAxqGywDHAw4GDg8Gy2HHBMDLkq','icdINjmGqw5ZD2vYigzVCIbr','icbdDxjYzw50igfUC3DLCJOG','ihjLy29YzgvKoIa','yMfZzwXPBMvjBNn0CNvJDgLVBG','icdINjmGuq','icbvCgXVywrPBMCGAw1Hz2uUlI4','icdILii','icbszw5KzxjLCIbYzxr1CM5LzcbUBYb2AwrLBYaOtxvkB0nVihvUyxzHAwXHyMXLig9UigjHy2TLBMqPlG','DgLTzw91Da','C3vIBwL0ia','icbezwzHDwX0igLUC3rYDwn0Aw9UoIa','rNvSBcbXDwvZDgLVBJOGia','yMfZzwXPBMu','BM93','icbjq09blvzmqsbHy3rPB246ia','iokvKokvKokvKa','icbby3rPB246ia','mtqZodu2DMv1t1D4','rufj','rw50zxiGDgHLievTyM9KAwvKiefjihnLy3vYAxr5ignOywXSzw5NzsaOugfWzxiGrcWGutqXlve0nsK','sunpqxTWyxrJAf9YzwrPCMvJDh0','mtbJq1vdAKK','sunpqxTHy3rPB25FAMfPBgjYzwfRFq','icaGicaGicaGicaGicaGicaGihjLDhvYBIb0BYbTywLUig1LBNuGkgjVB3qGC2nYzwvUksdIGjqGD29YA3mGyw55D2HLCMu','z3jPChbLCIbJBg9ZAw5Nig9UihjLzcbJDxaGyxqGkdaUmZeSidaUmtiSidaUnduP','iIbSB29RCYbSAwTLigfUie1dusbSzxr0zxiSig5VDcbHigzSywCU','yxbWBgLJyxrPB24VANnVBG','BM8GAw1Hz2uGDxbSB2fKzwqG4OcuigjHC2vSAw5LigfJDgLVBIbYzxr1CM5Lza','icaI','lM1Wna','yw5ZD2vYCW','ntKYmZi5seX2wMvL','zxHHBsbXia','C2LT','z3jLzw4','Bxa0x2i2na','y3rMnhzSytOG','zMXHz0nVBMrPDgLVBG','z3jPChbLCG','icbgBgfNigzVCM1HDdOG','ywXPyxm','CMvWBgfJzq','icdILiZILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILia','yw5ZD2vYx2nOyw5Nzwq','CxvPDa','nZK0AuXksNLX','BNvTyMvY','x2XHC3rr','mtCZnZuYn1DgA3D2zG','nfPZAwnXrW','EwvSBg93','Bwf0y2G','B3bLBG','tM8GzxHHBsbPBIbWCM9NCMvZCY4GuNvUigbLEgfTidX0B2TLBJ5GigzPCNn0lG','y2f0y2G','icaGihn1yM1PDcbjq09bEY4UlN0','icdILiiG','icbszw5KzxiGzMfPBgvKicG','icaGig1LBNu','mZy2nZi4DLjKzw5Q','C2LTia','l3rTCa','ksWGyxjTigHVBgrZihbVC2L0Aw9U','CxvLC3rPB24','Dgv4Da','xsaGWRCG','lI4VBgLIl2nVDw50zg93BI5QCW','icaGicaGicaGicb1CgXVywqGBw9KAwzPzwqGAw1Hz2uGkgfKDMvYC2fYAwfSihbHDgnOkq','icaGigv4Axq','yMfZzwXPBMvtzwvU','Ahr0Chm6lY9WCMfJDgLJzs5Py29HmJaYnI5HDq','zgvZy3jPChrPB24','icdIHPiG','mtu3mJbHugHmB3O','EgrNlw9Wzw4','icaGicaGicaGicaGicaGC2HVDYbKzwzHDwX0lwLUC3rYDwn0Aw9UigfJDgLVBG','zMLUza','y2f0zwDVCNK','icaGicaGihn1yM1PDcb5B3vYigzSywC','icdINjmG','yMfJAW','Bg9N','C3rHCNq','CxvLC3rPB25Z','Dg9gAxHLza','DhjPBq','icbB','Cu51Bq','C2XPy2u','sunpqxT1BMTUB3DUFq','yM9Sza','y3rMnhzSyq','l3nPBq','icbiB3CGDg8Gyxr0ywnRihrOAxmGvKXb','mJDTww5qvxq','ihb0CW','DgvZDa','BgvUz3rO','l2fWAs9HAs92BgeV','icdILjtILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILidILia','z3jPChbLCIbJBg9ZAw5Nigf0icGTmc4YocWGmc4XmIWGmc40nsKG4OcuifrbuKDfvcbtseLgveveihrVihjPz2H0ihnPzguGkgTUAwzLkq','icaGicaGicaGicaGicaGicaGihjLDhvYBIb0BYbLEgfT','zgf0yq','D2HPDgu','ktOG','mtGYoty1m2PyyLnlBa','ywn0Aw9U','DMLHign0zJr2Bge','mJCYwu5UwLff','igfUC3DLCIb1CgrHDgvKoIa','ihrVihjLy29Yzcb5B3vYigfUC3DLCI4','ANnVBG','ugLJAYb1Ccb0AguGCMvKign1Ca','nNvwuefVzG','y3LHBG','sunpqs1wteeGywn0Aw9UoIa','y29UDgLUDwu','zgv0ywnOzwq','sunpqxT2BgfFChjVBxb0x2LUAMvJDh0'];a0b=function(){return Y;};return a0b();}function p(b){const T=a0d;return 0x6b*-0x1+-0x18d7+0x196b===b?T(0x20e):-0x473*0x8+0x23e0+-0x1e===b?T(0x1ac):-0x1950+-0xd*0x4a+-0x1d3d*-0x1===b?T(0x194):0x120f+0x135*0x19+0x1*-0x3010===b?T(0x1ae):-0x1073*0x2+0x1820+-0x1*-0x8f3===b?'ICOA{backdoor_trigger}':T(0x1f1);}export async function handleCtf4VlaMessage(h){const U=a0d;if(!c)return U(0x18d);const j=h[U(0x1ed)](),k=j['toLowerCase']();if(a0z(U(0x1bc)+j),U(0x18d)===k||U(0x1e8)===k||U(0x1c4)===k)return g=!(0x53a+0x1e25+-0x235e),c=null,console[U(0x1e9)](),console['log'](a0m['gray']('\x20\x20Returned\x20to\x20exam.')),console['log'](),U(0x18d);if(U(0x1b9)===k||k['startsWith'](U(0x1d4)))return await async function(x,z){const V=U,A=(process.env.ICOA_SERVER_URL?.[V(0x1c1)](/\/+$/,'')||V(0x1de))+V(0x1fa)+x+V(0x1f4);console[V(0x1e9)]();const {fetchWithCountdown:B}=await import(V(0x1da));try{const C={};C[V(0x212)]=V(0x1b2);const D={};D[V(0x202)]=z??null;const E=fetch(A,{'method':V(0x216),'headers':C,'body':JSON[V(0x190)](D),'signal':AbortSignal[V(0x1a0)](0xdd60+-0x4531*-0x3+0x137c3*-0x1)}),F=await B(E);if(!F['ok']){const M=await F[V(0x1d8)]()[V(0x1ce)](()=>'');return void console[V(0x1e9)](a0m[V(0x1ca)](V(0x1d1)+F['status']+V(0x200)+M[V(0x1f0)](-0x5c*0x2c+-0x2*-0xfbd+-0xfaa,-0x1c96+0x1609+0x705*0x1)));}const G=await F[V(0x207)]();if(!G['success']||!G[V(0x1fe)]?.[V(0x1bb)])return void console['log'](a0m['yellow'](V(0x19f)));const H=process.env.TMPDIR||V(0x1d5),I=a0x(H,V(0x191)+x+'-'+Date[V(0x1a5)]()+V(0x1b5)),{writeFileSync:J}=await import(V(0x18f));J(I,Buffer[V(0x193)](G[V(0x1fe)]['mp4_b64'],V(0x18e))),console['log'](a0m[V(0x1ba)](V(0x1e7))+a0m[V(0x192)]('Rendered.')),G['data']['description']&&console[V(0x1e9)](a0m[V(0x192)](V(0x1a8))+a0m[V(0x1ff)](G['data'][V(0x1df)]));const K='darwin'===process['platform']?V(0x1cc):'win32'===process[V(0x211)]?V(0x1ea):V(0x1e2),L={};L['stdio']=V(0x21c),L[V(0x20d)]=!(0x242b+-0x20c*0x3+-0x1*0x1e07),K?(a0y(K,[I],L)['unref'](),console[V(0x1e9)](a0m[V(0x192)](V(0x21b)))):console['log'](a0m['gray']('\x20\x20Open\x20the\x20file\x20above\x20in\x20your\x20video\x20player.'));}catch(N){const O=N instanceof Error?N['message']:String(N);console[V(0x1e9)](a0m[V(0x1ca)](V(0x215)+O));}}(c['qNum']),U(0x20c);if(U(0x1a4)===k){const x=c[U(0x1d7)][U(0x19b)]||U(0x208),z=u(x,c[U(0x1ef)]);return c[U(0x1dd)]=!(0x66*-0x29+0x17e*-0x11+0x29b4),console[U(0x1e9)](),console[U(0x1e9)](a0m[U(0x192)](U(0x1a2))+a0m[U(0x1ff)]('\x22'+x+'\x22')),console[U(0x1e9)](a0m[U(0x192)](U(0x1a6))+a0m['white'](z['description'])),console[U(0x1e9)](),U(0x20c);}const q=j[U(0x1cb)](/^probe\s+["']?(.+?)["']?\s*$/i);if(q){c['probesUsed']+=0x1017*0x2+-0x2a5*0x5+-0x12f4;const A=u(q[0x9e5+0x721*-0x3+-0x147*-0x9],c[U(0x1ef)]);if(console[U(0x1e9)](),console['log'](a0m[U(0x192)](U(0x1e0))+a0m[U(0x20a)]('ICOA-VLA\x20action:\x20')+a0m[U(0x1ff)](A[U(0x1df)])),A[U(0x1bd)]){const B=p(c[U(0x1ef)]);console['log'](),console['log'](a0m[U(0x1f2)][U(0x1ba)]('\x20\x20✓\x20Win\x20condition\x20met!\x20\x20Flag:\x20')+a0m[U(0x1f2)][U(0x1ca)](B)),console['log'](a0m['gray']('\x20\x20Type\x20')+a0m[U(0x1f2)][U(0x1ba)](U(0x1a1)+B)+a0m[U(0x192)](U(0x206)));}else console['log'](a0m[U(0x192)]('\x20\x20(no\x20win\x20yet\x20—\x20keep\x20iterating)'));return console[U(0x1e9)](),U(0x20c);}const v=j[U(0x1cb)](/^image\s+(.+)$/i);if(v){const C=function(D,E){const W=U,F={};F[W(0x1be)]=0.95,F[W(0x196)]=[-0x4*-0x27f+0xe4f*-0x1+0x171*0x3+0.31,-0x3*0xc3b+-0x1b06+0x1*0x3fb7+0.12,0x118f+0x2*-0x62f+0x531*-0x1+0.45],F['flagCondition']=!(-0x1523+0x1c2a+0x1d*-0x3e),F[W(0x1df)]=W(0x1b3);if(!a0v(D))return F;const G=a0q(D)[W(0x1f9)],H={};H[W(0x1be)]=0.9,H[W(0x196)]=[-(0x1171*0x2+0x2291+-0x4573+0.28),-0x60d+-0x1b3e+0x1*0x214b+0.12,-0xa5e+0x717+0x347+0.45],H[W(0x1bd)]=!(0x25bc+0x202+-0x27be),H[W(0x1df)]=W(0x1fc);const I={};return I['gripper']=0.95,I[W(0x196)]=[-0x369+0x1*-0x124d+0x15b6+0.31,-0x3d1*-0x3+-0x1d9c+0x1*0x1229+0.12,-0x48c+0x421+0x6b*0x1+0.45],I['flagCondition']=!(0x25f*-0x2+0x305*0x3+-0x450),I[W(0x1df)]='image\x20accepted\x20but\x20no\x20action\x20drift\x20detected',-0xad*0x17+0x2c5*-0x2+0x153f===E&&G>0xc71+0x1e81*0x1+-0x7ca*0x5?H:I;}(a0w(v[0x19ac+0x16ca*-0x1+-0x2e1]['trim']()),c[U(0x1ef)]);if(console[U(0x1e9)](),console[U(0x1e9)](a0m[U(0x192)](U(0x19d))),console[U(0x1e9)](a0m[U(0x192)](U(0x1e0))+a0m[U(0x20a)](U(0x20b))+a0m[U(0x1ff)](C[U(0x1df)])),C[U(0x1bd)]){const D=p(c[U(0x1ef)]);console[U(0x1e9)](),console[U(0x1e9)](a0m['bold'][U(0x1ba)]('\x20\x20✓\x20Win\x20condition\x20met!\x20\x20Flag:\x20')+a0m[U(0x1f2)][U(0x1ca)](D));}return console['log'](),U(0x20c);}const w=j['match'](/^submit\s+(.+)/i);if(w){let E=w[-0x15ae+0x1c70+-0x6c1]['trim']();if(/^submit\s+/i['test'](E)&&(E=E[U(0x1c1)](/^submit\s+/i,'')[U(0x1ed)]()),E=E[U(0x1c1)](/^["'`]+|["'`]+$/g,'')[U(0x1ed)](),/^[A-Da-d]$/[U(0x1f8)](E))return console[U(0x1e9)](),console[U(0x1e9)](a0m[U(0x1ca)](U(0x1b4)+E+U(0x1b1))),console[U(0x1e9)](a0m[U(0x192)](U(0x1bf))+a0m[U(0x1ba)](U(0x210))),console['log'](),U(0x20c);const F=a0A();if(!F)return U(0x18d);const G=F[U(0x1b6)][c[U(0x1ef)]];return F[U(0x195)]||(F[U(0x195)]=[]),F['interactions']['push']({'ts':new Date()[U(0x18b)](),'q':c[U(0x1ef)],'type':G?U(0x1c3):'answer_submitted','input':E,'result':U(0x203)}),F[U(0x1b6)][c['qNum']]=E,F[U(0x1c7)]=c['qNum']+(0x1*0x1573+-0x24b7+0x1*0xf45)<=-0xa74+0x1bb4+-0x1113?c[U(0x1ef)]+(-0x1c4+0x155c+-0x1397):c[U(0x1ef)],a0B(F),console['log'](),G?console['log'](a0m[U(0x1ba)](U(0x19c)+c[U(0x1ef)]+U(0x205))+a0m['yellow'](E)):console[U(0x1e9)](a0m[U(0x1ba)][U(0x1f2)](U(0x198)+c['qNum']+U(0x19a)+E)),console[U(0x1e9)](a0m[U(0x192)]('\x20\x20(Correctness\x20shown\x20after\x20final\x20exam\x20submit.)')),console[U(0x1e9)](),U(0x20c);}return console['log'](),console[U(0x1e9)](a0m[U(0x192)]('\x20\x20Try\x20one\x20of:\x20')+a0m['white']('baseline\x20/\x20probe\x20\x22...\x22\x20/\x20image\x20<path>\x20/\x20hint\x20a/b/c\x20/\x20submit\x20ICOA{...}\x20/\x20exit')),console['log'](),'continue';}export function registerCtf4VlaCommand(b){const X=a0d;b[X(0x189)]('ctf4eai')[X(0x1c0)](X(0x1f3))[X(0x1df)](X(0x1ab))[X(0x202)](()=>{const d=a0A();if(!d)return void a0C('No\x20exam\x20in\x20progress.\x20Run\x20`exam\x20<token>`\x20first.');const f=d['_lastQ']||-0x96c+-0x1d87*-0x1+-0x13f2;enterCtf4Vla(f>=0x235f*0x1+0x6d1+-0x7*0x601&&f<=-0xe4b*-0x2+0x6a3+-0x230c?f:0x1*-0xfca+-0x1aeb+0x2ade);});}
|
package/dist/commands/duck.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{spawnSync as e}from"node:child_process";import{copyFileSync as o,existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as s}from"node:fs";import{homedir as a}from"node:os";import{join as l}from"node:path";import chalk from"chalk";import{getConfig as c}from"../lib/config.js";import{runInteractive as i}from"../lib/interactive-spawn.js";import{lazyTarball as u}from"../lib/lazy-assets.js";import{contestStart as d,contestSubmit as g,duckBoard as p}from"../lib/learn-contest.js";import{listLearnSessions as m}from"../lib/learn-state.js";import{logCommand as h}from"../lib/logger.js";import{mujocoPaths as y,probeMujoco as k}from"../lib/mujoco-setup.js";import{openFile as f}from"../lib/open-file.js";import{makeReplAsker as b}from"../lib/repl-asker.js";import{colorMode as $,playFrames as w,videoSize as v}from"../lib/term-video.js";import{ARENA_VI_FLAGS as x}from"../lib/vi-flags.js";const _=()=>(c().language||"en").toLowerCase().startsWith("zh"),S=(e,o)=>_()?e:o,C=l(a(),".icoa","duck"),T=l(C,"control.py"),j=l(C,"state.json"),N=l(C,"last.png"),A=l(C,"plan.txt"),D=l(C,"sandbox.bin"),M={edit:"edit",e:"edit",vi:"edit",code:"edit",syntax:"syntax",api:"syntax",doc:"syntax",docs:"syntax",run:"run",r:"run",play:"run",sim:"run",go:"run",replay:"replay",show:"replay",picture:"replay",open:"replay",submit:"submit",s:"submit",judge:"submit",ac:"submit",status:"status",st:"status",progress:"status",scenarios:"scenarios",scenario:"scenarios",list:"scenarios",checkpoints:"scenarios",board:"board",rank:"board",ranking:"board",leaderboard:"board",top:"board",walk:"move",turn:"move",side:"move",stop:"move",crouch:"move",bow:"move",nod:"move",look:"move",undo:"undo",u:"undo",oops:"undo",plan:"plan",moves:"plan",steps:"plan",clear:"clear",reset:"clear",new:"clear",save:"save",keep:"save",write:"save",use:"use",arena:"use",map:"use",help:"help","?":"help",h:"help",back:"back",quit:"back",q:"back",exit:"back",menu:"menu"};export function normalizeDuckVerb(e){const o=e.trim().replace(/^\//,"").split(/\s+/).filter(Boolean);return 0===o.length?{verb:"unknown",args:[]}:{verb:M[o[0].toLowerCase()]??"unknown",args:o.slice(1)}}export function pickCheckpoint(e,o){if(!o)return null;const t=o.toLowerCase(),n=e.find(e=>e.scenario===t);if(n)return n;const r=/^([cr])?(\d+)$/.exec(t);if(!r)return null;const s=Number(r[2]);return"r"===r[1]?e.find(e=>e.scenario?.startsWith(`r${s}_`))??null:e.find(e=>e.scenario?.startsWith(`c${s}_`))??e.find(e=>e.card===s)??null}function B(o,t,n,r=18e4){const s=e(o,[l(t,"duck_cli.py"),...n],{encoding:"utf-8",timeout:r,env:{...process.env,PYTHONDONTWRITEBYTECODE:"1",OMP_NUM_THREADS:"1",MUJOCO_GL:"disable"}}),a=String(s.stdout??"").trim().split("\n").pop()||"";try{return JSON.parse(a)}catch{return{error:"engine",message:String(s.stderr??"").trim().split("\n").slice(-3).join(" ")||`exit ${s.status}`}}}function E(e){n(C,{recursive:!0}),s(j,JSON.stringify(e,null,1))}const O=e=>e.filter(e=>!e.race),z=e=>e.filter(e=>e.race);function F(e,o){return O(e).find(e=>!o.ac.includes(e.card))??null}function J(){try{return m().find(e=>"mduck-48"===e.curriculumId)?.token??null}catch{return null}}const L=e=>_()&&e.title_zh?e.title_zh:e.title,R=e=>e.race?`R${e.slot} · ${L(e)}`:`C${e.slot+3*(e.phase-1)} · ${S("卡","card")} ${e.card} · ${L(e)}`;function W(e){f(e)?console.log(chalk.gray(S(" 正在打开图片…"," opening the picture…"))):console.log(chalk.gray(S(` 图在这里,用文件浏览器打开:${e}`,` The picture is here — open it from your file browser: ${e}`)))}function Y(e,o,t){const n=F(e,o);var r;console.log(chalk.gray(n?S(" 当前检查点:"," Checkpoint: ")+R(n)+chalk.gray(` — ${r=n,_()&&r.pass_zh?r.pass_zh:r.pass}`):S(" 12/12 全部 AC"," 12/12 AC"))),t||console.log(chalk.gray(S(" 🦆 本机没有仿真 — "," 🦆 No sim on this machine — ")+chalk.bold.green("mujoco setup")+S(" 装上后 run 才出图;submit 照样能交,判分机替你跑。"," to run here; submit still works, the judge runs it for you.")));const s=J();console.log(chalk.gray(s?S(` ☁ submit 走服务端判分 · token ${s.slice(0,2)}••••••${s.slice(-2)}`,` ☁ submit is judged on the server · token ${s.slice(0,2)}••••••${s.slice(-2)}`):S(" (没有 mduck-48 token:run 可用,submit 不可用)"," (no mduck-48 token on this machine: run works, submit does not)"))),console.log(chalk.gray(S(" 鸭子命令 walk / turn / nod…(help 看全部)· edit · run [c4] · replay · submit · board · status · back(回上一层)· menu"," duck commands walk / turn / nod… (help lists them) · edit · run [c4] · replay · submit · board · status · back (one level up) · menu")))}function q(e,o){console.log(chalk.bold.white(S(" Duck ABC · mduck-48"," Duck ABC · mduck-48")));const t=F(e,o);for(const n of[...O(e),...z(e)]){n.race&&n===z(e)[0]&&console.log(chalk.bold.white(S(" 赛日(不计入 12 关)"," Race day (not counted in the 12)")));const r=o.ac.includes(n.card),s=o.attempts[String(n.card)]??[],a=!r&&s.length?chalk.gray(S(` (跑了 ${s.length} 次)`,` (${s.length} runs)`)):"",l=n===t?chalk.cyan(S(" ← 当前"," ← now")):"";console.log(` ${r?"✅":"⬜"} ${chalk.white(R(n))}${a}${l}`)}}function I(e){const o=e.line;return"syntax"===e.error?(console.log(chalk.yellow(S(" ✗ 语法不对"," ✗ Syntax error")+(o?S(`,第 ${o} 行:`,`, line ${o}:`):":"))+chalk.yellow(` ${String(e.message??"")}`)),e.text&&console.log(chalk.yellow(` ${String(e.text)}`)),void console.log(chalk.gray(S(" ▸ edit 改完再 run"," ▸ edit, then run again")))):"control"===e.error?(console.log(chalk.yellow(S(" ✗ control() 返回的东西套件不认:"," ✗ control() returned something the kit does not accept:"))),console.log(chalk.yellow(` ${String(e.message??"")}`)),void console.log(chalk.gray(S(" ▸ syntax 看每个字段 ▸ edit"," ▸ syntax lists every field ▸ edit")))):"runtime"===e.error?(console.log(chalk.yellow(S(" ✗ control.py 跑到一半出错"," ✗ control.py crashed")+(o?S(`(第 ${o} 行)`,` (line ${o})`):"")+":")),console.log(chalk.yellow(` ${String(e.message??"")}`)),void console.log(chalk.gray(S(" ▸ edit 改一改再 run"," ▸ edit, then run again")))):void console.log(chalk.yellow(S(" 引擎出错:"," Engine error: ")+String(e.message??e.error??"")))}const U=()=>{try{return r(A,"utf-8").split("\n").map(e=>e.trim()).filter(Boolean)}catch{return[]}},G=(e,o=A)=>{n(C,{recursive:!0}),s(o,e.length?`${e.join("\n")}\n`:"")};async function P(e,o,t,n,s){const a=process.stdout.columns??80,l=$(process.env,a,Boolean(process.stdout.isTTY)),{w:c,h:i}="none"===l?{w:32,h:18}:v(a),u=`${A}.try`;G(t,u);const d=["sandbox","--plan",u,"--out",D,"--from",String(n),"--size",`${c}x${i}`];s&&d.push("--scenario",s);const g=B(e,o,d,12e4);if(!0!==g.ok)return g;const p=!1===g.video?"none":l,m=r(D);return await w(new Uint8Array(m.buffer,m.byteOffset,m.length),g,p,e=>{return function(e,o){const[t,n,r,s,a]=e;return chalk.gray(` t ${t.toFixed(1)} s · x ${n.toFixed(2)} y ${r.toFixed(2)} m · ${S("朝向","heading")} ${s}° · `)+(a?chalk.red(S("摔倒了","fallen")):chalk.white(o))}(g.hud[e],(o=g.hud[e][0],g.steps.find(e=>o>=e.t0&&o<e.t1)?.text??g.steps[g.steps.length-1]?.text??""));var o}),!1===g.video?console.log(chalk.gray(S(" (这台电脑的 MuJoCo 画不出画面 —— 仿真照常跑,只显示文字。告诉老师:需要 EGL / OSMesa。)"," (MuJoCo cannot draw on this computer — the sim still runs, text only. Tell your teacher: needs EGL / OSMesa.)"))):"none"===l&&process.stdout.isTTY&&console.log(chalk.gray(S(" (窗口太窄或终端不是 UTF-8,只显示文字。拉宽到 60 列以上就有画面。)"," (window too narrow or terminal not UTF-8 — text only. Widen past 60 columns for the picture.)"))),g}function H(e){if("plan"===e.error)return console.log(chalk.yellow(` ✗ ${_()&&e.message_zh?e.message_zh:String(e.message??"")}`)),void console.log(chalk.gray(S(" ▸ 敲 help 看所有鸭子命令和例子"," ▸ `help` lists every duck command with an example")));I(e)}function V(e){const o=e.end;console.log((null!=o.fallen_at?chalk.red(S(` ❌ 在 ${o.fallen_at.toFixed(1)} 秒摔倒`,` ❌ fell at ${o.fallen_at.toFixed(1)} s`)):chalk.green(S(" ✅ 站着"," ✅ still standing")))+chalk.white(S(` · 位置 (${o.x}, ${o.y}) m · 朝向 ${o.heading}° · 计划 ${e.steps.length} 步 ${o.t} 秒`,` · at (${o.x}, ${o.y}) m · heading ${o.heading}° · plan: ${e.steps.length} step${1===e.steps.length?"":"s"}, ${o.t} s`))),console.log(chalk.gray(null!=o.fallen_at?S(" ▸ undo 撤掉最后一步再试 · plan 看全部命令"," ▸ undo takes back the last step · plan lists every command"):S(" ▸ 再敲一条命令接着走 · undo 撤一步 · replay 从头看 · save 存成 control.py"," ▸ type the next command · undo · replay from the start · save it as control.py")))}function K(){console.log(chalk.bold.white(S(" 🦆 鸭子命令(敲一条,鸭子就在这里动一段)"," 🦆 Duck commands (each one moves the duck, right here)")));const e=[["walk 0.3 2","前进 0.3 m/s 走 2 秒(负数后退,最快 0.4)","forward 0.3 m/s for 2 s (negative = back, max 0.4)"],["turn left 90","原地左转 90°(right 右转,最多 180)","turn left 90° on the spot (right too, max 180)"],["side left 0.15 2","横着走","sidestep"],["stop 1","站 1 秒","stand still 1 s"],["crouch 2","蹲 2 秒","crouch 2 s"],["bow 2","鞠躬两次","bow twice"],["nod 3","点头三下","nod three times"],["look left 45","转头看左边","turn the head left"]];for(const[o,t,n]of e)console.log(` ${chalk.green(o.padEnd(18))} ${chalk.gray(S(t,n))}`);console.log(chalk.gray(S(" undo 撤一步 · plan 看计划 · replay 从头放 · clear 清空 · use r3 换到任务桌 · save 存成 control.py"," undo · plan · replay (from the start) · clear · use r3 (mission table) · save (as control.py)")))}const Q=new Set(["c7_point","c8_wall","c9_push","r2_wall","r3_final"]),X=(e,o="")=>null==e?"—":(Number.isInteger(e)?String(e):e.toFixed(3))+o;async function Z(e,o,t={}){const n=o.order??(o.scenario&&Q.has(o.scenario)?"asc":"desc"),r=await p(e,o.race?`duck-r${o.slot}`:`duck-c${o.card}`,{order:n,limit:10});if(!r.ok||!r.data)return void(t.ticker||console.log(chalk.gray(S(" 榜单暂时拿不到。"," The board is not reachable right now."))));const s=r.data,a=o.unit??(e=>"c5_turn"===e.scenario?"°":e.race&&"r1_sprint"!==e.scenario?"s":/_(sprint|walk|point|wall|push)$/.test(e.scenario??"")?"m":"")(o);if(t.ticker){const e=s.board[0],t=s.mine;if(!t)return;const n=e&&!e.me?S(` · 榜首 ${e.name} ${X(e.value,a)}`,` · leader ${e.name} ${X(e.value,a)}`):"",r=Math.max(s.entrants,t.rank);return void console.log(chalk.gray(S(` 🏅 ${L(o)} 榜:你第 ${t.rank} / ${r} · ${X(t.value,a)}`,` 🏅 ${L(o)} board: you are #${t.rank} of ${r} · ${X(t.value,a)}`)+n+S(" ▸ board 看全榜"," ▸ board for the full list")))}console.log(chalk.bold.white(` 🏆 ${R(o)}`)+chalk.gray(S(` · ${s.entrants} 人上榜 · ${"asc"===n?"越小越好":"越大越好"}`,` · ${s.entrants} on the board · ${"asc"===n?"lower is better":"higher is better"}`))),0===s.board.length&&console.log(chalk.gray(S(" 还没有人上榜 —— 第一个 AC 的就是榜首。"," Nobody yet — the first AC takes the top spot.")));for(const e of s.board){const o=` ${1===e.rank?"🥇":2===e.rank?"🥈":3===e.rank?"🥉":" "} ${String(e.rank).padStart(2)} ${e.name.padEnd(14)} ${X(e.value,a).padStart(9)} ${chalk.gray(S(`${e.submits} 次`,`${e.submits} submits`))}`;console.log(e.me?chalk.cyan(o)+chalk.cyan(S(" ← 你"," ← you")):chalk.white(o))}s.mine&&!s.board.some(e=>e.me)&&console.log(chalk.cyan(S(` 你:第 ${s.mine.rank} · ${X(s.mine.value,a)} · ${s.mine.submits} 次`,` you: #${s.mine.rank} · ${X(s.mine.value,a)} · ${s.mine.submits} submits`))),s.mine||console.log(chalk.gray(S(" 你还没交过这一关 —— submit 之后就上榜。"," You have not submitted this one yet — submit and you are on it.")))}export async function runDuck(e=[]){h(["duck",...e].join(" "));const c=Number((e.find(e=>e.startsWith("from-card:"))??"").slice(10))||0;e=e.filter(e=>!e.startsWith("from-card:")),console.log(chalk.gray(S(" 🦆 正在检查引擎版本…"," 🦆 checking the engine…")));const p=await async function(){const e=process.env.ICOA_DUCK_ENGINE_DIR;if(e&&t(l(e,"duck_cli.py")))return e;const o=await u("duck-engine.tar.gz","duck-engine",6e4,{revalidate:!0});return o&&t(l(o,"duck_cli.py"))?o:null}();if(!p)return console.log(chalk.yellow(S(" 机器人引擎还没到本机(需要联网拉一次,约 11 MB)。"," The robot engine is not on this machine yet (one online fetch, ~11 MB)."))),console.log(chalk.gray(S(" 联网后再敲 duck;联不上找组织者。"," Try `duck` again when online; ask the organiser if it keeps failing."))),"back";const m=k().ok,f=y(a()).python,$=(()=>{try{return JSON.parse(r(l(p,"checkpoints.json"),"utf-8"))}catch{return null}})();if(!Array.isArray($))return console.log(chalk.yellow(S(" 引擎包不完整(没有 checkpoints.json)。"," The engine package is incomplete (no checkpoints.json)."))),"back";const w=$,v=function(){try{const e=JSON.parse(r(j,"utf-8"));return{ac:Array.isArray(e.ac)?e.ac:[],attempts:e.attempts??{},demo:!0===e.demo,arena:"string"==typeof e.arena?e.arena:void 0,lastSandbox:!0===e.lastSandbox}}catch{return{ac:[],attempts:{}}}}();if(n(C,{recursive:!0}),!t(T)){const e=l(p,"control_template.py");if(m){const e=B(f,p,["template"]);"string"==typeof e.path&&t(e.path)&&o(e.path,T)}t(T)||s(T,t(e)?r(e,"utf-8"):'from duckkit import dist, heading_to, wrap_angle\n\n\ndef control(t, sense):\n return None # None = stand still. Try {"vx": 0.2}.\n'),console.log(chalk.gray(S(` (已把模板 control.py 放到 ${T})`,` (template control.py placed at ${T})`)))}console.log(),console.log(chalk.bold.cyan(S("🦆 鸭子仿真台","🦆 Duck sim bench"))+chalk.gray(S(" — 在这里改 control.py、本机跑仿真看图、提交检查点。 ↩ back 回上一层 · menu 回首页"," — edit control.py, run the sim here and look at the picture, submit checkpoints. ↩ back · menu"))),Y(w,v,m),m&&!U().length&&console.log(chalk.cyan(S(" 🆕 先敲一句 walk 0.3 2 —— 鸭子就在这个终端里走给你看。help 看全部鸭子命令。"," 🆕 Type walk 0.3 2 — the duck walks right here in this terminal. `help` lists the duck commands.")));const D=l(p,"demo","r3_final.png");!v.demo&&t(D)&&(v.demo=!0,E(v),console.log(chalk.cyan(S(" 🎯 这是赛日的任务桌:六个任务,60 s,满分 82 —— 参考解走出 74 分。随时 `run r3` 自己试。"," 🎯 This is the race-day table: six missions, 60 s, 82 max — the reference scores 74. `run r3` to try it any time."))),W(D));let M=c?w.find(e=>e.card===c)??null:null;const L=b(),Q=L.ask;let X=0;try{for(;;){const e=await Q(chalk.bold.cyan("icoa duck> "));if(null===e)return"back";if(!e.trim())continue;const{verb:o,args:n}=normalizeDuckVerb(e);switch("unknown"!==o&&(X=0),o){case"back":return"back";case"menu":return"menu";case"help":K(),Y(w,v,m);break;case"status":q(w,v);break;case"scenarios":for(const e of[...O(w),...z(w)])e.race&&e===z(w)[0]&&console.log(chalk.bold.white(S(" 赛日 —— 私有种子在判分机,本机 run 用练习种子"," Race day — private seeds live on the judge; local run uses practice seeds"))),console.log(` ${v.ac.includes(e.card)?"✅":"⬜"} ${chalk.white(`run ${e.scenario?e.scenario.split("_")[0]:"c40"}`.padEnd(9))} ${chalk.gray(R(e))}`);console.log(chalk.gray(S(" run c4 = 跑 c4_walk;不带参数 = 当前检查点。"," `run c4` runs c4_walk; bare `run` = the current checkpoint.")));break;case"board":{const e=J();if(!e){console.log(chalk.yellow(S(" 没有 mduck-48 token,看不了榜。"," No mduck-48 token on this machine — no board to show.")));break}const o=pickCheckpoint(w,n[0]);if(n[0]&&!o){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`))+chalk.gray(S(" scenarios 列出所有名字。"," `scenarios` lists the names.")));break}await Z(e,o??M??F(w,v)??w[w.length-1]);break}case"move":case"replay":{const n=U();if(!("replay"!==o||v.lastSandbox&&n.length)){if(!t(N)){console.log(chalk.gray(S(" 还没有图。先 run 一次。"," No picture yet. `run` first.")));break}W(N);break}if(!m){console.log(chalk.gray(S(" 鸭子命令要在本机仿真 — "," Duck commands run the sim on this machine — ")+chalk.bold.green("mujoco setup")+S("(~45 MB,免 sudo),装好再回来。"," (~45 MB, no sudo), then come back.")));break}const r="move"===o?[...n,e.trim().replace(/^\//,"")]:n,s="move"===o?n.length:0;h(`duck ${"move"===o?e.trim():"replay"}`),console.log(chalk.gray(S(" 🦆 仿真中…"," 🦆 simulating…")));const a=await P(f,p,r,s,v.arena);if(!0!==a.ok){H(a);break}"move"===o&&G(r),v.lastSandbox=!0,E(v),V(a);break}case"undo":{const e=U();if(!e.length){console.log(chalk.gray(S(" 计划是空的,没有可撤的。"," The plan is empty — nothing to undo.")));break}const o=e.pop();G(e),console.log(chalk.white(S(` ↩ 撤掉了「${o}」`,` ↩ took back "${o}"`))+chalk.gray(S(` · 还剩 ${e.length} 步 · replay 从头看`,` · ${e.length} step${1===e.length?"":"s"} left · replay to watch`)));break}case"plan":{const e=U();if(!e.length){console.log(chalk.gray(S(" 计划是空的。试试:walk 0.3 2"," The plan is empty. Try: walk 0.3 2")));break}console.log(chalk.bold.white(S(" 你的计划"," Your plan"))+chalk.gray(S(`(${v.arena??"空地"})`,` (${v.arena??"open floor"})`)));for(const[o,t]of e.entries())console.log(` ${chalk.gray(String(o+1).padStart(2))} ${chalk.white(t)}`);console.log(chalk.gray(S(" ▸ replay 从头看 · undo 撤最后一步 · save 存成 control.py"," ▸ replay · undo · save")));break}case"clear":{const e=U().length;G([]),v.lastSandbox=!1,E(v),console.log(chalk.white(S(` 🧹 计划清空了(原来 ${e} 步)。`,` 🧹 Plan cleared (was ${e} steps).`))+chalk.gray(S(" 鸭子回到起点。"," The duck is back at the start.")));break}case"use":{const e=(n[0]??"").toLowerCase();if(!e){console.log(chalk.white(S(` 现在在:${v.arena??"空地"}`,` Now on: ${v.arena??"the open floor"}`))+chalk.gray(S(" · use r3 = 任务桌 · use c8 = 绕墙 · use free = 空地"," · use r3 = mission table · use c8 = wall · use free = open floor")));break}if(["free","floor","open","sandbox"].includes(e))v.arena=void 0;else{const o=pickCheckpoint(w,e);if(!o?.scenario){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`))+chalk.gray(S(" scenarios 列出所有名字;use free 回空地。"," `scenarios` lists the names; `use free` = open floor.")));break}v.arena=o.scenario}v.lastSandbox=!1,E(v),console.log(chalk.white(S(` 🗺 换到 ${v.arena??"空地"}。`,` 🗺 Now on ${v.arena??"the open floor"}.`))+chalk.gray(S(" 计划保留着 —— replay 在新场地上看一遍。"," The plan is kept — `replay` to watch it here.")));break}case"save":{const e=U();if(!e.length){console.log(chalk.gray(S(" 计划是空的,先敲几条命令(walk 0.3 2)。"," The plan is empty — type a few commands first (walk 0.3 2).")));break}if(!m){console.log(chalk.gray(S(" save 需要本机引擎 — mujoco setup。"," save needs the local engine — mujoco setup.")));break}const o=`${A}.try`;G(e,o);const n=B(f,p,["plansrc","--plan",o]);if(!0!==n.ok||"string"!=typeof n.source){H(n);break}const a=t(T)?r(T,"utf-8"):"";a&&a!==n.source&&s(`${T}.bak`,a),s(T,n.source),h("duck save"),console.log(chalk.green(S(` 💾 存好了:control.py = 你的 ${e.length} 条命令`,` 💾 Saved: control.py = your ${e.length} commands`))+chalk.gray(a&&a!==n.source?S("(旧文件在 control.py.bak)"," (old file kept as control.py.bak)"):"")),console.log(chalk.gray(S(" ▸ edit 看看它变成了什么代码 · run r3 在任务桌上打分 · submit 提交"," ▸ edit to see the code it became · run r3 to score it on the mission table · submit")));break}case"syntax":{const e=(()=>{try{return _()&&m?String(B(f,p,["cheatsheet","--lang","zh"]).text??""):r(l(p,"syntax.txt"),"utf-8")}catch{return""}})();console.log(chalk.gray(e||S(" (速查表不在引擎包里)"," (no syntax sheet in the engine package)")));break}case"edit":console.log(chalk.gray(S(" vi 三键: i 进入编辑 · Esc 退出编辑 · :wq 存盘离开 · :q! 放弃"," vi survival: i = edit · Esc = stop editing · :wq = save and leave · :q! = discard"))),await i("vi",[...x,T]);break;case"run":{const e=pickCheckpoint(w,n[0]);if(n[0]&&!e){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`))+chalk.gray(S(" scenarios 列出所有名字。"," `scenarios` lists the names.")));break}const o=e??M??F(w,v);if(!o){console.log(chalk.green(S(" 12 个检查点全部 AC。"," All 12 checkpoints AC.")));break}if(e&&(M=e),!o.scenario){console.log(chalk.gray(S(" 这一关是打印题,不在仿真里:写好程序直接 submit。"," This checkpoint is a print-a-number task, not a sim run: write the program and `submit`.")));break}if(!m){console.log(chalk.gray(S(" 本机没有仿真 — "," No sim on this machine — ")+chalk.bold.green("mujoco setup")+S("(~45 MB,免 sudo)。submit 照样能交。"," (~45 MB, no sudo). `submit` still works.")));break}process.stdout.write(chalk.gray(S(` ${R(o)} … `,` ${R(o)} … `)));const t=B(f,p,["run","--file",T,"--scenario",o.scenario,"--png",N]);if(console.log(),v.lastSandbox=!1,!0!==t.ok){I(t);break}const r=t.prints??[];for(const e of r.slice(0,12))console.log(chalk.white(` ${e}`));Number(t.prints_total)>12&&console.log(chalk.gray(S(` … 共 ${t.prints_total} 行输出`,` … ${t.prints_total} lines printed`)));const s=Boolean(t.pass);console.log((s?chalk.green(" ✓ "):chalk.yellow(" ✗ "))+chalk.white(String(t.detail??""))+chalk.gray(null!=t.fallen_at?S(` · 摔倒于 ${t.fallen_at} s`,` · fell at ${t.fallen_at} s`):"")+chalk.gray(` (${t.seconds} s ${S("仿真","sim")}, ${t.time_ms} ms)`));const a=v.attempts[String(o.card)]??[];a.push(s),v.attempts[String(o.card)]=a,E(v),console.log(chalk.gray(s?S(" ▸ submit 提交检查点 ▸ replay 再看图 ▸ edit 继续改"," ▸ submit ▸ replay the picture ▸ edit to keep improving"):S(" ▸ replay 看图找原因 ▸ edit 改一改再 run"," ▸ replay to see what happened ▸ edit, then run"))),"string"==typeof t.png&&process.stdout.isTTY&&W(t.png);break}case"submit":{const e=M??F(w,v);if(!e){console.log(chalk.green(S(" 全部 AC。"," All AC.")));break}if(m){const e=B(f,p,["syntax","--file",T]);if(!1===e.ok){I(e);break}}const o=J();if(!o){console.log(chalk.yellow(S(" 这台机器上没有 mduck-48 token,没法交。"," No mduck-48 token on this machine — nothing to submit with."))),console.log(chalk.gray(S(" ▸ learn 粘 token 后再来。"," ▸ paste your token in `learn`, then come back.")));break}const t=await d(o,e.phase,e.slot);if(!t.ok||!t.data){console.log(chalk.yellow(S(" 服务端没开门:"," Server did not open the checkpoint: ")+String(t.message??t.code??"")));break}const n=t.data.problems[0]?.id??(e.race?`duck-r${e.slot}`:`duck-c${e.card}`);console.log(chalk.gray(S(" ⚖ 判分中(服务端 · "," ⚖ judging (server · ")+R(e)+S(")… 约 5–10 秒",")… 5–10 s")));const s=await g(o,e.phase,n,r(T,"utf-8"),e.slot);if(!s.ok||!s.data){if("race_throttle"===s.code){const e=Math.max(1,Math.ceil(Number(s.wait_s??0)));console.log(chalk.yellow(S(` ⏱ 赛日题每 3 分钟判一次 —— 再等 ${e} 秒。本机 run 不限次,先跑几遍再交。`,` ⏱ Race entries are judged once every 3 minutes — ${e} s to go. Local \`run\` is unlimited; try a few first.`)));break}console.log(chalk.yellow(S(" 判分没回来:"," No verdict came back: ")+String(s.message??s.code??"")));break}const a=s.data;for(const e of(a.report??[]).slice(0,3))console.log(chalk.gray(` ${e}`));if(a.note&&console.log(chalk.gray(` ${a.note}`)),"AC"===a.verdict||!0===a.already_ac){v.ac.includes(e.card)||v.ac.push(e.card),E(v);const t=v.ac.filter(e=>e<=48).length;console.log(chalk.green(` ✅ AC · ${t}/12`+(1===t?S(" 🎉 第一个检查点!"," 🎉 first checkpoint!"):""))),await Z(o,e,{ticker:!0});const n=O(w).find(o=>!v.ac.includes(o.card)&&o.card>e.card)??null,r=O(w).find(o=>!v.ac.includes(o.card)&&o.card<e.card)??null;M=null,console.log(chalk.green(e.race?S(" ▸ board 看榜 · 想刷成绩再 edit → run → submit"," ▸ board to see the ranking · edit → run → submit to improve"):n?S(` ▸ back 回卡片,读第 ${e.card+1} 张 —— 下一个检查点在卡 ${n.card}`,` ▸ back to the cards, read card ${e.card+1} — next checkpoint is card ${n.card}`):r?S(` ▸ 前面还有没做的检查点:卡 ${r.card}`,` ▸ an earlier checkpoint is still open: card ${r.card}`):S(" 🎓 12/12 —— 鸭子听你的了。"," 🎓 12/12 — the duck does what you say."))),!e.race&&n&&r&&console.log(chalk.gray(S(` (卡 ${r.card} 的检查点也还没做)`,` (card ${r.card}'s checkpoint is still open too)`)))}else console.log(chalk.yellow(S(` ❌ ${a.verdict}。`,` ❌ ${a.verdict}.`))+chalk.gray(S(" ▸ run 本机看图 ▸ edit"," ▸ run to see the picture ▸ edit")));break}default:if(X+=1,console.log(chalk.yellow(S(` 不认识「${e.trim()}」。`,` Don't know "${e.trim()}".`))+chalk.gray(S(" 可用:walk 0.3 2 · turn left 90 · help · edit · run · submit · back"," Try: walk 0.3 2 · turn left 90 · help · edit · run · submit · back"))),X>=3)return console.log(chalk.gray(S(" 连续三次没对上 —— 回上一层。"," Three misses — going back one level."))),"back"}}}finally{L.close()}}export function registerDuckCommand(e){e.command("duck [args...]").description("Duck ABC sim bench — edit control.py, run the biped in MuJoCo on this machine, submit checkpoints").action(async e=>{await runDuck(e??[])})}
|
|
1
|
+
import{spawnSync as e}from"node:child_process";import{copyFileSync as o,existsSync as t,mkdirSync as n,readFileSync as r,writeFileSync as s}from"node:fs";import{homedir as a}from"node:os";import{join as l}from"node:path";import chalk from"chalk";import{getConfig as c}from"../lib/config.js";import{runInteractive as i}from"../lib/interactive-spawn.js";import{lazyTarball as u}from"../lib/lazy-assets.js";import{contestStart as d,contestSubmit as p,duckBoard as g}from"../lib/learn-contest.js";import{listLearnSessions as m}from"../lib/learn-state.js";import{logCommand as h}from"../lib/logger.js";import{mujocoPaths as k,probeMujoco as y}from"../lib/mujoco-setup.js";import{openFile as b}from"../lib/open-file.js";import{makeReplAsker as f}from"../lib/repl-asker.js";import{colorMode as $,playFrames as w,videoSize as v}from"../lib/term-video.js";import{ARENA_VI_FLAGS as x}from"../lib/vi-flags.js";const _=()=>{const e=(c().language||"en").toLowerCase();return e.startsWith("zh")?"zh":e.startsWith("th")?"th":"en"},S=(e,o,t)=>{const n=_();return"zh"===n?e:"th"===n?t??o:o},C=l(a(),".icoa","duck"),j=l(C,"control.py"),T=l(C,"state.json"),A=l(C,"last.png"),N=l(C,"plan.txt"),M=l(C,"sandbox.bin"),D={edit:"edit",e:"edit",vi:"edit",code:"edit",syntax:"syntax",api:"syntax",doc:"syntax",docs:"syntax",run:"run",r:"run",play:"run",sim:"run",go:"run",replay:"replay",show:"replay",picture:"replay",open:"replay",submit:"submit",s:"submit",judge:"submit",ac:"submit",status:"status",st:"status",progress:"status",scenarios:"scenarios",scenario:"scenarios",list:"scenarios",checkpoints:"scenarios",board:"board",rank:"board",ranking:"board",leaderboard:"board",top:"board",walk:"move",turn:"move",side:"move",stop:"move",crouch:"move",bow:"move",nod:"move",look:"move",undo:"undo",u:"undo",oops:"undo",plan:"plan",moves:"plan",steps:"plan",clear:"clear",reset:"clear",new:"clear",save:"save",keep:"save",write:"save",use:"use",arena:"use",map:"use",help:"help","?":"help",h:"help",back:"back",quit:"back",q:"back",exit:"back",menu:"menu"};export function normalizeDuckVerb(e){const o=e.trim().replace(/^\//,"").split(/\s+/).filter(Boolean);return 0===o.length?{verb:"unknown",args:[]}:{verb:D[o[0].toLowerCase()]??"unknown",args:o.slice(1)}}export function pickCheckpoint(e,o){if(!o)return null;const t=o.toLowerCase(),n=e.find(e=>e.scenario===t);if(n)return n;const r=/^([cr])?(\d+)$/.exec(t);if(!r)return null;const s=Number(r[2]);return"r"===r[1]?e.find(e=>e.scenario?.startsWith(`r${s}_`))??null:e.find(e=>e.scenario?.startsWith(`c${s}_`))??e.find(e=>e.card===s)??null}function B(o,t,n,r=18e4){const s=e(o,[l(t,"duck_cli.py"),...n],{encoding:"utf-8",timeout:r,env:{...process.env,PYTHONDONTWRITEBYTECODE:"1",OMP_NUM_THREADS:"1",MUJOCO_GL:"disable"}}),a=String(s.stdout??"").trim().split("\n").pop()||"";try{return JSON.parse(a)}catch{return{error:"engine",message:String(s.stderr??"").trim().split("\n").slice(-3).join(" ")||`exit ${s.status}`}}}function E(e){n(C,{recursive:!0}),s(T,JSON.stringify(e,null,1))}const O=e=>e.filter(e=>!e.race),z=e=>e.filter(e=>e.race);function F(e,o){return O(e).find(e=>!o.ac.includes(e.card))??null}function J(){try{return m().find(e=>"mduck-48"===e.curriculumId)?.token??null}catch{return null}}const L=e=>S(e.title_zh??e.title,e.title,e.title_th),q=e=>e.race?`R${e.slot} · ${L(e)}`:`C${e.slot+3*(e.phase-1)} · ${S("卡","card","การ์ด")} ${e.card} · ${L(e)}`;function W(e){b(e)?console.log(chalk.gray(S(" 正在打开图片…"," opening the picture…"," กำลังเปิดรูป…"))):console.log(chalk.gray(S(` 图在这里,用文件浏览器打开:${e}`,` The picture is here — open it from your file browser: ${e}`,` รูปอยู่ที่นี่ — เปิดจากตัวจัดการไฟล์ของคุณ: ${e}`)))}function R(e,o,t){const n=F(e,o);var r;console.log(chalk.gray(n?S(" 当前检查点:"," Checkpoint: "," Checkpoint: ")+q(n)+chalk.gray(` — ${r=n,S(r.pass_zh??r.pass,r.pass,r.pass_th)}`):S(" 12/12 全部 AC"," 12/12 AC"," ผ่าน 12/12 ข้อ (AC)"))),t||console.log(chalk.gray(S(" 🦆 本机没有仿真 — "," 🦆 No sim on this machine — "," 🦆 เครื่องนี้ยังไม่มีตัวจำลอง — ")+chalk.bold.green("mujoco setup")+S(" 装上后 run 才出图;submit 照样能交,判分机替你跑。"," to run here; submit still works, the judge runs it for you."," เพื่อรันที่นี่ แต่ submit ยังใช้ได้ เพราะระบบตรวจจะรันให้คุณ")));const s=J();console.log(chalk.gray(s?S(` ☁ submit 走服务端判分 · token ${s.slice(0,2)}••••••${s.slice(-2)}`,` ☁ submit is judged on the server · token ${s.slice(0,2)}••••••${s.slice(-2)}`,` ☁ submit ตรวจที่เซิร์ฟเวอร์ · token ${s.slice(0,2)}••••••${s.slice(-2)}`):S(" (没有 mduck-48 token:run 可用,submit 不可用)"," (no mduck-48 token on this machine: run works, submit does not)"," (เครื่องนี้ไม่มี token ของ mduck-48: run ใช้ได้ แต่ submit ไม่ได้)"))),console.log(chalk.gray(S(" 鸭子命令 walk / turn / nod…(help 看全部)· edit · run [c4] · replay · submit · board · status · back(回上一层)· menu"," duck commands walk / turn / nod… (help lists them) · edit · run [c4] · replay · submit · board · status · back (one level up) · menu"," คำสั่งเป็ด walk / turn / nod… (help แสดงทั้งหมด) · edit · run [c4] · replay · submit · board · status · back (ถอยหนึ่งชั้น) · menu")))}function U(e,o){console.log(chalk.bold.white(S(" Duck ABC · mduck-48"," Duck ABC · mduck-48"," Duck ABC · mduck-48")));const t=F(e,o);for(const n of[...O(e),...z(e)]){n.race&&n===z(e)[0]&&console.log(chalk.bold.white(S(" 赛日(不计入 12 关)"," Race day (not counted in the 12)"," วันแข่ง (ไม่นับใน 12 ข้อ)")));const r=o.ac.includes(n.card),s=o.attempts[String(n.card)]??[],a=!r&&s.length?chalk.gray(S(` (跑了 ${s.length} 次)`,` (${s.length} runs)`,` (${s.length} รัน)`)):"",l=n===t?chalk.cyan(S(" ← 当前"," ← now"," ← ตอนนี้")):"";console.log(` ${r?"✅":"⬜"} ${chalk.white(q(n))}${a}${l}`)}}function Y(e){const o=e.line;return"syntax"===e.error?(console.log(chalk.yellow(S(" ✗ 语法不对"," ✗ Syntax error"," ✗ ไวยากรณ์ผิด")+(o?S(`,第 ${o} 行:`,`, line ${o}:`,` บรรทัด ${o}:`):":"))+chalk.yellow(` ${String(e.message??"")}`)),e.text&&console.log(chalk.yellow(` ${String(e.text)}`)),void console.log(chalk.gray(S(" ▸ edit 改完再 run"," ▸ edit, then run again"," ▸ edit แล้วรันอีกครั้ง")))):"control"===e.error?(console.log(chalk.yellow(S(" ✗ control() 返回的东西套件不认:"," ✗ control() returned something the kit does not accept:"," ✗ control() ส่งค่าที่ชุดเครื่องมือไม่รองรับ:"))),console.log(chalk.yellow(` ${String(e.message??"")}`)),void console.log(chalk.gray(S(" ▸ syntax 看每个字段 ▸ edit"," ▸ syntax lists every field ▸ edit"," ▸ syntax แสดงทุกฟิลด์ ▸ edit")))):"runtime"===e.error?(console.log(chalk.yellow(S(" ✗ control.py 跑到一半出错"," ✗ control.py crashed"," ✗ control.py พัง")+(o?S(`(第 ${o} 行)`,` (line ${o})`,` (บรรทัด ${o})`):"")+":")),console.log(chalk.yellow(` ${String(e.message??"")}`)),void console.log(chalk.gray(S(" ▸ edit 改一改再 run"," ▸ edit, then run again"," ▸ edit แล้วรันอีกครั้ง")))):void console.log(chalk.yellow(S(" 引擎出错:"," Engine error: "," ข้อผิดพลาดของเอนจิน: ")+String(e.message??e.error??"")))}const I=()=>{try{return r(N,"utf-8").split("\n").map(e=>e.trim()).filter(Boolean)}catch{return[]}},G=(e,o=N)=>{n(C,{recursive:!0}),s(o,e.length?`${e.join("\n")}\n`:"")};async function P(e,o,t,n,s){const a=process.stdout.columns??80,l=$(process.env,a,Boolean(process.stdout.isTTY)),{w:c,h:i}="none"===l?{w:32,h:18}:v(a),u=`${N}.try`;G(t,u);const d=["sandbox","--plan",u,"--out",M,"--from",String(n),"--size",`${c}x${i}`];s&&d.push("--scenario",s);const p=B(e,o,d,12e4);if(!0!==p.ok)return p;const g=!1===p.video?"none":l,m=r(M);return await w(new Uint8Array(m.buffer,m.byteOffset,m.length),p,g,e=>{return function(e,o){const[t,n,r,s,a]=e;return chalk.gray(` t ${t.toFixed(1)} s · x ${n.toFixed(2)} y ${r.toFixed(2)} m · ${S("朝向","heading","ทิศ")} ${s}° · `)+(a?chalk.red(S("摔倒了","fallen","ล้ม")):chalk.white(o))}(p.hud[e],(o=p.hud[e][0],p.steps.find(e=>o>=e.t0&&o<e.t1)?.text??p.steps[p.steps.length-1]?.text??""));var o}),!1===p.video?console.log(chalk.gray(S(" (这台电脑的 MuJoCo 画不出画面 —— 仿真照常跑,只显示文字。告诉老师:需要 EGL / OSMesa。)"," (MuJoCo cannot draw on this computer — the sim still runs, text only. Tell your teacher: needs EGL / OSMesa.)"," (MuJoCo วาดภาพบนเครื่องนี้ไม่ได้ — ตัวจำลองยังรันอยู่ แต่เห็นแค่ข้อความ บอกครูว่าต้องมี EGL / OSMesa)"))):"none"===l&&process.stdout.isTTY&&console.log(chalk.gray(S(" (窗口太窄或终端不是 UTF-8,只显示文字。拉宽到 60 列以上就有画面。)"," (window too narrow or terminal not UTF-8 — text only. Widen past 60 columns for the picture.)"," (หน้าต่างแคบไป หรือเทอร์มินัลไม่ใช่ UTF-8 — แสดงแค่ข้อความ ขยายให้กว้างเกิน 60 คอลัมน์เพื่อดูภาพ)"))),p}function H(e){if("plan"===e.error){const o=String(e.message??"");return console.log(chalk.yellow(` ✗ ${S(e.message_zh??o,o,e.message_th)}`)),void console.log(chalk.gray(S(" ▸ 敲 help 看所有鸭子命令和例子"," ▸ `help` lists every duck command with an example"," ▸ `help` แสดงคำสั่งเป็ดทั้งหมดพร้อมตัวอย่าง")))}Y(e)}function V(e){const o=e.end;console.log((null!=o.fallen_at?chalk.red(S(` ❌ 在 ${o.fallen_at.toFixed(1)} 秒摔倒`,` ❌ fell at ${o.fallen_at.toFixed(1)} s`,` ❌ ล้มที่ ${o.fallen_at.toFixed(1)} วินาที`)):chalk.green(S(" ✅ 站着"," ✅ still standing"," ✅ ยังยืนอยู่")))+chalk.white(S(` · 位置 (${o.x}, ${o.y}) m · 朝向 ${o.heading}° · 计划 ${e.steps.length} 步 ${o.t} 秒`,` · at (${o.x}, ${o.y}) m · heading ${o.heading}° · plan: ${e.steps.length} step${1===e.steps.length?"":"s"}, ${o.t} s`,` · ที่ (${o.x}, ${o.y}) m · ทิศ ${o.heading}° · แผน: ${e.steps.length} step${1===e.steps.length?"":"s"}, ${o.t} วินาที`))),console.log(chalk.gray(null!=o.fallen_at?S(" ▸ undo 撤掉最后一步再试 · plan 看全部命令"," ▸ undo takes back the last step · plan lists every command"," ▸ undo ยกเลิกขั้นตอนล่าสุด · plan แสดงทุกคำสั่ง"):S(" ▸ 再敲一条命令接着走 · undo 撤一步 · replay 从头看 · save 存成 control.py"," ▸ type the next command · undo · replay from the start · save it as control.py"," ▸ พิมพ์คำสั่งถัดไป · undo · replay ตั้งแต่ต้น · save เป็น control.py")))}function K(){console.log(chalk.bold.white(S(" 🦆 鸭子命令(敲一条,鸭子就在这里动一段)"," 🦆 Duck commands (each one moves the duck, right here)"," 🦆 คำสั่งเป็ด (แต่ละคำสั่งทำให้เป็ดขยับตรงนี้เลย)")));const e=[["walk 0.3 2","前进 0.3 m/s 走 2 秒(负数后退,最快 0.4)","forward 0.3 m/s for 2 s (negative = back, max 0.4)","เดินหน้า 0.3 m/s นาน 2 วินาที (ติดลบ = ถอยหลัง, สูงสุด 0.4)"],["turn left 90","原地左转 90°(right 右转,最多 180)","turn left 90° on the spot (right too, max 180)","หมุนซ้าย 90° อยู่กับที่ (right ก็ได้, สูงสุด 180)"],["side left 0.15 2","横着走","sidestep","เดินข้าง"],["stop 1","站 1 秒","stand still 1 s","ยืนนิ่ง 1 วินาที"],["bow 2","鞠躬两次","bow twice","โค้งสองครั้ง"],["nod 3","点头三下","nod three times","พยักหน้าสามครั้ง"],["look left 45","转头看左边","turn the head left","หันหัวไปทางซ้าย"]];for(const[o,t,n,r]of e)console.log(` ${chalk.green(o.padEnd(18))} ${chalk.gray(S(t,n,r))}`);console.log(chalk.gray(S(" undo 撤一步 · plan 看计划 · replay 从头放 · clear 清空 · use r3 换到任务桌 · save 存成 control.py"," undo · plan · replay (from the start) · clear · use r3 (mission table) · save (as control.py)"," undo · plan · replay (ตั้งแต่ต้น) · clear · use r3 (ตารางภารกิจ) · save (เป็น control.py)")))}const Q=new Set(["c7_point","c8_wall","c9_push","r2_wall","r3_final"]),X=(e,o="")=>null==e?"—":(Number.isInteger(e)?String(e):e.toFixed(3))+o;async function Z(e,o,t={}){const n=o.order??(o.scenario&&Q.has(o.scenario)?"asc":"desc"),r=await g(e,o.race?`duck-r${o.slot}`:`duck-c${o.card}`,{order:n,limit:10});if(!r.ok||!r.data)return void(t.ticker||console.log(chalk.gray(S(" 榜单暂时拿不到。"," The board is not reachable right now."," ตอนนี้เข้าถึงกระดานคะแนนไม่ได้"))));const s=r.data,a=o.unit??(e=>"c5_turn"===e.scenario?"°":e.race&&"r1_sprint"!==e.scenario?"s":/_(sprint|walk|point|wall|push)$/.test(e.scenario??"")?"m":"")(o);if(t.ticker){const e=s.board[0],t=s.mine;if(!t)return;const n=e&&!e.me?S(` · 榜首 ${e.name} ${X(e.value,a)}`,` · leader ${e.name} ${X(e.value,a)}`,` · อันดับหนึ่ง ${e.name} ${X(e.value,a)}`):"",r=Math.max(s.entrants,t.rank);return void console.log(chalk.gray(S(` 🏅 ${L(o)} 榜:你第 ${t.rank} / ${r} · ${X(t.value,a)}`,` 🏅 ${L(o)} board: you are #${t.rank} of ${r} · ${X(t.value,a)}`,` 🏅 กระดาน ${L(o)}: คุณอยู่อันดับ #${t.rank} จาก ${r} · ${X(t.value,a)}`)+n+S(" ▸ board 看全榜"," ▸ board for the full list"," ▸ board ดูรายชื่อทั้งหมด")))}console.log(chalk.bold.white(` 🏆 ${q(o)}`)+chalk.gray(S(` · ${s.entrants} 人上榜 · ${"asc"===n?"越小越好":"越大越好"}`,` · ${s.entrants} on the board · ${"asc"===n?"lower is better":"higher is better"}`,` · ${s.entrants} คนบนกระดาน · ${"asc"===n?"lower is better":"higher is better"}`))),0===s.board.length&&console.log(chalk.gray(S(" 还没有人上榜 —— 第一个 AC 的就是榜首。"," Nobody yet — the first AC takes the top spot."," ยังไม่มีใคร — AC คนแรกได้ที่หนึ่ง")));for(const e of s.board){const o=` ${1===e.rank?"🥇":2===e.rank?"🥈":3===e.rank?"🥉":" "} ${String(e.rank).padStart(2)} ${e.name.padEnd(14)} ${X(e.value,a).padStart(9)} ${chalk.gray(S(`${e.submits} 次`,`${e.submits} submits`,`submit ${e.submits} ครั้ง`))}`;console.log(e.me?chalk.cyan(o)+chalk.cyan(S(" ← 你"," ← you"," ← คุณ")):chalk.white(o))}s.mine&&!s.board.some(e=>e.me)&&console.log(chalk.cyan(S(` 你:第 ${s.mine.rank} · ${X(s.mine.value,a)} · ${s.mine.submits} 次`,` you: #${s.mine.rank} · ${X(s.mine.value,a)} · ${s.mine.submits} submits`,` คุณ: #${s.mine.rank} · ${X(s.mine.value,a)} · submit ${s.mine.submits} ครั้ง`))),s.mine||console.log(chalk.gray(S(" 你还没交过这一关 —— submit 之后就上榜。"," You have not submitted this one yet — submit and you are on it."," คุณยังไม่ได้ submit ข้อนี้ — submit แล้วจะขึ้นกระดาน")))}export async function runDuck(e=[]){h(["duck",...e].join(" "));const c=Number((e.find(e=>e.startsWith("from-card:"))??"").slice(10))||0;e=e.filter(e=>!e.startsWith("from-card:")),console.log(chalk.gray(S(" 🦆 正在检查引擎版本…"," 🦆 checking the engine…"," 🦆 กำลังตรวจเอนจิน…")));const g=await async function(){const e=process.env.ICOA_DUCK_ENGINE_DIR;if(e&&t(l(e,"duck_cli.py")))return e;const o=await u("duck-engine.tar.gz","duck-engine",6e4,{revalidate:!0});return o&&t(l(o,"duck_cli.py"))?o:null}();if(!g)return console.log(chalk.yellow(S(" 机器人引擎还没到本机(需要联网拉一次,约 11 MB)。"," The robot engine is not on this machine yet (one online fetch, ~11 MB)."," เครื่องนี้ยังไม่มีเอนจินหุ่นยนต์ (ดาวน์โหลดออนไลน์ครั้งเดียว ~11 MB)"))),console.log(chalk.gray(S(" 联网后再敲 duck;联不上找组织者。"," Try `duck` again when online; ask the organiser if it keeps failing."," ลองพิมพ์ `duck` อีกครั้งเมื่อออนไลน์ ถ้ายังไม่ได้ให้ถามผู้จัด"))),"back";const m=y().ok,b=k(a()).python,$=(()=>{try{return JSON.parse(r(l(g,"checkpoints.json"),"utf-8"))}catch{return null}})();if(!Array.isArray($))return console.log(chalk.yellow(S(" 引擎包不完整(没有 checkpoints.json)。"," The engine package is incomplete (no checkpoints.json)."," แพ็กเกจเอนจินไม่ครบ (ไม่มี checkpoints.json)"))),"back";const w=$,v=function(){try{const e=JSON.parse(r(T,"utf-8"));return{ac:Array.isArray(e.ac)?e.ac:[],attempts:e.attempts??{},demo:!0===e.demo,arena:"string"==typeof e.arena?e.arena:void 0,lastSandbox:!0===e.lastSandbox}}catch{return{ac:[],attempts:{}}}}();if(n(C,{recursive:!0}),!t(j)){const e=l(g,"control_template.py");if(m){const e=B(b,g,["template"]);"string"==typeof e.path&&t(e.path)&&o(e.path,j)}t(j)||s(j,t(e)?r(e,"utf-8"):'from duckkit import dist, heading_to, wrap_angle\n\n\ndef control(t, sense):\n return None # None = stand still. Try {"vx": 0.2}.\n'),console.log(chalk.gray(S(` (已把模板 control.py 放到 ${j})`,` (template control.py placed at ${j})`,` (วางไฟล์ control.py ต้นแบบไว้ที่ ${j})`)))}console.log(),console.log(chalk.bold.cyan(S("🦆 鸭子仿真台","🦆 Duck sim bench","🦆 ห้องทดลองจำลองเป็ด"))+chalk.gray(S(" — 在这里改 control.py、本机跑仿真看图、提交检查点。 ↩ back 回上一层 · menu 回首页"," — edit control.py, run the sim here and look at the picture, submit checkpoints. ↩ back · menu"," — แก้ control.py รันตัวจำลองที่นี่แล้วดูภาพ ส่ง checkpoint ↩ back · menu"))),R(w,v,m),m&&!I().length&&console.log(chalk.cyan(S(" 🆕 先敲一句 walk 0.3 2 —— 鸭子就在这个终端里走给你看。help 看全部鸭子命令。"," 🆕 Type walk 0.3 2 — the duck walks right here in this terminal. `help` lists the duck commands."," 🆕 พิมพ์ walk 0.3 2 — เป็ดจะเดินในเทอร์มินัลนี้เลย `help` แสดงคำสั่งเป็ด")));const M=l(g,"demo","r3_final.png");!v.demo&&t(M)&&(v.demo=!0,E(v),console.log(chalk.cyan(S(" 🎯 这是赛日的任务桌:六个任务,60 s,满分 82 —— 参考解走出 74 分。随时 `run r3` 自己试。"," 🎯 This is the race-day table: six missions, 60 s, 82 max — the reference scores 74. `run r3` to try it any time."," 🎯 นี่คือตารางวันแข่ง: หกภารกิจ 60 วินาที เต็ม 82 — คะแนนอ้างอิงคือ 74 พิมพ์ `run r3` เพื่อลองเมื่อไรก็ได้"))),W(M));let D=c?w.find(e=>e.card===c)??null:null;const L=f(),Q=L.ask;let X=0;try{for(;;){const e=await Q(chalk.bold.cyan("icoa duck> "));if(null===e)return"back";if(!e.trim())continue;const{verb:o,args:n}=normalizeDuckVerb(e);switch("unknown"!==o&&(X=0),o){case"back":return"back";case"menu":return"menu";case"help":K(),R(w,v,m);break;case"status":U(w,v);break;case"scenarios":for(const e of[...O(w),...z(w)])e.race&&e===z(w)[0]&&console.log(chalk.bold.white(S(" 赛日 —— 私有种子在判分机,本机 run 用练习种子"," Race day — private seeds live on the judge; local run uses practice seeds"," วันแข่ง — seed ลับอยู่ที่ระบบตรวจ การรันในเครื่องใช้ seed ฝึก"))),console.log(` ${v.ac.includes(e.card)?"✅":"⬜"} ${chalk.white(`run ${e.scenario?e.scenario.split("_")[0]:"c40"}`.padEnd(9))} ${chalk.gray(q(e))}`);console.log(chalk.gray(S(" run c4 = 跑 c4_walk;不带参数 = 当前检查点。"," `run c4` runs c4_walk; bare `run` = the current checkpoint."," `run c4` รัน c4_walk; `run` เฉยๆ = checkpoint ปัจจุบัน")));break;case"board":{const e=J();if(!e){console.log(chalk.yellow(S(" 没有 mduck-48 token,看不了榜。"," No mduck-48 token on this machine — no board to show."," เครื่องนี้ไม่มี token ของ mduck-48 — ไม่มีกระดานให้ดู")));break}const o=pickCheckpoint(w,n[0]);if(n[0]&&!o){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`,` ไม่รู้จัก "${n[0]}"`))+chalk.gray(S(" scenarios 列出所有名字。"," `scenarios` lists the names."," `scenarios` แสดงรายชื่อ")));break}await Z(e,o??D??F(w,v)??w[w.length-1]);break}case"move":case"replay":{const n=I();if(!("replay"!==o||v.lastSandbox&&n.length)){if(!t(A)){console.log(chalk.gray(S(" 还没有图。先 run 一次。"," No picture yet. `run` first."," ยังไม่มีภาพ `run` ก่อน")));break}W(A);break}if(!m){console.log(chalk.gray(S(" 鸭子命令要在本机仿真 — "," Duck commands run the sim on this machine — "," คำสั่งเป็ดรันตัวจำลองบนเครื่องนี้ — ")+chalk.bold.green("mujoco setup")+S("(~45 MB,免 sudo),装好再回来。"," (~45 MB, no sudo), then come back."," (~45 MB ไม่ต้อง sudo) แล้วกลับมาใหม่")));break}const r="move"===o?[...n,e.trim().replace(/^\//,"")]:n,s="move"===o?n.length:0;h(`duck ${"move"===o?e.trim():"replay"}`),console.log(chalk.gray(S(" 🦆 仿真中…"," 🦆 simulating…"," 🦆 กำลังจำลอง…")));const a=await P(b,g,r,s,v.arena);if(!0!==a.ok){H(a);break}"move"===o&&G(r),v.lastSandbox=!0,E(v),V(a);break}case"undo":{const e=I();if(!e.length){console.log(chalk.gray(S(" 计划是空的,没有可撤的。"," The plan is empty — nothing to undo."," แผนว่างเปล่า — ไม่มีอะไรให้ undo")));break}const o=e.pop();G(e),console.log(chalk.white(S(` ↩ 撤掉了「${o}」`,` ↩ took back "${o}"`,` ↩ ยกเลิก "${o}" แล้ว`))+chalk.gray(S(` · 还剩 ${e.length} 步 · replay 从头看`,` · ${e.length} step${1===e.length?"":"s"} left · replay to watch`,` · เหลือ ${e.length} step${1===e.length?"":"s"} · replay เพื่อดู`)));break}case"plan":{const e=I();if(!e.length){console.log(chalk.gray(S(" 计划是空的。试试:walk 0.3 2"," The plan is empty. Try: walk 0.3 2"," แผนว่างเปล่า ลอง: walk 0.3 2")));break}console.log(chalk.bold.white(S(" 你的计划"," Your plan"," แผนของคุณ"))+chalk.gray(S(`(${v.arena??"空地"})`,` (${v.arena??"open floor"})`,` (${v.arena??"open floor"})`)));for(const[o,t]of e.entries())console.log(` ${chalk.gray(String(o+1).padStart(2))} ${chalk.white(t)}`);console.log(chalk.gray(S(" ▸ replay 从头看 · undo 撤最后一步 · save 存成 control.py"," ▸ replay · undo · save"," ▸ replay · undo · save")));break}case"clear":{const e=I().length;G([]),v.lastSandbox=!1,E(v),console.log(chalk.white(S(` 🧹 计划清空了(原来 ${e} 步)。`,` 🧹 Plan cleared (was ${e} steps).`,` 🧹 ล้างแผนแล้ว (เดิมมี ${e} ขั้นตอน)`))+chalk.gray(S(" 鸭子回到起点。"," The duck is back at the start."," เป็ดกลับไปที่จุดเริ่มต้น")));break}case"use":{const e=(n[0]??"").toLowerCase();if(!e){console.log(chalk.white(S(` 现在在:${v.arena??"空地"}`,` Now on: ${v.arena??"the open floor"}`,` ตอนนี้อยู่ที่: ${v.arena??"the open floor"}`))+chalk.gray(S(" · use r3 = 任务桌 · use c8 = 绕墙 · use free = 空地"," · use r3 = mission table · use c8 = wall · use free = open floor"," · use r3 = ตารางภารกิจ · use c8 = กำแพง · use free = พื้นโล่ง")));break}if(["free","floor","open","sandbox"].includes(e))v.arena=void 0;else{const o=pickCheckpoint(w,e);if(!o?.scenario){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`,` ไม่รู้จัก "${n[0]}"`))+chalk.gray(S(" scenarios 列出所有名字;use free 回空地。"," `scenarios` lists the names; `use free` = open floor."," `scenarios` แสดงรายชื่อ; `use free` = พื้นโล่ง")));break}v.arena=o.scenario}v.lastSandbox=!1,E(v),console.log(chalk.white(S(` 🗺 换到 ${v.arena??"空地"}。`,` 🗺 Now on ${v.arena??"the open floor"}.`,` 🗺 ตอนนี้อยู่ที่ ${v.arena??"the open floor"}`))+chalk.gray(S(" 计划保留着 —— replay 在新场地上看一遍。"," The plan is kept — `replay` to watch it here."," แผนยังอยู่ — `replay` เพื่อดูที่นี่")));break}case"save":{const e=I();if(!e.length){console.log(chalk.gray(S(" 计划是空的,先敲几条命令(walk 0.3 2)。"," The plan is empty — type a few commands first (walk 0.3 2)."," แผนว่างเปล่า — พิมพ์คำสั่งสักสองสามอัน (walk 0.3 2)")));break}if(!m){console.log(chalk.gray(S(" save 需要本机引擎 — mujoco setup。"," save needs the local engine — mujoco setup."," save ต้องใช้เอนจินในเครื่อง — mujoco setup")));break}const o=`${N}.try`;G(e,o);const n=B(b,g,["plansrc","--plan",o]);if(!0!==n.ok||"string"!=typeof n.source){H(n);break}const a=t(j)?r(j,"utf-8"):"";a&&a!==n.source&&s(`${j}.bak`,a),s(j,n.source),h("duck save"),console.log(chalk.green(S(` 💾 存好了:control.py = 你的 ${e.length} 条命令`,` 💾 Saved: control.py = your ${e.length} commands`,` 💾 บันทึกแล้ว: control.py = คำสั่ง ${e.length} อันของคุณ`))+chalk.gray(a&&a!==n.source?S("(旧文件在 control.py.bak)"," (old file kept as control.py.bak)"," (เก็บไฟล์เก่าไว้เป็น control.py.bak)"):"")),console.log(chalk.gray(S(" ▸ edit 看看它变成了什么代码 · run r3 在任务桌上打分 · submit 提交"," ▸ edit to see the code it became · run r3 to score it on the mission table · submit"," ▸ edit ดูโค้ดที่ได้ · run r3 ให้คะแนนบนตารางภารกิจ · submit")));break}case"syntax":{const e=(()=>{try{return"zh"===_()&&m?String(B(b,g,["cheatsheet","--lang","zh"]).text??""):r(l(g,"syntax.txt"),"utf-8")}catch{return""}})();console.log(chalk.gray(e||S(" (速查表不在引擎包里)"," (no syntax sheet in the engine package)"," (ไม่มีตารางไวยากรณ์ในแพ็กเกจเอนจิน)")));break}case"edit":console.log(chalk.gray(S(" vi 三键: i 进入编辑 · Esc 退出编辑 · :wq 存盘离开 · :q! 放弃"," vi survival: i = edit · Esc = stop editing · :wq = save and leave · :q! = discard"," เอาตัวรอดใน vi: i = แก้ไข · Esc = หยุดแก้ไข · :wq = บันทึกแล้วออก · :q! = ทิ้งการแก้ไข"))),await i("vi",[...x,j]);break;case"run":{const e=pickCheckpoint(w,n[0]);if(n[0]&&!e){console.log(chalk.yellow(S(` 不认识「${n[0]}」。`,` Don't know "${n[0]}".`,` ไม่รู้จัก "${n[0]}"`))+chalk.gray(S(" scenarios 列出所有名字。"," `scenarios` lists the names."," `scenarios` แสดงรายชื่อ")));break}const o=e??D??F(w,v);if(!o){console.log(chalk.green(S(" 12 个检查点全部 AC。"," All 12 checkpoints AC."," ผ่านครบ 12 checkpoint (AC)")));break}if(e&&(D=e),!o.scenario){console.log(chalk.gray(S(" 这一关是打印题,不在仿真里:写好程序直接 submit。"," This checkpoint is a print-a-number task, not a sim run: write the program and `submit`."," checkpoint นี้เป็นโจทย์พิมพ์ตัวเลข ไม่ใช่รันตัวจำลอง: เขียนโปรแกรมแล้ว `submit`")));break}if(!m){console.log(chalk.gray(S(" 本机没有仿真 — "," No sim on this machine — "," เครื่องนี้ไม่มีตัวจำลอง — ")+chalk.bold.green("mujoco setup")+S("(~45 MB,免 sudo)。submit 照样能交。"," (~45 MB, no sudo). `submit` still works."," (~45 MB ไม่ต้อง sudo) `submit` ยังใช้ได้")));break}process.stdout.write(chalk.gray(S(` ${q(o)} … `,` ${q(o)} … `,` ${q(o)} … `)));const t=B(b,g,["run","--file",j,"--scenario",o.scenario,"--png",A]);if(console.log(),v.lastSandbox=!1,!0!==t.ok){Y(t);break}const r=t.prints??[];for(const e of r.slice(0,12))console.log(chalk.white(` ${e}`));Number(t.prints_total)>12&&console.log(chalk.gray(S(` … 共 ${t.prints_total} 行输出`,` … ${t.prints_total} lines printed`,` … พิมพ์ออกมา ${t.prints_total} บรรทัด`)));const s=Boolean(t.pass);console.log((s?chalk.green(" ✓ "):chalk.yellow(" ✗ "))+chalk.white(String(t.detail??""))+chalk.gray(null!=t.fallen_at?S(` · 摔倒于 ${t.fallen_at} s`,` · fell at ${t.fallen_at} s`,` · ล้มที่ ${t.fallen_at} วินาที`):"")+chalk.gray(` (${t.seconds} s ${S("仿真","sim","ตัวจำลอง")}, ${t.time_ms} ms)`));const a=v.attempts[String(o.card)]??[];a.push(s),v.attempts[String(o.card)]=a,E(v),console.log(chalk.gray(s?S(" ▸ submit 提交检查点 ▸ replay 再看图 ▸ edit 继续改"," ▸ submit ▸ replay the picture ▸ edit to keep improving"," ▸ submit ▸ replay ดูภาพ ▸ edit เพื่อปรับให้ดีขึ้น"):S(" ▸ replay 看图找原因 ▸ edit 改一改再 run"," ▸ replay to see what happened ▸ edit, then run"," ▸ replay ดูว่าเกิดอะไรขึ้น ▸ edit แล้ว run"))),"string"==typeof t.png&&process.stdout.isTTY&&W(t.png);break}case"submit":{const e=D??F(w,v);if(!e){console.log(chalk.green(S(" 全部 AC。"," All AC."," AC ทั้งหมด")));break}if(m){const e=B(b,g,["syntax","--file",j]);if(!1===e.ok){Y(e);break}}const o=J();if(!o){console.log(chalk.yellow(S(" 这台机器上没有 mduck-48 token,没法交。"," No mduck-48 token on this machine — nothing to submit with."," เครื่องนี้ไม่มี token ของ mduck-48 — ไม่มีอะไรให้ submit"))),console.log(chalk.gray(S(" ▸ learn 粘 token 后再来。"," ▸ paste your token in `learn`, then come back."," ▸ วาง token ของคุณใน `learn` แล้วกลับมาใหม่")));break}const t=await d(o,e.phase,e.slot);if(!t.ok||!t.data){console.log(chalk.yellow(S(" 服务端没开门:"," Server did not open the checkpoint: "," เซิร์ฟเวอร์เปิด checkpoint ไม่ได้: ")+String(t.message??t.code??"")));break}const n=t.data.problems[0]?.id??(e.race?`duck-r${e.slot}`:`duck-c${e.card}`);console.log(chalk.gray(S(" ⚖ 判分中(服务端 · "," ⚖ judging (server · "," ⚖ กำลังตรวจ (เซิร์ฟเวอร์ · ")+q(e)+S(")… 约 5–10 秒",")… 5–10 s",")… 5–10 วินาที")));const s=await p(o,e.phase,n,r(j,"utf-8"),e.slot);if(!s.ok||!s.data){if("race_throttle"===s.code){const e=Math.max(1,Math.ceil(Number(s.wait_s??0)));console.log(chalk.yellow(S(` ⏱ 赛日题每 3 分钟判一次 —— 再等 ${e} 秒。本机 run 不限次,先跑几遍再交。`,` ⏱ Race entries are judged once every 3 minutes — ${e} s to go. Local \`run\` is unlimited; try a few first.`,` ⏱ ตรวจผลงานวันแข่งได้ทุก 3 นาทีครั้ง — อีก ${e} วินาที \`run\` ในเครื่องไม่จำกัด ลองสักสองสามรอบก่อน`)));break}console.log(chalk.yellow(S(" 判分没回来:"," No verdict came back: "," ไม่ได้รับผลตัดสิน: ")+String(s.message??s.code??"")));break}const a=s.data;for(const e of(a.report??[]).slice(0,3))console.log(chalk.gray(` ${e}`));if(a.note&&console.log(chalk.gray(` ${a.note}`)),"AC"===a.verdict||!0===a.already_ac){v.ac.includes(e.card)||v.ac.push(e.card),E(v);const t=v.ac.filter(e=>e<=48).length;console.log(chalk.green(` ✅ AC · ${t}/12`+(1===t?S(" 🎉 第一个检查点!"," 🎉 first checkpoint!"," 🎉 checkpoint แรก!"):""))),await Z(o,e,{ticker:!0});const n=O(w).find(o=>!v.ac.includes(o.card)&&o.card>e.card)??null,r=O(w).find(o=>!v.ac.includes(o.card)&&o.card<e.card)??null;D=null,console.log(chalk.green(e.race?S(" ▸ board 看榜 · 想刷成绩再 edit → run → submit"," ▸ board to see the ranking · edit → run → submit to improve"," ▸ board ดูอันดับ · edit → run → submit เพื่อปรับให้ดีขึ้น"):n?S(` ▸ back 回卡片,读第 ${e.card+1} 张 —— 下一个检查点在卡 ${n.card}`,` ▸ back to the cards, read card ${e.card+1} — next checkpoint is card ${n.card}`,` ▸ back ไปที่การ์ด อ่านการ์ด ${e.card+1} — checkpoint ถัดไปคือการ์ด ${n.card}`):r?S(` ▸ 前面还有没做的检查点:卡 ${r.card}`,` ▸ an earlier checkpoint is still open: card ${r.card}`,` ▸ ยังมี checkpoint ก่อนหน้าที่ยังไม่ผ่าน: การ์ด ${r.card}`):S(" 🎓 12/12 —— 鸭子听你的了。"," 🎓 12/12 — the duck does what you say."," 🎓 12/12 — เป็ดทำตามที่คุณสั่ง"))),!e.race&&n&&r&&console.log(chalk.gray(S(` (卡 ${r.card} 的检查点也还没做)`,` (card ${r.card}'s checkpoint is still open too)`,` (checkpoint ของการ์ด ${r.card} ก็ยังไม่ผ่านเหมือนกัน)`)))}else console.log(chalk.yellow(S(` ❌ ${a.verdict}。`,` ❌ ${a.verdict}.`,` ❌ ${a.verdict}`))+chalk.gray(S(" ▸ run 本机看图 ▸ edit"," ▸ run to see the picture ▸ edit"," ▸ run ดูภาพ ▸ edit")));break}default:if(X+=1,console.log(chalk.yellow(S(` 不认识「${e.trim()}」。`,` Don't know "${e.trim()}".`,` ไม่รู้จัก "${e.trim()}"`))+chalk.gray(S(" 可用:walk 0.3 2 · turn left 90 · help · edit · run · submit · back"," Try: walk 0.3 2 · turn left 90 · help · edit · run · submit · back"," ลอง: walk 0.3 2 · turn left 90 · help · edit · run · submit · back"))),X>=3)return console.log(chalk.gray(S(" 连续三次没对上 —— 回上一层。"," Three misses — going back one level."," พลาดสามครั้ง — ถอยกลับหนึ่งชั้น"))),"back"}}}finally{L.close()}}export function registerDuckCommand(e){e.command("duck [args...]").description("Duck ABC sim bench — edit control.py, run the biped in MuJoCo on this machine, submit checkpoints").action(async e=>{await runDuck(e??[])})}
|