Skip to content

Commit a3d357d

Browse files
He ChenyuHe Chenyu
authored andcommitted
add competition+
1 parent 1cbeb5e commit a3d357d

3 files changed

Lines changed: 179 additions & 2 deletions

File tree

DataCollect.html

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<!DOCTYPE html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>参赛信息登记 · Contest Profile</title>
7+
<meta name="theme-color" content="#0b0c0d" />
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
9+
<style>
10+
:root{ --bg:#0b0c0d; --panel:#0f1113; --muted:#9aa4ad; --text:#e6eef6; --accent:#48a0ff; --radius:12px; }
11+
body{margin:0;background:var(--bg);color:var(--muted);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial;}
12+
.wrap{max-width:560px;margin:0 auto;padding:20px}
13+
h1{color:#fff;font-size:20px;margin:0 0 12px;display:flex;align-items:center;gap:8px}
14+
.card{background:var(--panel);border:1px solid rgba(255,255,255,0.08);border-radius:var(--radius);padding:16px}
15+
label{display:block;margin-top:10px;font-size:13px;color:#cbd5e1}
16+
input{width:100%;margin-top:6px;background:#161a1e;border:1px solid #222;border-radius:8px;padding:8px 10px;color:#e6eef6;font-size:13px}
17+
.row{display:flex;gap:10px;justify-content:flex-end;margin-top:14px}
18+
button{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border-radius:10px;border:1px solid rgba(255,255,255,0.08);background:var(--panel);color:var(--text);cursor:pointer}
19+
button.primary{background:var(--accent);color:#071022;border:0}
20+
</style>
21+
</head>
22+
<body>
23+
<div class="wrap">
24+
<h1><i class="fas fa-id-card"></i> 参赛信息登记 · Contest Profile</h1>
25+
<div class="card">
26+
<label>昵称 / Handle
27+
<input id="handle" placeholder="如 alice" />
28+
</label>
29+
<label>GitHub 用户名 / GitHub Username
30+
<input id="github" placeholder="如 alice" />
31+
</label>
32+
<label>邮箱 / Email (可选 Optional)
33+
<input id="email" placeholder="example@domain.com" />
34+
</label>
35+
<div class="row">
36+
<button id="cancel"><i class="fas fa-xmark"></i> 取消 Cancel</button>
37+
<button id="save" class="primary"><i class="fas fa-check"></i> 保存 Save</button>
38+
</div>
39+
</div>
40+
</div>
41+
<script>
42+
function save(){
43+
const handle=document.getElementById('handle').value.trim();
44+
const github=document.getElementById('github').value.trim();
45+
const email=document.getElementById('email').value.trim();
46+
if(!handle){ alert('请输入昵称 / Handle'); return; }
47+
if(!github){ alert('请输入 GitHub 用户名'); return; }
48+
const obj={ handle, github, email };
49+
try{ localStorage.setItem('contest_profile', JSON.stringify(obj)); }catch(e){}
50+
try{ window.opener && window.opener.postMessage({type:'contest_profile_saved'}, '*'); }catch(e){}
51+
setTimeout(()=>{ window.close(); }, 120);
52+
}
53+
document.getElementById('save').addEventListener('click', save);
54+
document.getElementById('cancel').addEventListener('click', ()=>window.close());
55+
// 预填已有
56+
try{
57+
const raw=localStorage.getItem('contest_profile'); if(raw){ const p=JSON.parse(raw); handle.value=p.handle||''; github.value=p.github||''; email.value=p.email||''; }
58+
}catch(e){}
59+
</script>
60+
</body>
61+
</html>

competition/submit.html

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<!DOCTYPE html>
2+
<html lang="zh-CN">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<title>提交参赛 · Submit Contest</title>
7+
<meta name="theme-color" content="#0b0c0d" />
8+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" />
9+
<style>
10+
:root{ --bg:#0b0c0d; --panel:#0f1113; --muted:#9aa4ad; --text:#e6eef6; --accent:#48a0ff; --radius:12px; }
11+
body{margin:0;background:var(--bg);color:var(--muted);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial}
12+
.wrap{max-width:900px;margin:0 auto;padding:20px}
13+
header{display:flex;align-items:center;gap:10px;justify-content:space-between}
14+
header h1{color:#fff;font-size:20px;margin:0;display:flex;align-items:center;gap:8px}
15+
.card{background:var(--panel);border:1px solid rgba(255,255,255,0.08);border-radius:var(--radius);padding:16px;margin-top:16px}
16+
.row{display:flex;gap:10px;flex-wrap:wrap}
17+
a.btn,button.btn{display:inline-flex;align-items:center;gap:8px;padding:8px 12px;border-radius:10px;text-decoration:none;border:1px solid rgba(255,255,255,0.08);background:var(--panel);color:var(--text);cursor:pointer}
18+
a.btn.primary,button.btn.primary{background:var(--accent);color:#071022;border:0}
19+
textarea{width:100%;min-height:260px;background:#161a1e;border:1px solid #222;border-radius:8px;color:#e6eef6;padding:10px 12px;font-family:Menlo,monospace;font-size:13px}
20+
.muted{color:#7e8b97}
21+
</style>
22+
</head>
23+
<body>
24+
<div class="wrap">
25+
<header>
26+
<h1><i class="fas fa-paper-plane"></i> 提交参赛 · Submit Contest</h1>
27+
<div class="row">
28+
<a class="btn" href="../index.html"><i class="fas fa-flag-checkered"></i> 每周挑战 Weekly</a>
29+
<a class="btn" href="../../index.html"><i class="fas fa-code"></i> 编辑器 Editor</a>
30+
</div>
31+
</header>
32+
33+
<div class="card">
34+
<div id="summary" class="muted">解析提交中…</div>
35+
<div class="row" style="margin-top:8px">
36+
<button id="copyBtn" class="btn"><i class="fas fa-copy"></i> 复制代码 Copy Code</button>
37+
<a id="openGh" class="btn primary" target="_blank" rel="noreferrer"><i class="fas fa-file-circle-plus"></i> 前往 GitHub 新建文件 Create on GitHub</a>
38+
</div>
39+
<textarea id="code"></textarea>
40+
<div class="muted" style="margin-top:8px">提示:点击“前往 GitHub 新建文件”,在打开的页面粘贴代码,提交到 `submissions/week-<n>/<handle>/solution.c`,然后发起 PR。
41+
</div>
42+
</div>
43+
</div>
44+
<script>
45+
function decodeBase64(b64){
46+
try{
47+
const bin=atob(b64); const bytes=new Uint8Array(bin.length); for(let i=0;i<bin.length;i++) bytes[i]=bin.charCodeAt(i);
48+
return new TextDecoder().decode(bytes);
49+
}catch(e){ return decodeURIComponent(escape(atob(b64))); }
50+
}
51+
function parseWeek(code){ const m=code.match(/week-(\d+)/i); return m? parseInt(m[1],10): null; }
52+
const OWNER='DanielHe666';
53+
const REPO='c';
54+
(function(){
55+
const h=location.hash||''; if(!h.startsWith('#submission=')){ document.getElementById('summary').textContent='无提交数据 / No submission payload.'; return; }
56+
try{
57+
const obj=JSON.parse(decodeBase64(h.slice('#submission='.length))||'{}');
58+
const week=parseWeek(obj.challenge)||1;
59+
const handle=(obj.handle||'anon').replace(/[^a-zA-Z0-9_-]/g,'-');
60+
const path=`submissions/week-${week}/${handle}`;
61+
const ghNew=`https://github.com/${OWNER}/${REPO}/new/main/${encodeURIComponent(path)}?filename=solution.c`;
62+
document.getElementById('openGh').href=ghNew;
63+
document.getElementById('code').value=obj.code||'';
64+
document.getElementById('summary').textContent=`选手 ${obj.handle||'anon'} · 题目 ${obj.challenge} · 估算 ${obj.bytes||0} 字节`;
65+
document.getElementById('copyBtn').addEventListener('click',()=>{
66+
navigator.clipboard.writeText(document.getElementById('code').value).then(()=>{
67+
document.getElementById('copyBtn').innerHTML='<i class="fas fa-check"></i> 已复制 Copied';
68+
});
69+
});
70+
}catch(e){ document.getElementById('summary').textContent='解析失败 / Parse failed'; }
71+
})();
72+
</script>
73+
</body>
74+
</html>

index.html

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,7 @@ <h2><i class="fas fa-file-code"></i> <span id="fileTitle">main.c</span></h2>
640640
online:'在线', offline:'离线模式', run_title_on:'运行 (Ctrl/Cmd+Enter)', run_title_off:'离线:请连接网络后再运行', io_toggle:'输入/输出', hide_io:'隐藏 I/O',
641641
cases_empty:'暂无用例,点击 + 新建。', case_name:'用例', delete:'删除',
642642
share_title:'生成分享链接', share_desc:'可选择包含以下内容以便对方完整复现:', include_stdin:'包含输入 (stdin)', include_cases:'包含测试用例',
643+
contest:'参赛', contest_desc:'参与每周挑战:输入题目编码(例如 week-1),生成参赛提交数据。首次将弹出信息登记。', contest_code_placeholder:'题目编码,如 week-1', contest_submit:'参赛提交', contest_first_info:'首次参赛,请填写信息后自动继续提交...', contest_profile_copied:'参赛提交信息已复制,请按比赛 README 发起 PR。', contest_invalid_code:'题目编码不正确,请检查。',
643644
offline_title:'离线不可运行', offline_desc:'当前处于离线状态,暂不进行本地模拟运行,以避免结果不一致。请恢复网络后再点击“运行”。测试用例批量/单个运行也需要网络。', ok:'知道了',
644645
metrics_title:'代码复杂度与度量', metrics_desc:'实时分析当前编辑器内容,帮助了解规模与潜在复杂度。复杂度为近似估算(启发式),非精确解析。', metrics_refresh:'刷新度量', metrics_copy:'复制报告', metrics_copied:'已复制', metrics_placeholder:'(点击“刷新度量”或编辑代码后查看)',
645646
save_as:'另存为', theme:'主题', theme_light:'明亮', theme_dark:'暗色', stdin_placeholder:'请先输入再点击运行...', stdout_placeholder:'程序输出将显示在这里...', expected_placeholder:'期望输出 (可留空)',
@@ -653,6 +654,7 @@ <h2><i class="fas fa-file-code"></i> <span id="fileTitle">main.c</span></h2>
653654
online:'Online', offline:'Offline', run_title_on:'Run (Ctrl/Cmd+Enter)', run_title_off:'Offline: connect network to run', io_toggle:'I/O Panel', hide_io:'Hide I/O',
654655
cases_empty:'No cases yet, click + to add.', case_name:'Case', delete:'Delete',
655656
share_title:'Create Share Link', share_desc:'Select items to include for full reproduction:', include_stdin:'Include stdin', include_cases:'Include test cases',
657+
contest:'Contest', contest_desc:'Participate in weekly challenge: enter problem code (e.g. week-1) to generate submission payload. First time will prompt info.', contest_code_placeholder:'Problem code, e.g. week-1', contest_submit:'Submit Contest', contest_first_info:'First time participation: collecting profile then auto submit...', contest_profile_copied:'Contest submission copied. Follow README to open PR.', contest_invalid_code:'Invalid problem code.',
656658
offline_title:'Offline - Execution Disabled', offline_desc:'You are offline. To avoid misleading outputs, local simulation is disabled. Please reconnect to run. Test cases also require network.', ok:'Got it',
657659
metrics_title:'Code Metrics', metrics_desc:'Analyze the current code for size and potential complexity. Heuristic only, not a precise parser.', metrics_refresh:'Refresh', metrics_copy:'Copy Report', metrics_copied:'Copied', metrics_placeholder:'(Click “Refresh” or edit code to update)',
658660
save_as:'Save As', theme:'Theme', theme_light:'Light', theme_dark:'Dark', stdin_placeholder:'Enter stdin (optional), then click Run', stdout_placeholder:'Program output will appear here...', expected_placeholder:'Expected output (optional)',
@@ -806,8 +808,8 @@ <h2><i class="fas fa-file-code"></i> <span id="fileTitle">main.c</span></h2>
806808
modal.id = 'shareModal';
807809
modal.style.position='fixed'; modal.style.inset='0'; modal.style.display='flex'; modal.style.alignItems='center'; modal.style.justifyContent='center'; modal.style.background='rgba(0,0,0,.45)'; modal.style.zIndex='4500';
808810
}
809-
// 依据语言生成内容
810-
modal.innerHTML = '<div style="width:min(460px,92vw);background:var(--panel);border:1px solid rgba(255,255,255,0.08);border-radius:14px;box-shadow:0 18px 50px -10px rgba(0,0,0,.55);padding:16px;transform:translateY(12px) scale(.96);opacity:0;transition:.28s var(--anim-enter)"><div style="display:flex;align-items:center;justify-content:space-between"><div style="font-weight:600;color:#fff"><i class=\'fas fa-share-nodes\'></i> '+t('share_title')+'</div><button id="shareClose" class="btn ghost"><i class=\'fas fa-xmark\'></i> '+t('ok')+'</button></div><div style="margin-top:12px;color:var(--muted);font-size:13px;line-height:1.7">'+t('share_desc')+'</div><div style="margin-top:10px;display:flex;flex-direction:column;gap:8px;color:var(--muted)"><label style="display:flex;align-items:center;gap:8px"><input id="optStdin" type="checkbox"/> '+t('include_stdin')+'</label><label style="display:flex;align-items:center;gap:8px"><input id="optCases" type="checkbox"/> '+t('include_cases')+'</label></div><div style="margin-top:12px;display:flex;gap:8px;justify-content:flex-end"><button id="shareCopy" class="btn primary" style="background:var(--accent);color:#071022"><i class=\'fas fa-link\'></i> '+t('share_copy')+'</button></div></div>';
811+
// 依据语言生成内容(加入参赛选项)
812+
modal.innerHTML = '<div style="width:min(520px,92vw);background:var(--panel);border:1px solid rgba(255,255,255,0.08);border-radius:14px;box-shadow:0 18px 50px -10px rgba(0,0,0,.55);padding:16px;transform:translateY(12px) scale(.96);opacity:0;transition:.28s var(--anim-enter)"><div style="display:flex;align-items:center;justify-content:space-between"><div style="font-weight:600;color:#fff"><i class=\'fas fa-share-nodes\'></i> '+t('share_title')+'</div><button id="shareClose" class="btn ghost"><i class=\'fas fa-xmark\'></i> '+t('ok')+'</button></div><div style="margin-top:12px;color:var(--muted);font-size:13px;line-height:1.7">'+t('share_desc')+'</div><div style="margin-top:10px;display:flex;flex-direction:column;gap:8px;color:var(--muted)"><label style="display:flex;align-items:center;gap:8px"><input id="optStdin" type="checkbox"/> '+t('include_stdin')+'</label><label style="display:flex;align-items:center;gap:8px"><input id="optCases" type="checkbox"/> '+t('include_cases')+'</label></div><div style="margin-top:12px;display:flex;flex-direction:column;gap:6px;border-top:1px solid rgba(255,255,255,0.05);padding-top:10px"><div style="font-weight:600;color:#fff;font-size:13px"><i class=\'fas fa-trophy\'></i> '+t('contest')+'</div><div style="color:var(--muted);font-size:12px;line-height:1.6">'+t('contest_desc')+'</div><input id="contestCodeInput" placeholder="'+t('contest_code_placeholder')+'" style="margin-top:6px;background:#161a1e;border:1px solid #222;border-radius:8px;padding:6px 8px;color:#eee;font-size:12px"/></div><div style="margin-top:14px;display:flex;gap:8px;justify-content:flex-end;flex-wrap:wrap"><button id="contestSubmitBtn" class="btn" style="background:#9146ff;color:#fff"><i class=\'fas fa-medal\'></i> '+t('contest_submit')+'</button><button id="shareCopy" class="btn primary" style="background:var(--accent);color:#071022"><i class=\'fas fa-link\'></i> '+t('share_copy')+'</button></div></div>';
811813
document.body.appendChild(modal);
812814
modal.style.display='flex';
813815
requestAnimationFrame(()=>{ const inner=modal.firstElementChild; inner.style.opacity='1'; inner.style.transform='translateY(0) scale(1)'; });
@@ -824,6 +826,46 @@ <h2><i class="fas fa-file-code"></i> <span id="fileTitle">main.c</span></h2>
824826
setTimeout(()=>{ copyBtn.innerHTML = '<i class="fas fa-link"></i> '+t('share_copy'); }, 1200);
825827
}).catch(()=>{ prompt('复制失败,请手动复制:', url); });
826828
};
829+
// —— 参赛提交逻辑 ——
830+
const contestBtn = modal.querySelector('#contestSubmitBtn');
831+
const contestInput = modal.querySelector('#contestCodeInput');
832+
let pendingContestCode = null;
833+
function validContestCode(code){ return /^week-\d+$/i.test(code.trim()); }
834+
function buildContestPayload(code){
835+
const profileRaw = localStorage.getItem('contest_profile');
836+
let profile = {}; try{ profile = JSON.parse(profileRaw||'{}'); }catch(e){}
837+
const handle = profile.handle || profile.nickname || 'anon';
838+
const github = profile.github || '';
839+
const email = profile.email || '';
840+
const source = window.editor? window.editor.getValue() : '';
841+
const bytes = new TextEncoder().encode(source).length;
842+
return { type:'contest', version:1, challenge:code, handle, github, email, bytes, ts:new Date().toISOString(), code:source };
843+
}
844+
function performContestSubmit(code){
845+
const payload = buildContestPayload(code);
846+
try{
847+
const b64 = encodeBase64(JSON.stringify(payload));
848+
const url = 'competition/submit.html#submission=' + b64;
849+
window.open(url, '_blank');
850+
}catch(e){ alert('Contest submit failed: '+ (e&&e.message)); }
851+
}
852+
window.addEventListener('message', (ev)=>{
853+
if(ev && ev.data && ev.data.type==='contest_profile_saved' && pendingContestCode){
854+
setTimeout(()=>performContestSubmit(pendingContestCode), 150);
855+
}
856+
}, { once:false });
857+
contestBtn.onclick = ()=>{
858+
const code = (contestInput.value||'').trim();
859+
if(!validContestCode(code)){ alert(t('contest_invalid_code')); return; }
860+
const profileRaw = localStorage.getItem('contest_profile');
861+
if(!profileRaw){
862+
pendingContestCode = code;
863+
alert(t('contest_first_info'));
864+
window.open('DataCollect.html', 'contestProfile', 'width=520,height=600');
865+
}else{
866+
performContestSubmit(code);
867+
}
868+
};
827869
document.addEventListener('keydown', function esc(e){ if(e.key==='Escape'){ close(); document.removeEventListener('keydown', esc);} });
828870
}
829871
shareBtn.addEventListener('click', open);

0 commit comments

Comments
 (0)