补全9月11日至13日课评:为13名学生创建请假文档,为5个班级创建总结文档

This commit is contained in:
chengzi
2026-09-13 19:34:34 +08:00
parent 167d832353
commit 21001eccf5
1322 changed files with 37510 additions and 4136 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,883 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>第1周周六下午CSP04班课评</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;600;700&family=Noto+Sans+SC:wght@300;400;500;600&display=swap');
:root {
--coral: #e85d4c;
--coral-light: #f5a99e;
--coral-dark: #c44738;
--amber: #f0a84a;
--amber-light: #f5d08a;
--ink: #2c2420;
--ink-soft: #5a524e;
--paper: #faf6f1;
--paper-warm: #f5efe8;
--cream: #fffdf9;
--border: #e8e0d8;
--shadow-soft: rgba(44, 36, 32, 0.06);
--shadow-medium: rgba(44, 36, 32, 0.10);
--shadow-card: rgba(44, 36, 32, 0.08);
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, sans-serif;
background: var(--paper);
min-height: 100vh;
color: var(--ink);
background-image:
radial-gradient(circle at 20% 50%, rgba(240, 168, 74, 0.03) 0%, transparent 50%),
radial-gradient(circle at 80% 20%, rgba(232, 93, 76, 0.02) 0%, transparent 50%),
radial-gradient(circle at 50% 80%, rgba(240, 168, 74, 0.02) 0%, transparent 40%);
}
.topbar {
position: sticky;
top: 0;
z-index: 100;
background: rgba(250, 246, 241, 0.92);
border-bottom: 1px solid var(--border);
padding: 14px 28px;
display: flex;
justify-content: space-between;
align-items: center;
}
.topbar-title {
font-family: 'Noto Serif SC', serif;
font-size: 1.05em;
font-weight: 600;
color: var(--ink);
letter-spacing: 0.5px;
}
.topbar-meta {
font-size: 0.8em;
color: var(--ink-soft);
margin-top: 2px;
}
.topbar-actions {
display: flex;
gap: 10px;
}
.btn {
padding: 8px 18px;
border-radius: 10px;
font-size: 0.85em;
font-weight: 500;
cursor: pointer;
transition: all 0.25s ease;
border: none;
font-family: inherit;
}
.btn-outline {
background: transparent;
border: 1.5px solid var(--border);
color: var(--ink-soft);
}
.btn-outline:hover {
border-color: var(--coral);
color: var(--coral);
background: rgba(232, 93, 76, 0.05);
}
.btn-success {
background: var(--coral);
color: white;
}
.btn-success:hover {
background: var(--coral-dark);
}
.main {
max-width: 680px;
margin: 0 auto;
padding: 28px 20px 160px;
position: relative;
}
.course-hero {
background: linear-gradient(135deg, var(--cream) 0%, var(--paper-warm) 100%);
border-radius: 20px;
padding: 36px 32px 32px;
margin-bottom: 24px;
border: 1px solid var(--border);
position: relative;
overflow: hidden;
box-shadow: 0 2px 8px var(--shadow-soft), 0 8px 32px var(--shadow-card);
}
.course-hero::before {
content: '';
position: absolute;
top: -60px;
right: -40px;
width: 180px;
height: 180px;
border-radius: 50%;
background: radial-gradient(circle, rgba(232, 93, 76, 0.08) 0%, transparent 70%);
}
.course-hero::after {
content: '';
position: absolute;
bottom: -40px;
left: -30px;
width: 140px;
height: 140px;
border-radius: 50%;
background: radial-gradient(circle, rgba(240, 168, 74, 0.06) 0%, transparent 70%);
}
.hero-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: linear-gradient(135deg, var(--coral) 0%, var(--amber) 100%);
color: white;
font-size: 0.75em;
font-weight: 600;
padding: 6px 16px;
border-radius: 20px;
margin-bottom: 16px;
position: relative;
z-index: 1;
letter-spacing: 0.5px;
}
.hero-title {
font-family: 'Noto Serif SC', serif;
font-size: 2.2em;
font-weight: 700;
color: var(--ink);
line-height: 1.3;
margin-bottom: 8px;
position: relative;
z-index: 1;
letter-spacing: 2px;
}
.hero-subtitle {
font-size: 0.95em;
color: var(--ink-soft);
margin-bottom: 20px;
position: relative;
z-index: 1;
}
.hero-divider {
width: 60px;
height: 3px;
background: linear-gradient(90deg, var(--coral), var(--amber));
border-radius: 2px;
margin-bottom: 20px;
position: relative;
z-index: 1;
}
.hero-info {
display: flex;
flex-wrap: wrap;
gap: 16px;
position: relative;
z-index: 1;
}
.hero-info-item {
display: flex;
align-items: center;
gap: 6px;
font-size: 0.85em;
color: var(--ink-soft);
}
.hero-info-item .icon { font-size: 1.1em; }
.goals-section {
background: var(--cream);
border-radius: 16px;
padding: 24px;
margin-bottom: 28px;
border: 1px solid var(--border);
box-shadow: 0 2px 12px var(--shadow-soft);
}
.goals-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 18px;
}
.goals-title {
font-family: 'Noto Serif SC', serif;
font-size: 1em;
font-weight: 600;
color: var(--ink);
display: flex;
align-items: center;
gap: 8px;
}
.goals-title .title-icon { font-size: 1.2em; }
.goals-toggle {
font-size: 0.78em;
color: var(--ink-soft);
cursor: pointer;
background: var(--paper-warm);
border: 1px solid var(--border);
font-family: inherit;
padding: 5px 12px;
border-radius: 8px;
transition: all 0.2s ease;
}
.goals-toggle:hover {
background: var(--coral);
color: white;
border-color: var(--coral);
}
.goals-list {
list-style: none;
display: block;
}
.goals-list.collapsed { display: none; }
.goals-list li {
padding: 12px 16px;
background: var(--paper);
border-radius: 10px;
margin-bottom: 10px;
font-size: 0.9em;
color: var(--ink-soft);
display: flex;
align-items: flex-start;
gap: 12px;
border-left: 3px solid transparent;
transition: all 0.2s ease;
}
.goals-list li:hover {
border-left-color: var(--coral);
background: var(--cream);
transform: translateX(4px);
}
.goals-list li:last-child { margin-bottom: 0; }
.goal-num {
background: linear-gradient(135deg, var(--coral) 0%, var(--amber) 100%);
color: white;
width: 26px;
height: 26px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.78em;
font-weight: 600;
flex-shrink: 0;
margin-top: 1px;
}
.goal-text { flex: 1; line-height: 1.6; }
.cards-slider-wrapper {
position: relative;
border-radius: 16px;
margin-bottom: 20px;
overflow: hidden;
}
.cards-slider {
position: relative;
min-height: 300px;
}
.student-card { display: none; }
.student-card.active { display: block; position: relative; pointer-events: auto; }
.student-card:hover {
box-shadow: 0 8px 32px var(--shadow-medium);
}
.card-header {
padding: 18px 24px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border);
background: linear-gradient(135deg, rgba(250, 246, 241, 0.5) 0%, rgba(245, 239, 232, 0.5) 100%);
border-radius: 16px 16px 0 0;
}
.student-name {
font-family: 'Noto Serif SC', serif;
font-size: 1.15em;
font-weight: 600;
color: var(--ink);
letter-spacing: 1px;
}
.card-badge {
font-size: 0.75em;
padding: 5px 12px;
border-radius: 20px;
font-weight: 500;
}
.badge-normal { background: #e8f5e9; color: #2e7d32; }
.badge-makeup { background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%); color: #e65100; }
.badge-absent { background: #fce4ec; color: #c2185b; }
.card-body { padding: 24px; }
.feedback-content {
font-size: 0.92em;
line-height: 2;
color: var(--ink-soft);
margin-bottom: 20px;
}
.feedback-content[contenteditable="true"] { outline: none; border: 2px dashed transparent; border-radius: 10px; padding: 10px; margin: -10px; transition: all 0.2s ease; }
.feedback-content[contenteditable="true"]:hover { border-color: var(--border); background: var(--paper); }
.feedback-content[contenteditable="true"]:focus { border-color: var(--coral); background: rgba(232, 93, 76, 0.03); }
.side-nav-btn {
position: fixed;
top: 50%;
transform: translateY(-50%);
z-index: 90;
width: 52px;
height: 80px;
border: none;
background: rgba(250, 246, 241, 0.85);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4em;
color: var(--ink-soft);
transition: all 0.3s ease;
box-shadow: 0 4px 16px var(--shadow-medium);
}
.side-nav-btn:hover:not(:disabled) { background: var(--cream); color: var(--coral); width: 60px; box-shadow: 0 6px 24px rgba(232, 93, 76, 0.15); }
.side-nav-btn:disabled { opacity: 0.25; cursor: not-allowed; }
.side-nav-btn.prev-btn { left: 0; border-radius: 0 12px 12px 0; border-right: 1px solid var(--border); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding-right: 4px; }
.side-nav-btn.next-btn { right: 0; border-radius: 12px 0 0 12px; border-left: 1px solid var(--border); border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); padding-left: 4px; }
.side-nav-btn .arrow { transition: transform 0.3s ease; }
.side-nav-btn:hover .arrow.prev-arrow { transform: translateX(-3px); }
.side-nav-btn:hover .arrow.next-arrow { transform: translateX(3px); }
.nav-controls { display: flex; justify-content: center; align-items: center; gap: 20px; margin-bottom: 16px; }
.page-indicator { font-family: 'Noto Serif SC', serif; font-size: 0.95em; color: var(--ink-soft); font-weight: 500; min-width: 70px; text-align: center; letter-spacing: 1px; }
.progress-dots { display: flex; justify-content: center; gap: 10px; margin-top: 4px; }
.progress-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); cursor: pointer; transition: all 0.3s ease; position: relative; }
.progress-dot.active { background: var(--coral); width: 28px; border-radius: 4px; }
.progress-dot:hover:not(.active) { background: var(--coral-light); transform: scale(1.3); }
.bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: rgba(250, 246, 241, 0.95);
border-top: 1px solid var(--border);
padding: 14px 24px;
display: flex;
justify-content: center;
gap: 12px;
z-index: 100;
}
.toast {
position: fixed;
bottom: 80px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--ink);
color: white;
padding: 12px 28px;
border-radius: 10px;
font-size: 0.85em;
opacity: 0;
transition: all 0.3s ease;
pointer-events: none;
z-index: 200;
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.edit-mode-badge {
display: none;
position: fixed;
top: 80px;
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
color: #92400e;
padding: 8px 20px;
border-radius: 20px;
font-size: 0.8em;
font-weight: 500;
z-index: 200;
border: 1px solid #fcd34d;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}
.edit-mode-badge.show { display: block; }
.footer { text-align: center; padding: 36px 20px; color: #bbb; font-size: 0.78em; font-family: 'Noto Serif SC', serif; letter-spacing: 1px; }
.oj-section { margin-top: 20px; border-radius: 12px; border: 1px solid var(--border); overflow: hidden; background: var(--paper); }
.oj-header { display: flex; align-items: center; gap: 8px; padding: 12px 16px; background: linear-gradient(135deg, rgba(232, 93, 76, 0.06) 0%, rgba(240, 168, 74, 0.04) 100%); border-bottom: 1px solid var(--border); font-size: 0.85em; font-weight: 600; color: var(--ink); }
.oj-table { width: 100%; border-collapse: collapse; font-size: 0.82em; }
.oj-table thead th { padding: 10px 14px; text-align: left; font-weight: 600; color: var(--ink-soft); background: var(--cream); border-bottom: 1px solid var(--border); font-size: 0.9em; }
.oj-table thead th:first-child { width: 45%; }
.oj-table thead th:nth-child(2) { width: 18%; }
.oj-table thead th:nth-child(3) { width: 16%; text-align: center; }
.oj-table thead th:last-child { width: 21%; text-align: center; }
.oj-table tbody td { padding: 10px 14px; border-bottom: 1px solid rgba(232, 228, 222, 0.5); color: var(--ink); vertical-align: middle; }
.oj-table tbody tr:last-child td { border-bottom: none; }
.oj-table tbody tr:hover td { background: rgba(232, 93, 76, 0.02); }
.oj-status { display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px; border-radius: 20px; font-size: 0.88em; font-weight: 500; }
.oj-status.ac { background: #e8f5e9; color: #2e7d32; }
.oj-status.wa { background: #fff3e0; color: #e65100; }
.oj-status.re { background: #fce4ec; color: #c2185b; }
.oj-status.tle { background: #e3f2fd; color: #1565c0; }
.oj-status.pending { background: #f5f5f5; color: #9e9e9e; }
.oj-status-icon { font-size: 1.1em; line-height: 1; }
.oj-submit-count { text-align: center; font-weight: 500; color: var(--ink-soft); }
.oj-submit-count.highlight { color: var(--coral); font-weight: 600; }
.oj-pattern { text-align: center; font-size: 0.9em; color: var(--ink-soft); }
.oj-summary { display: flex; align-items: center; gap: 12px; padding: 10px 16px; background: var(--cream); border-top: 1px solid var(--border); font-size: 0.82em; color: var(--ink-soft); }
.oj-summary .oj-summary-item { display: flex; align-items: center; gap: 4px; }
.oj-summary .oj-summary-num { font-weight: 600; color: var(--ink); }
@media (max-width: 768px){
.hero-title { font-size: 1.7em; }
.side-nav-btn { width: 40px; height: 60px; font-size: 1.1em; }
.main { padding: 20px 16px 160px; }
.course-hero { padding: 28px 20px 24px; }
.oj-table { font-size: 0.78em; }
.oj-table tbody td, .oj-table thead th { padding: 8px 10px; }
}
</style>
</head>
<body>
<!-- 顶部导航 -->
<div class="topbar">
<div>
<div class="topbar-title">第1周 · CSP04班课评</div>
<div class="topbar-meta">2026年9月5日 · 《基础回顾·OJ五题精讲》 · 橙子老师</div>
</div>
<div class="topbar-actions">
<button class="btn btn-outline" onclick="toggleEdit()" id="editBtn">✏️ 编辑</button>
<button class="btn btn-outline" onclick="exportText()">📋 导出</button>
</div>
</div>
<!-- 编辑模式提示 -->
<div class="edit-mode-badge" id="editBadge">📝 编辑模式 · 点击文字即可修改</div>
<!-- 侧边翻页按钮 -->
<button class="side-nav-btn prev-btn" id="sidePrevBtn" onclick="prevCard()" title="上一张">
<span class="arrow prev-arrow">‹</span>
</button>
<button class="side-nav-btn next-btn" id="sideNextBtn" onclick="nextCard()" title="下一张">
<span class="arrow next-arrow">›</span>
</button>
<!-- 主内容 -->
<div class="main">
<!-- 课程封面区域 -->
<div class="course-hero">
<div class="hero-badge">📚 本周课程</div>
<h1 class="hero-title">《基础回顾·OJ五题精讲》</h1>
<p class="hero-subtitle">C++信息奥赛 · 第1课</p>
<div class="hero-divider"></div>
<div class="hero-info">
<div class="hero-info-item"><span class="icon">📅</span><span>2026年9月5日</span></div>
<div class="hero-info-item"><span class="icon">⏰</span><span>周六 14:00-16:00</span></div>
<div class="hero-info-item"><span class="icon">👩‍🏫</span><span>橙子老师</span></div>
</div>
</div>
<!-- 学习目标 -->
<div class="goals-section">
<div class="goals-header">
<span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span>
<button class="goals-toggle" onclick="toggleGoals()">收起</button>
</div>
<ul class="goals-list" id="goalsList"><li><span class="goal-num">1</span><span class="goal-text">字符串处理与回文判断(ASCII大小写转换、双指针)</span></li><li><span class="goal-num">2</span><span class="goal-text">数组有序去重(快慢指针)</span></li><li><span class="goal-num">3</span><span class="goal-text">进制转换(除K取余、映射表0123456789ABCDEF)</span></li><li><span class="goal-num">4</span><span class="goal-text">二进制与位运算(拆位数1、2的幂/幸运数)</span></li><li><span class="goal-num">5</span><span class="goal-text">模拟与状态标记(约瑟夫报数游戏)</span></li></ul>
</div>
<!-- 学生卡片滑动区 -->
<div class="cards-slider-wrapper">
<div class="cards-slider" id="cardsSlider">
<div class="student-card active">
<div class="card-header">
<span class="student-name">郑子煜</span>
<span class="card-badge badge-normal">正常上课</span>
</div>
<div class="card-body">
<div class="feedback-content" data-student="郑子煜">新学期第一课态度认真、跟住老师节奏;尝试回文串和进制数位两道题都还差一点没通,假期后基础需要重新拾起,多复习基础概念、留意语法细节会更稳~</div>
<div class="oj-section" data-oj-section="郑子煜">
<div class="oj-header"><span>📊</span><span>OJ 做题数据 · 题目解析与错因</span></div>
<table class="oj-table">
<thead><tr><th>题目</th><th>状态</th><th style="text-align:center">提交次数</th><th style="text-align:center">思考模式</th><th>解析 / 为什么错</th></tr></thead>
<tbody><tr><td>S0401P1 小杨的回文串</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>CE</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>编译错误——分号/括号/变量名等语法细节未检查,先在本地编译通过</td></tr><tr><td>S0401P2 小杨有序去重</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P3 小杨的进制数位</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count">1</td><td class="oj-pattern">遇到困难</td><td>答案错误——进制转换"除K取余、余数倒序拼+0特判"细节未掌握</td></tr><tr><td>S0401A6 基础回顾-选择</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401A7 基础回顾-判断</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P4 小杨的幸运数字</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P5 小杨的报数游戏</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr></tbody>
</table>
<div class="oj-summary">
<div class="oj-summary-item"><span>完成:</span><span class="oj-summary-num">0/2</span></div>
<div class="oj-summary-item"><span>AC:</span><span class="oj-summary-num">0</span></div>
<div class="oj-summary-item"><span>总提交:</span><span class="oj-summary-num">3</span></div>
</div>
</div>
</div>
</div><div class="student-card">
<div class="card-header">
<span class="student-name">张雨禾</span>
<span class="card-badge badge-normal">正常上课</span>
</div>
<div class="card-body">
<div class="feedback-content" data-student="张雨禾">专注、坐得住,态度认真;尝试5题共10次提交,仅进制数位一次通过,其余多为审题粗心和语法小错,每天复习、写完自查会更好~</div>
<div class="oj-section" data-oj-section="张雨禾">
<div class="oj-header"><span>📊</span><span>OJ 做题数据 · 题目解析与错因</span></div>
<table class="oj-table">
<thead><tr><th>题目</th><th>状态</th><th style="text-align:center">提交次数</th><th style="text-align:center">思考模式</th><th>解析 / 为什么错</th></tr></thead>
<tbody><tr><td>S0401P1 小杨的回文串</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>答案错误——先数原串大小写个数再转,别转完再统计</td></tr><tr><td>S0401P2 小杨有序去重</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>CE</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>编译错误——语法细节未检查</td></tr><tr><td>S0401P3 小杨的进制数位</td><td><span class="oj-status ac"><span class="oj-status-icon">✓</span>AC</span></td><td class="oj-submit-count">1</td><td class="oj-pattern">一气呵成</td><td>进制数位一次过,掌握扎实</td></tr><tr><td>S0401A6 基础回顾-选择</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">3</td><td class="oj-pattern">反复调试</td><td>答案错误——选择/判断题多审题粗心、概念没记牢</td></tr><tr><td>S0401A7 基础回顾-判断</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>答案错误——判断题细节记牢</td></tr><tr><td>S0401P4 小杨的幸运数字</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P5 小杨的报数游戏</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr></tbody>
</table>
<div class="oj-summary">
<div class="oj-summary-item"><span>完成:</span><span class="oj-summary-num">1/5</span></div>
<div class="oj-summary-item"><span>AC:</span><span class="oj-summary-num">1</span></div>
<div class="oj-summary-item"><span>总提交:</span><span class="oj-summary-num">10</span></div>
</div>
</div>
</div>
</div><div class="student-card">
<div class="card-header">
<span class="student-name">苏俊宇</span>
<span class="card-badge badge-normal">正常上课</span>
</div>
<div class="card-body">
<div class="feedback-content" data-student="苏俊宇">认真专注,逻辑思维出色;回文串、有序去重两题一次通过、一气呵成,基础很扎实!把这份思路多落实到手上,再多写几题会更棒~</div>
<div class="oj-section" data-oj-section="苏俊宇">
<div class="oj-header"><span>📊</span><span>OJ 做题数据 · 题目解析与错因</span></div>
<table class="oj-table">
<thead><tr><th>题目</th><th>状态</th><th style="text-align:center">提交次数</th><th style="text-align:center">思考模式</th><th>解析 / 为什么错</th></tr></thead>
<tbody><tr><td>S0401P1 小杨的回文串</td><td><span class="oj-status ac"><span class="oj-status-icon">✓</span>AC</span></td><td class="oj-submit-count">1</td><td class="oj-pattern">一气呵成</td><td>回文判断一次过,思路清晰</td></tr><tr><td>S0401P2 小杨有序去重</td><td><span class="oj-status ac"><span class="oj-status-icon">✓</span>AC</span></td><td class="oj-submit-count">1</td><td class="oj-pattern">一气呵成</td><td>快慢指针去重一次过,掌握扎实</td></tr><tr><td>S0401P3 小杨的进制数位</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401A6 基础回顾-选择</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401A7 基础回顾-判断</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P4 小杨的幸运数字</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P5 小杨的报数游戏</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr></tbody>
</table>
<div class="oj-summary">
<div class="oj-summary-item"><span>完成:</span><span class="oj-summary-num">2/2</span></div>
<div class="oj-summary-item"><span>AC:</span><span class="oj-summary-num">2</span></div>
<div class="oj-summary-item"><span>总提交:</span><span class="oj-summary-num">2</span></div>
</div>
</div>
</div>
</div><div class="student-card">
<div class="card-header">
<span class="student-name">鲍佳音</span>
<span class="card-badge badge-normal">正常上课</span>
</div>
<div class="card-body">
<div class="feedback-content" data-student="鲍佳音">欢迎佳音加入CSP04班!第一次上课就很投入、态度认真;主动尝试5题共10次提交,进制数位一次通过,思维底子不错,继续加油~</div>
<div class="oj-section" data-oj-section="鲍佳音">
<div class="oj-header"><span>📊</span><span>OJ 做题数据 · 题目解析与错因</span></div>
<table class="oj-table">
<thead><tr><th>题目</th><th>状态</th><th style="text-align:center">提交次数</th><th style="text-align:center">思考模式</th><th>解析 / 为什么错</th></tr></thead>
<tbody><tr><td>S0401P1 小杨的回文串</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>答案错误——先数原串大小写个数再转</td></tr><tr><td>S0401P2 小杨有序去重</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>答案错误——快慢指针细节待练</td></tr><tr><td>S0401P3 小杨的进制数位</td><td><span class="oj-status ac"><span class="oj-status-icon">✓</span>AC</span></td><td class="oj-submit-count">1</td><td class="oj-pattern">一气呵成</td><td>进制数位一次过,基础不错</td></tr><tr><td>S0401A6 基础回顾-选择</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">3</td><td class="oj-pattern">反复调试</td><td>答案错误——概念/审题细节</td></tr><tr><td>S0401A7 基础回顾-判断</td><td><span class="oj-status wa"><span class="oj-status-icon">✗</span>WA</span></td><td class="oj-submit-count highlight">2</td><td class="oj-pattern">遇到困难</td><td>答案错误——判断题细节</td></tr><tr><td>S0401P4 小杨的幸运数字</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr><tr><td>S0401P5 小杨的报数游戏</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>未提交(课上未做)</td></tr></tbody>
</table>
<div class="oj-summary">
<div class="oj-summary-item"><span>完成:</span><span class="oj-summary-num">1/5</span></div>
<div class="oj-summary-item"><span>AC:</span><span class="oj-summary-num">1</span></div>
<div class="oj-summary-item"><span>总提交:</span><span class="oj-summary-num">10</span></div>
</div>
</div>
</div>
</div><div class="student-card">
<div class="card-header">
<span class="student-name">卢华琛</span>
<span class="card-badge badge-absent">请假</span>
</div>
<div class="card-body">
<div class="feedback-content" data-student="卢华琛">本周因事请假未到课。请在家复习上学期基础知识,有空到OJ看看《基础回顾》题目,为下节课做好准备;如需补课可联系老师安排。</div>
<div class="oj-section" data-oj-section="卢华琛">
<div class="oj-header"><span>📊</span><span>OJ 做题数据 · 题目解析与错因</span></div>
<table class="oj-table">
<thead><tr><th>题目</th><th>状态</th><th style="text-align:center">提交次数</th><th style="text-align:center">思考模式</th><th>解析 / 为什么错</th></tr></thead>
<tbody><tr><td>S0401P1 小杨的回文串</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401P2 小杨有序去重</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401P3 小杨的进制数位</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401A6 基础回顾-选择</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401A7 基础回顾-判断</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401P4 小杨的幸运数字</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr><tr><td>S0401P5 小杨的报数游戏</td><td><span class="oj-status pending">未提交</span></td><td class="oj-submit-count">0</td><td class="oj-pattern">-</td><td>请假未到课</td></tr></tbody>
</table>
<div class="oj-summary">
<div class="oj-summary-item"><span>完成:</span><span class="oj-summary-num">0/0</span></div>
<div class="oj-summary-item"><span>AC:</span><span class="oj-summary-num">0</span></div>
<div class="oj-summary-item"><span>总提交:</span><span class="oj-summary-num">0</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 导航控制 -->
<div class="nav-controls">
<span class="page-indicator" id="pageIndicator">1 / N</span>
</div>
<!-- 进度点 -->
<div class="progress-dots" id="progressDots">
<div class="progress-dot active" onclick="goToCard(0)"></div><div class="progress-dot" onclick="goToCard(1)"></div><div class="progress-dot" onclick="goToCard(2)"></div><div class="progress-dot" onclick="goToCard(3)"></div><div class="progress-dot" onclick="goToCard(4)"></div>
</div>
<div class="footer">穹狼科创 · CSP04班 · 橙子老师</div>
</div>
<!-- 底部操作栏 -->
<div class="bottom-bar" id="bottomBar" style="display: none;">
<button class="btn btn-outline" onclick="cancelEdit()">取消</button>
<button class="btn btn-success" onclick="saveEdit()">✓ 保存修改</button>
</div>
<!-- 提示条 -->
<div class="toast" id="toast"></div>
<script>
let currentCard = 0;
const totalCards = 5;
const allCards = document.querySelectorAll('.student-card');
const sidePrevBtn = document.getElementById('sidePrevBtn');
const sideNextBtn = document.getElementById('sideNextBtn');
const pageIndicator = document.getElementById('pageIndicator');
const progressDots = document.querySelectorAll('.progress-dot');
function updateSlider() {
allCards.forEach(function(card, i) {
card.classList.remove('active', 'prev');
if (i === currentCard) { card.classList.add('active'); }
else if (i < currentCard) { card.classList.add('prev'); }
});
pageIndicator.textContent = (currentCard + 1) + ' / ' + totalCards;
sidePrevBtn.disabled = currentCard === 0;
sideNextBtn.disabled = currentCard === totalCards - 1;
progressDots.forEach(function(dot, i) { dot.classList.toggle('active', i === currentCard); });
}
function nextCard() { if (currentCard < totalCards - 1) { currentCard++; updateSlider(); } }
function prevCard() { if (currentCard > 0) { currentCard--; updateSlider(); } }
function goToCard(i) { currentCard = i; updateSlider(); }
document.addEventListener('keydown', function(e) {
if (e.key === 'ArrowLeft') prevCard();
if (e.key === 'ArrowRight') nextCard();
});
var touchStartX = 0;
var sliderEl = document.getElementById('cardsSlider');
sliderEl.addEventListener('touchstart', function(e) { touchStartX = e.changedTouches[0].screenX; });
sliderEl.addEventListener('touchend', function(e) {
var dx = e.changedTouches[0].screenX;
if (touchStartX - dx > 50) nextCard();
if (dx - touchStartX > 50) prevCard();
});
updateSlider();
function toggleGoals() {
var list = document.getElementById('goalsList');
var btn = document.querySelector('.goals-toggle');
list.classList.toggle('collapsed');
btn.textContent = list.classList.contains('collapsed') ? '展开' : '收起';
}
var originalContent = {};
var originalMetrics = {};
var isEditMode = false;
function toggleEdit() {
isEditMode = !isEditMode;
var feedbacks = document.querySelectorAll('.feedback-content');
var metricComments = document.querySelectorAll('.metric-comment');
var starRatings = document.querySelectorAll('.star-rating');
var editBtn = document.getElementById('editBtn');
var editBadge = document.getElementById('editBadge');
var bottomBar = document.getElementById('bottomBar');
if (isEditMode) {
feedbacks.forEach(function(el) { originalContent[el.dataset.student] = el.innerHTML; });
metricComments.forEach(function(el) {
var key = el.closest('.student-card').querySelector('.student-name').textContent + '-' + el.dataset.metricComment;
originalMetrics[key] = { text: el.innerHTML, score: 0 };
});
starRatings.forEach(function(el) {
var key = el.closest('.student-card').querySelector('.student-name').textContent + '-' + el.closest('.metric-item').dataset.metric;
if (originalMetrics[key]) originalMetrics[key].score = el.dataset.score;
});
feedbacks.forEach(function(el) { el.contentEditable = true; });
metricComments.forEach(function(el) { el.contentEditable = true; });
starRatings.forEach(function(el) { el.classList.add('editable'); });
editBtn.textContent = '✏️ 退出编辑';
editBadge.classList.add('show');
bottomBar.style.display = 'flex';
showToast('编辑模式已开启,点击文字或星星即可修改');
} else {
feedbacks.forEach(function(el) { el.contentEditable = false; });
metricComments.forEach(function(el) { el.contentEditable = false; });
starRatings.forEach(function(el) { el.classList.remove('editable'); });
editBtn.textContent = '✏️ 编辑';
editBadge.classList.remove('show');
bottomBar.style.display = 'none';
}
}
function saveEdit() {
isEditMode = false;
document.querySelectorAll('.feedback-content').forEach(function(el) { el.contentEditable = false; });
document.querySelectorAll('.metric-comment').forEach(function(el) { el.contentEditable = false; });
document.querySelectorAll('.star-rating').forEach(function(el) { el.classList.remove('editable'); });
document.getElementById('editBtn').textContent = '✏️ 编辑';
document.getElementById('editBadge').classList.remove('show');
document.getElementById('bottomBar').style.display = 'none';
originalContent = {};
originalMetrics = {};
showToast('✓ 修改已保存');
}
function cancelEdit() {
isEditMode = false;
document.querySelectorAll('.feedback-content').forEach(function(el) {
if (originalContent[el.dataset.student]) el.innerHTML = originalContent[el.dataset.student];
el.contentEditable = false;
});
document.querySelectorAll('.metric-comment').forEach(function(el) {
var key = el.closest('.student-card').querySelector('.student-name').textContent + '-' + el.dataset.metricComment;
if (originalMetrics[key]) el.innerHTML = originalMetrics[key].text;
el.contentEditable = false;
});
document.querySelectorAll('.star-rating').forEach(function(el) {
var key = el.closest('.student-card').querySelector('.student-name').textContent + '-' + el.closest('.metric-item').dataset.metric;
if (originalMetrics[key]) setStarRating(el, parseInt(originalMetrics[key].score));
el.classList.remove('editable');
});
document.getElementById('editBtn').textContent = '✏️ 编辑';
document.getElementById('editBadge').classList.remove('show');
document.getElementById('bottomBar').style.display = 'none';
originalContent = {};
originalMetrics = {};
showToast('已恢复原始内容');
}
function exportText() {
var text = '第1周周六下午CSP04班课评\n';
text += '2026年9月5日 · 《基础回顾·OJ五题精讲》 · 橙子老师\n';
text += '═══════════════════════════════════════\n\n';
text += '🎯 本周知识点\n';
text += '─────────────────────────────────────\n';
text += '1. 字符串处理与回文判断(ASCII大小写转换、双指针)\n2. 数组有序去重(快慢指针)\n3. 进制转换(除K取余、映射表0123456789ABCDEF)\n4. 二进制与位运算(拆位数1、2的幂/幸运数)\n5. 模拟与状态标记(约瑟夫报数游戏)\n\n';
text += '═══════════════════════════════════════\n\n';
document.querySelectorAll('.student-card').forEach(function(card) {
var name = card.querySelector('.student-name').textContent;
var badge = card.querySelector('.card-badge').textContent;
var feedback = card.querySelector('.feedback-content').innerText;
text += '【' + name + '】' + badge + '\n';
text += '─────────────────────────────────\n';
text += feedback + '\n\n';
card.querySelectorAll('.metric-item').forEach(function(m) {
var label = m.querySelector('.metric-label').textContent;
var rating = m.querySelector('.star-rating');
var score = parseInt(rating.dataset.score);
var scoreLabels = ['未评', '⭐', '⭐⭐', '⭐⭐⭐', '⭐⭐⭐⭐', '⭐⭐⭐⭐⭐'];
var stars = scoreLabels[score] || '未评';
var comment = m.querySelector('.metric-comment').innerText.trim();
if (comment === '点击编辑评语...') comment = '';
text += ' ' + label + ':' + stars;
if (comment) text += '(' + comment + ')';
text += '\n';
});
text += '\n';
});
navigator.clipboard.writeText(text).then(function() {
showToast('✓ 已复制到剪贴板,可直接粘贴发送');
}).catch(function() {
var ta = document.createElement('textarea');
ta.value = text; document.body.appendChild(ta); ta.select();
document.execCommand('copy'); document.body.removeChild(ta);
showToast('✓ 已复制到剪贴板');
});
}
function showToast(msg) {
var toast = document.getElementById('toast');
toast.textContent = msg;
toast.classList.add('show');
setTimeout(function() { toast.classList.remove('show'); }, 2000);
}
</script>
</body>
</html>

View File

@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
# 将第33周综合课评页替换为 8月12-13日 两天专属(4课)
import io
path = 'output/课评汇总/第33周穹狼传奇&小龙虾综合课评_0812-0813.html'
block1 = ''' <!-- ═══════ 区块1:穹狼传奇 8-12 第3课 ═══════ -->
<div class="course-block">
<div class="course-hero">
<div class="hero-badge">🐺 穹狼传奇班</div>
<h1 class="hero-title">《精灵图动作播放器与小怪素材》</h1>
<p class="hero-subtitle">AI创意编程 · 第3课</p>
<div class="hero-divider"></div>
<div class="hero-info">
<div class="hero-info-item"><span class="icon">📅</span><span>2026年8月12日</span></div>
<div class="hero-info-item"><span class="icon">⏰</span><span>上午 09:00</span></div>
<div class="hero-info-item"><span class="icon">👩‍🏫</span><span>橙子老师</span></div>
</div>
</div>
<div class="goals-section"><div class="goals-header"><span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span><button class="goals-toggle" onclick="toggleGoals(this)">收起</button></div><ul class="goals-list"><li><span class="goal-num">1</span><span class="goal-text">让AI写需求文档:用"计划模式"(先出方案、不写代码)规划功能,审核后再开工</span></li><li><span class="goal-num">2</span><span class="goal-text">精灵图布局规范:图片两排排列、尺寸统一</span></li><li><span class="goal-num">3</span><span class="goal-text">精灵图动作播放器:上传素材即可预览动作播放</span></li><li><span class="goal-num">4</span><span class="goal-text">生成小怪素材:用提示词让AI生图、AI抠图去背景</span></li><li><span class="goal-num">5</span><span class="goal-text">素材精修归档:提示词放创作台精修,素材统一管理</span></li></ul></div>
<div class="cards-slider-wrapper">
<div class="cards-slider">
<div class="student-card active" data-key="haolin-0812"><div class="card-header"><span class="student-name">卢皓霖</span><span class="card-badge badge-normal">正常上课</span></div><div class="card-body"><div class="feedback-content" data-student="卢皓霖">皓霖家长好,本周学习的内容是《精灵图动作播放器与小怪素材》:<br>1. 让AI写需求文档:用"计划模式"(先出方案、不写代码)规划功能,审核后再开工<br>2. 精灵图布局规范:图片两排排列、尺寸统一<br>3. 精灵图动作播放器:上传素材即可预览动作播放<br>4. 生成小怪素材:用提示词让AI生图、AI抠图去背景<br>5. 素材精修归档:提示词放创作台精修,素材统一管理<br><br>昨天皓霖一口气做了22种动作精灵图,今天就把它们用起来啦~开始做"精灵图动作播放器",还学会让AI先写需求文档、审核之后再动手,做事的流程感越来越强!💪<br><br>今天还挑战了新任务:生成游戏的小怪角色!他让AI生成了"橘子怪",学会用AI抠图把背景去掉。遇到白底没抠干净,皓霖一点不慌,老师一提醒就自己调整过来了——这种不怕小麻烦的好心态,学编程特别珍贵!还学会把生图提示词放到创作台(AI生图的编辑工作区)里精修,素材越做越精致。😊<br><br>课堂上偶尔聊到游戏会走神,不过老师一提醒,皓霖马上就能回到任务上,这份"能收回来"的能力很棒!下次我们把任务切成两三小步,每完成一步击个掌,专注一小段、歇一小段,效率会更稳哟~<br><br>回家可以请皓霖打开"橘子怪"给你们看看,让他讲讲怎么让AI生图、又怎么把白底抠掉的——能讲清楚,就说明真的学会啦~明天做第一关地图,把精灵和小怪都用起来!老师会继续关注皓霖的表现,期待看到更多精彩!🌟💡</div><div class="metrics"><div class="metric-item" data-metric="课堂互动"><div class="metric-label">课堂互动</div><div class="star-rating editable" data-score="4"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">优秀</span></div><div class="metric-comment" data-metric-comment="课堂互动">学会"计划模式"让AI先写需求文档,主动和老师配合打磨素材;聊到游戏会走神,但一提醒能收回</div></div><div class="metric-item" data-metric="专注度"><div class="metric-label">专注度</div><div class="star-rating editable" data-score="3"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">良好</span></div><div class="metric-comment" data-metric-comment="专注度">偶尔聊游戏走神,老师提醒后能马上回到任务</div></div><div class="metric-item" data-metric="作品完成"><div class="metric-label">作品完成</div><div class="star-rating editable" data-score="4"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">优秀</span></div><div class="metric-comment" data-metric-comment="作品完成">把22种精灵图做成动作播放器,还生成"橘子怪"素材、学会AI抠图去背景</div></div><div class="metric-item" data-metric="知识点掌握"><div class="metric-label">知识点掌握</div><div class="star-rating editable" data-score="4"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">优秀</span></div><div class="metric-comment" data-metric-comment="知识点掌握">掌握需求文档先行、AI抠图、提示词精修;素材统一归档还需巩固</div></div></div></div></div>
</div>
</div>
</div>
'''
block2 = ''' <!-- ═══════ 区块2:小龙虾 8-12 第3课 ═══════ -->
<div class="course-block">
<div class="course-hero">
<div class="hero-badge">🦞 AICODE小龙虾班</div>
<h1 class="hero-title">《AI创意写作·修仙爽文《战临九天》》</h1>
<p class="hero-subtitle">AI创意编程 · 第3课</p>
<div class="hero-divider"></div>
<div class="hero-info">
<div class="hero-info-item"><span class="icon">📅</span><span>2026年8月12日</span></div>
<div class="hero-info-item"><span class="icon">⏰</span><span>下午</span></div>
<div class="hero-info-item"><span class="icon">👩‍🏫</span><span>橙子老师</span></div>
</div>
</div>
<div class="goals-section"><div class="goals-header"><span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span><button class="goals-toggle" onclick="toggleGoals(this)">收起</button></div><ul class="goals-list"><li><span class="goal-num">1</span><span class="goal-text">故事设定共创:把想要的题材、主角、金手指(随身空间+前世记忆)用清晰的话告诉AI,AI帮忙整理成大纲</span></li><li><span class="goal-num">2</span><span class="goal-text">力量体系设计:给故事定"武道八境"境界体系(武者→武师→武灵→武王→武宗→武尊→武圣→武帝),让世界规则自洽</span></li><li><span class="goal-num">3</span><span class="goal-text">角色与伏笔设计:废柴主角、随身老爷爷、部族覆灭之谜、天赋被父亲封印,每个角色背后都藏着钩子</span></li><li><span class="goal-num">4</span><span class="goal-text">剧情逻辑自查:发现设定前后矛盾就大胆提出质疑,核对原文、修改设定,让故事经得起推敲</span></li><li><span class="goal-num">5</span><span class="goal-text">作品网页化:把写好的小说做成单文件阅读网页,目录导航、明暗主题、字号调节,新章节随时加</span></li></ul></div>
<div class="cards-slider-wrapper">
<div class="cards-slider">
<div class="student-card active" data-key="junmian-0812"><div class="card-header"><span class="student-name">赵俊棉</span><span class="card-badge badge-normal">正常上课</span></div><div class="card-body"><div class="feedback-content" data-student="赵俊棉">俊棉家长好,本周学习的内容是《AI创意写作·修仙爽文《战临九天》》:<br>1. 故事设定共创:把想要的题材、主角、金手指(随身空间+前世记忆)用清晰的话告诉AI,AI帮忙整理成大纲<br>2. 力量体系设计:给故事定"武道八境"境界体系(武者→武师→武灵→武王→武宗→武尊→武圣→武帝),让世界规则自洽<br>3. 角色与伏笔设计:废柴主角、随身老爷爷、部族覆灭之谜、天赋被父亲封印,每个角色背后都藏着钩子<br>4. 剧情逻辑自查:发现设定前后矛盾就大胆提出质疑,核对原文、修改设定,让故事经得起推敲<br>5. 作品网页化:把写好的小说做成单文件阅读网页,目录导航、明暗主题、字号调节,新章节随时加<br><br>俊棉今天从"网页主编"升级成"故事主笔",书名、主角名、"武道八境"境界体系都是他自己拍板的,主人翁意识特别强~📖<br><br>最让老师惊喜的是他把"较真"用在了剧情逻辑上:第一章里他发现"16岁便突破炼气九层"和"先测灵根再修炼"的设定对不上(按故事设定,修炼要先测灵根、再一步步突破境界),直接提出"这个地方是不是不太对?",老师当场把第一章原文调出来一起核对修正——会自己审查自己故事逻辑,这就是作者思维💡<br><br>下午他一句"继续",AI就连着写出了第4-6章:破境武师、大比一拳镇场、硬抗武灵楚枫,一波接一波的爽快反转;他还把小说做成了网页版,目录导航、明暗主题、字号调节都有~<br><br>比起第2课"做完要检查、让AI迭代",这一课他更进一层,会主动找剧情漏洞,进步很明显~下节课老师想请俊棉当"小编剧",把《战临九天》的开篇讲给您听~<br><br>回家可以玩一个小游戏:让俊棉当"作者"、您当"读者",读完一段问他"下一章会发生什么",看他把伏笔怎么接回来~<br><br>老师会继续关注俊棉的表现,期待看到更多精彩!🌟💡</div><div class="metrics"><div class="metric-item" data-metric="课堂互动"><div class="metric-label">课堂互动</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="课堂互动">主人翁意识强,书名、主角、"武道八境"全自己拍板,主动质疑剧情设定</div></div><div class="metric-item" data-metric="专注度"><div class="metric-label">专注度</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="专注度">整节课全程主导故事创作,专注投入</div></div><div class="metric-item" data-metric="作品完成"><div class="metric-label">作品完成</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="作品完成">完成《战临九天》世界观设定+续写第4-6章+网页版阅读器</div></div><div class="metric-item" data-metric="知识点掌握"><div class="metric-label">知识点掌握</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="知识点掌握">把"剧情逻辑自查"用到极致,会审查自己故事逻辑</div></div></div></div></div>
</div>
</div>
</div>
'''
block3 = ''' <!-- ═══════ 区块3:穹狼传奇 8-13 第4课 ═══════ -->
<div class="course-block">
<div class="course-hero">
<div class="hero-badge">🐺 穹狼传奇班</div>
<h1 class="hero-title">《AI生成游戏地图——橙城第一关》</h1>
<p class="hero-subtitle">AI创意编程 · 第4课</p>
<div class="hero-divider"></div>
<div class="hero-info">
<div class="hero-info-item"><span class="icon">📅</span><span>2026年8月13日</span></div>
<div class="hero-info-item"><span class="icon">⏰</span><span>上午 09:00</span></div>
<div class="hero-info-item"><span class="icon">👩‍🏫</span><span>橙子老师</span></div>
</div>
</div>
<div class="goals-section"><div class="goals-header"><span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span><button class="goals-toggle" onclick="toggleGoals(this)">收起</button></div><ul class="goals-list"><li><span class="goal-num">1</span><span class="goal-text">用文字向AI描述想要的地图场景(横版过关、草原、关卡设计)</span></li><li><span class="goal-num">2</span><span class="goal-text">让AI先给出地图提示词,再用于生图</span></li><li><span class="goal-num">3</span><span class="goal-text">把提示词粘贴到游戏工坊的背景生成功能出图</span></li><li><span class="goal-num">4</span><span class="goal-text">一张一张生成地图(先生成第一关)</span></li><li><span class="goal-num">5</span><span class="goal-text">把生成好的地图图片分类保存好</span></li></ul></div>
<div class="cards-slider-wrapper">
<div class="cards-slider">
<div class="student-card active" data-key="haolin-0813"><div class="card-header"><span class="student-name">卢皓霖</span><span class="card-badge badge-normal">正常上课</span></div><div class="card-body"><div class="feedback-content" data-student="卢皓霖">皓霖家长好,本周学习的内容是《AI生成游戏地图——橙城第一关》:<br>1. 用文字向AI描述想要的地图场景(横版过关、草原、关卡设计)<br>2. 让AI先给出地图提示词,再用于生图<br>3. 把提示词粘贴到游戏工坊的背景生成功能出图<br>4. 一张一张生成地图(先生成第一关)<br>5. 把生成好的地图图片分类保存好<br><br>今天皓霖继续"穹狼传奇"游戏开发,第一关"橙城"地图终于做出来啦~前几课做的精灵图和小怪素材,这下有了自己的舞台!他学会先向AI描述想要的地图("在草原上,前面是一个城"),让AI先给提示词、再粘贴到背景生成里出图。😊<br><br>"让AI先给提示词"这步今天刚突破——一开始还没摸到方法,我们一起试了两三次就找到了,遇到卡壳不放弃、反复调整。这节课完全是皓霖自己在动手,老师只在旁边递工具,说明他已经能独立走通"描述→提示词→生图"的完整流程啦!💪<br><br>作品特别完整:第一关"橙城"加5张场景图都分门别类放好了,还做成"橙城·第一关 地图陈列"展示页,闯关页面也有雏形,越来越有模有样!🌟<br><br>课堂小提醒:皓霖偶尔会坐不住、爱聊游戏,但老师一提醒马上能回到任务。下节课让角色真正走进"橙城"地图走起来!<br><br>🏠 回家任务(2分钟):打开地图陈列页,让皓霖讲讲地图怎么一步步做出来的,重点说说"先要提示词"这步;再问问他第一关为什么选草原~<br><br>老师会继续关注皓霖的表现,期待看到更多精彩!🌟💡</div><div class="metrics"><div class="metric-item" data-metric="课堂互动"><div class="metric-label">课堂互动</div><div class="star-rating editable" data-score="4"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">优秀</span></div><div class="metric-comment" data-metric-comment="课堂互动">整节课基本独立动手,老师只在旁边递工具</div></div><div class="metric-item" data-metric="专注度"><div class="metric-label">专注度</div><div class="star-rating editable" data-score="3"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">良好</span></div><div class="metric-comment" data-metric-comment="专注度">偶尔坐不住、爱聊游戏,但老师一提醒能回到任务</div></div><div class="metric-item" data-metric="作品完成"><div class="metric-label">作品完成</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="作品完成">完成"橙城"第一关地图+5张场景图+地图陈列展示页+闯关页雏形</div></div><div class="metric-item" data-metric="知识点掌握"><div class="metric-label">知识点掌握</div><div class="star-rating editable" data-score="4"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">优秀</span></div><div class="metric-comment" data-metric-comment="知识点掌握">突破"让AI先给提示词",独立走通"描述→提示词→生图"完整流程</div></div></div></div></div>
</div>
</div>
</div>
'''
block4 = ''' <!-- ═══════ 区块4:小龙虾 8-13 第4课 ═══════ -->
<div class="course-block">
<div class="course-hero">
<div class="hero-badge">🦞 AICODE小龙虾班</div>
<h1 class="hero-title">《AI作品集·我的个人主页》</h1>
<p class="hero-subtitle">AI创意编程 · 第4课</p>
<div class="hero-divider"></div>
<div class="hero-info">
<div class="hero-info-item"><span class="icon">📅</span><span>2026年8月13日</span></div>
<div class="hero-info-item"><span class="icon">⏰</span><span>下午</span></div>
<div class="hero-info-item"><span class="icon">👩‍🏫</span><span>橙子老师</span></div>
</div>
</div>
<div class="goals-section"><div class="goals-header"><span class="goals-title"><span class="title-icon">🎯</span>本周知识点</span><button class="goals-toggle" onclick="toggleGoals(this)">收起</button></div><ul class="goals-list"><li><span class="goal-num">1</span><span class="goal-text">需求表达:用清晰的话告诉AI"我要一个介绍自己的主页",把想法说具体</span></li><li><span class="goal-num">2</span><span class="goal-text">个人介绍组织:把"我是谁、我喜欢做什么"整理成给AI的素材</span></li><li><span class="goal-num">3</span><span class="goal-text">作品集导航:一个主页集中放项目卡片,点击即可跳转到猜名字/冷笑话/小说等作品</span></li><li><span class="goal-num">4</span><span class="goal-text">页面优化迭代:让AI调背景图、加内容、改布局,多轮打磨到满意</span></li><li><span class="goal-num">5</span><span class="goal-text">项目串联:把前3课的游戏、网页、故事串成一个完整的个人作品集</span></li></ul></div>
<div class="cards-slider-wrapper">
<div class="cards-slider">
<div class="student-card active" data-key="junmian-0813"><div class="card-header"><span class="student-name">赵俊棉</span><span class="card-badge badge-normal">正常上课</span></div><div class="card-body"><div class="feedback-content" data-student="赵俊棉">俊棉家长好,本周学习的内容是《AI作品集·我的个人主页》:<br>1. 需求表达:用清晰的话告诉AI"我要一个介绍自己的主页",把想法说具体<br>2. 个人介绍组织:把"我是谁、我喜欢做什么"整理成给AI的素材<br>3. 作品集导航:一个主页集中放项目卡片,点击即可跳转到猜名字/冷笑话/小说等作品<br>4. 页面优化迭代:让AI调背景图、加内容、改布局,多轮打磨到满意<br>5. 项目串联:把前3课的游戏、网页、故事串成一个完整的个人作品集<br><br>俊棉今天当上了"作品集策展人"——把前3天做的猜名字游戏、冷笑话网页和《战临九天》小说,全部收进一个属于自己的个人主页,点卡片就能跳转,再也不用翻文件夹啦~🎉<br><br>主页处处是细节:首页是"你好呀,我是土逗"(俊棉给自己起的名字)的自我介绍,往下是6张特质卡,用小龙虾红的暗色主题、滚动入场动画和手机端适配,连网页图标都是一只小龙虾🦞;他还把"鱼航员嘉年华"图片做成了猜名字游戏的背景,让旧作品焕然一新~<br><br>今天他的"作品力"也在涨:一句"继续",AI就把《战临九天》从第6章写到第13章,越写越起劲;"较真"也跟着升级——第2课对玩法较真、第3课对剧情较真,这一课较真到了代码上:小说封面(初版)显示"0章"、点不进去,他和老师一起排查,发现是章节简介里的引号把代码截断了,修好后还总结出"以后加章节要检查引号"的小规则——从"用AI做内容"到"会修AI生成的网页",工程思维在悄悄发芽💪<br><br>下节课老师想请俊棉当"首席讲解员",打开作品集把这4天的成长讲给家长听;回家可以先来一场"策展人导览":让孩子从主页点进3个作品,每件用一句话介绍"这是什么、我怎么做出来的",家长当观众、问"这个怎么玩""哪件最得意"就好~平时在家,也多让俊棉自己开口把想法说给AI听,新点子都会从他嘴里长出来~<br><br>老师会继续关注俊棉的表现,期待看到更多精彩!🌟💡</div><div class="metrics"><div class="metric-item" data-metric="课堂互动"><div class="metric-label">课堂互动</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="课堂互动">当"作品集策展人",主动排查修复代码bug并总结规则</div></div><div class="metric-item" data-metric="专注度"><div class="metric-label">专注度</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="专注度">整节课专注打磨个人主页,细节拉满</div></div><div class="metric-item" data-metric="作品完成"><div class="metric-label">作品完成</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="作品完成">完成个人作品集主页(个人介绍+6特质卡+作品跳转)+续写小说第7-13章</div></div><div class="metric-item" data-metric="知识点掌握"><div class="metric-label">知识点掌握</div><div class="star-rating editable" data-score="5"><span class="star" data-val="1">★</span><span class="star" data-val="2">★</span><span class="star" data-val="3">★</span><span class="star" data-val="4">★</span><span class="star" data-val="5">★</span><span class="star-score">超棒</span></div><div class="metric-comment" data-metric-comment="知识点掌握">从"用AI做内容"到"会修AI生成的网页",工程思维悄悄发芽</div></div></div></div></div>
</div>
</div>
</div>
'''
new_blocks = block1 + block2 + block3 + block4
s = io.open(path, encoding='utf-8').read()
start = s.index('<!-- ═══════ 区块1')
end = s.index(' <div class="footer">')
s2 = s[:start] + new_blocks + s[end:]
io.open(path, 'w', encoding='utf-8', newline='').write(s2)
print('replaced bytes:', end - start, '->', len(new_blocks))
print('ok')

View File

@@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
"""Assemble per-problem teaching data (题目 statement + 参考答案 + 解析要点) for
CSP04 lesson 01. Reference code read from C++代码/CSP04/01/*.cpp (GBK)."""
import json, io
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent.parent.parent
CODE_DIR = ROOT / 'C++代码' / 'CSP04' / '01'
def read_code(fname):
for enc in ('gbk', 'gb18030', 'utf-8'):
try:
p = CODE_DIR / fname
if not p.exists():
return ''
return io.open(p, encoding=enc).read().strip()
except Exception:
continue
return ''
# 每题:题目在问什么 + 关键点(解析)
PROBLEMS = {
'S0401P1': {
'title': '小杨的回文串',
'statement': '给定一个只含英文字母、大小写混合的字符串,问三件事:①把所有字母统一转小写后,它是不是回文串(是Yes/否No);②原串里有多少个大写字母;③原串里有多少个小写字母。回文就是正读倒读一样,如 abba、abcba。',
'key_points': '先统计后转换(统计的是原串的大写/小写个数);大写字母 +32 = 小写字母;用双指针 l/r 向中间夹,发现一次不相等就判否;三行输出顺序是 回文结果/大写个数/小写个数。',
'code_file': '小杨的回文串.cpp',
},
'S0401P2': {
'title': '小杨有序去重',
'statement': '给定一份非降序的成绩单(相邻可能相等),去掉连续的重复成绩,得到“出现过的不同成绩”列表。用双指针在数组上原地完成:慢指针 j 指向已保留部分的末尾,快指针 i 向后扫,遇到 a[i] ≠ a[j] 就把 a[i] 复制到 a[j+1]。输出两行:去重后的列表;不同成绩的个数。',
'key_points': '前提是“有序”,只去相邻重复;比较对象是 a[j](保留区末尾),不是 a[i-1];j 从 1 开始、i 从 2 开始(第一个数无条件保留);n 最大 1e5,必须一遍扫完。',
'code_file': '小杨有序去重.cpp',
},
'S0401P3': {
'title': '小杨的进制数位',
'statement': '把十进制数 n 转换成 k 进制(2≤k≤16),并统计表示里的字符构成:①k 进制表示(超过 9 的数位用大写 A~F 表示 10~15);②表示中数字字符(0~9)的个数;③表示中字母字符(A~F)的个数。',
'key_points': '除 k 取余、余数倒着拼(out = S[余数] + out);查表 “0123456789ABCDEF”;n=0 要特判输出 0;统计的是 k 进制表示里的字符,不是十进制原数。',
'code_file': '小杨的进制数位.cpp',
},
'S0401P4': {
'title': '小杨的幸运数字',
'statement': '有些正整数的二进制表示里恰好只有 1 个 1(如 1=1、2=10、8=1000),这样的数叫“幸运数”,也就是 2 的幂。给 n 个正整数,统计:①这 n 个数里幸运数的个数;②这 n 个数的二进制表示中 1 的总个数。',
'key_points': '对每个数单独数它的 1 的个数(cnt1 每轮要清零);sum 累计的是“1 的个数”,cnt 累计的是“满足条件的数”,别混;1(=2^0)也是幸运数;进阶可用 n&(n-1)==0 判断/__builtin_popcount 数 1。',
'code_file': '小杨的幸运数字.cpp',
},
'S0401P5': {
'title': '小杨的报数游戏',
'statement': 'n 个小朋友围成一圈,编号 1~n。从 1 号开始沿顺时针从 1 报数,报到 k 的小朋友出列,出列者下一位重新从 1 报数……直到全部出列。按出列顺序输出编号(约瑟夫问题)。',
'key_points': '数组 arr[i] 记状态(0 在场/1 出列);只有 arr[idx]==0 的人才报数;报满 k 出列后 cnt 归零、p--;idx 越界就回绕 idx>n→idx=1;边界 k=1 依次出列 1 2 3…n。',
'code_file': '小杨的报数游戏.cpp',
},
}
out = {}
for pid, meta in PROBLEMS.items():
code = read_code(meta['code_file'])
out[pid] = {
'key': pid + ' ' + meta['title'],
'title': meta['title'],
'statement': meta['statement'],
'key_points': meta['key_points'],
'code_file': meta['code_file'],
'ref_code': code,
}
dest = ROOT / '.claude' / 'memory' / 'temp' / 'problems_meta.json'
dest.parent.mkdir(parents=True, exist_ok=True)
dest.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding='utf-8')
print('SAVED ->', dest)
for pid, meta in out.items():
print(pid, 'ref_code_len=', len(meta['ref_code']))

View File

@@ -0,0 +1,140 @@
# -*- coding: utf-8 -*-
"""
Fetch final submission code per (student, problem) for CSP04 lesson 01 (基础回顾).
Targets both CSP04 sections (0830 & 1400). Saves to JSON.
"""
import io, sys, json, re, httpx
from collections import defaultdict
from pathlib import Path
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent.parent
env = {}
for line in (PROJECT_ROOT / '.env').read_text(encoding='utf-8').split('\n'):
line = line.strip()
if line and not line.startswith('#') and '=' in line:
k, v = line.split('=', 1)
env[k] = v
base = env.get('OJ_BASE_URL', 'https://oj.qonnwolf.com')
TID = '6a8c6a8b8499477a04169f85' # CSP04 lesson 01 基础回顾 (A包)
# 数字题目 -> 展示名(参考课件 OJ ID)
PID_MAP = {
6775: 'S0401P1 小杨的回文串',
6776: 'S0401P2 小杨有序去重',
6777: 'S0401P3 小杨的进制数位',
6968: 'S0401P4 小杨的幸运数字',
6969: 'S0401P5 小杨的报数游戏',
}
CLASSES = {
'0830': ['欧俊宇', '汪子杰', '谢明泓', '王佳琳', '魏铭轩', '张立坤'],
'1400': ['郑子煜', '张雨禾', '苏俊宇', '卢华琛', '鲍佳音'],
}
ALL_TARGETS = sorted({n for lst in CLASSES.values() for n in lst})
STATUS_NAMES = {1: 'AC', 2: 'WA', 3: 'CE', 4: 'RE', 5: 'TLE', 6: 'MLE', 7: 'PE', 8: 'OLE'}
client = httpx.Client(base_url=base, follow_redirects=True, timeout=30)
r = client.post('/login', json={'uname': env.get('OJ_USERNAME'), 'password': env.get('OJ_PASSWORD')})
ok = any(c.name == 'sid' for c in client.cookies.jar)
print('LOGIN:', 'OK' if ok else 'FAIL')
if not ok:
raise SystemExit('login failed')
# 1. fetch all records for the homework
records = []
seen = set()
for page in range(1, 40):
r = client.get(f'/d/system/record?tid={TID}&page={page}', headers={'Accept': 'application/json'})
if r.status_code != 200:
break
try:
rdocs = r.json().get('rdocs', [])
except Exception:
break
if not rdocs:
break
for rec in rdocs:
rid = rec.get('_id')
if rid in seen:
continue
seen.add(rid)
records.append({
'rid': rid, 'uid': rec.get('uid'), 'pid': rec.get('pid'),
'status': rec.get('status'), 'score': rec.get('score', 0),
'judgeAt': rec.get('judgeAt', ''), 'lang': rec.get('lang'),
})
if len(rdocs) < 100:
break
print('TOTAL RECORDS:', len(records))
# 2. build uid -> name
uids = {rec['uid'] for rec in records}
uid_name = {}
for uid in sorted(uids):
try:
rr = client.get(f'/user/{uid}')
m = re.search(r'<title>([^<]+)</title>', rr.text)
if m:
nm = m.group(1).split(' - ')[0].strip()
uid_name[uid] = nm
except Exception:
pass
print('UID->NAME mapped:', len(uid_name))
for rec in records:
rec['name'] = uid_name.get(rec['uid'], '')
# 3. for each target student, per problem pick the LAST submission (max judgeAt by iso)
last_by_key = {}
for rec in records:
if rec['name'] not in ALL_TARGETS:
continue
if rec['pid'] not in PID_MAP:
continue
key = (rec['name'], rec['pid'])
if key not in last_by_key or rec['judgeAt'] > last_by_key[key]['judgeAt']:
last_by_key[key] = rec
print('LAST-SUB keys:', len(last_by_key))
# 4. fetch code per (name, pid)
result = {}
sample_shown = 0
for (name, pid), rec in last_by_key.items():
try:
rr = client.get(f"/d/system/record/{rec['rid']}", headers={'Accept': 'application/json'})
j = rr.json()
rdoc = j.get('rdoc', {})
code = rdoc.get('code', '')
lang = rdoc.get('lang') or rec.get('lang')
except Exception as e:
code = ''
lang = None
entry = {
'key': PID_MAP[pid],
'code': code,
'lang': lang,
'status': STATUS_NAMES.get(rec['status'], '?'),
'score': rec.get('score'),
'attempts': sum(1 for x in records if x['name'] == name and x['pid'] == pid),
'judgeAt': rec.get('judgeAt'),
}
result.setdefault(name, {})[str(pid)] = entry
if sample_shown < 2 and code:
sample_shown += 1
print(f"SAMPLE CODE [{name} / {PID_MAP[pid]}] lang={lang}:\n{code[:300]}")
client.close()
out = {
'tid': TID,
'classes': CLASSES,
'pid_map': {str(k): v for k, v in PID_MAP.items()},
'students': result,
}
out_path = PROJECT_ROOT / '.claude' / 'memory' / 'temp' / 'student_code_CSP04_L01.json'
out_path.write_text(json.dumps(out, ensure_ascii=False, indent=2), encoding='utf-8')
print('SAVED ->', out_path)
print('students with code:', sorted(result.keys()))

View File

@@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
"""Batch fix for 课评汇总 class pages:
1) Remove the 评星 (star rating) feature: strip each <div class="metrics">…</div> block,
delete star/metric CSS rules, and remove the dead star JS functions.
2) Fix the 翻页卡死 (pagination freeze) on carousel pages: switch slides from
absolute-stacked opacity to display:none for inactive cards (only the active
card is ever laid out/painted), and remove backdrop-filter blur (compositing cost).
Only applied to the first-week pages when <target> is the folder.
"""
import os, re, sys
# ------------- balanced <div class="metrics"> removal -------------
def remove_metrics(html):
marker = '<div class="metrics">'
res = []
i = 0
n = len(html)
while True:
idx = html.find(marker, i)
if idx == -1:
res.append(html[i:])
break
res.append(html[i:idx])
depth = 1
j = idx + len(marker)
while depth > 0 and j < n:
oi = html.find('<div', j)
ci = html.find('</div>', j)
if ci == -1:
j = n
break
if oi != -1 and oi < ci:
depth += 1
j = oi + 4
else:
depth -= 1
j = ci + 6
i = j
return ''.join(res)
# ------------- balanced CSS block parser -------------
def strip_css(css, is_carousel):
out = []
i = 0
n = len(css)
while i < n:
m = re.match(r'\s+', css[i:])
if m:
out.append(m.group(0)); i += m.end(); continue
m = re.match(r'/\*.*?\*/', css[i:], re.S)
if m:
out.append(m.group(0)); i += m.end(); continue
brace = css.find('{', i)
if brace == -1:
out.append(css[i:]); break
sel = css[i:brace]
depth = 1
j = brace + 1
while depth > 0 and j < n:
if css[j] == '{': depth += 1
elif css[j] == '}': depth -= 1
j += 1
body = css[brace+1:j-1]
full = css[i:j]
selnorm = sel.strip()
if selnorm.startswith('@media') or selnorm.startswith('@supports'):
out.append(selnorm + '{' + strip_css(body, is_carousel) + '}')
elif re.search(r'\.(?:metric|star)', selnorm):
pass # drop star / metric rules
elif is_carousel and re.match(r'^\.student-card', selnorm):
if '.prev' in selnorm:
pass # drop the now-unneeded prev-state rule
elif '.active' in selnorm:
out.append('.student-card.active { display: block; position: relative; pointer-events: auto; }')
elif re.match(r'^\.student-card\s*$', selnorm):
out.append('.student-card { display: none; }')
else:
out.append(full) # .student-card:hover
else:
out.append(full)
i = j
return ''.join(out)
def process_styles(html, is_carousel):
def repl(m):
css = strip_css(m.group(2), is_carousel)
css = re.sub(r'backdrop-filter\s*:\s*blur\([^)]*\);?', '', css)
return m.group(1) + css + m.group(3)
return re.sub(r'(<style[^>]*>)(.*?)(</style>)', repl, html, flags=re.S)
# ------------- dead star JS removal -------------
def remove_function(js, name):
pat = re.compile(r'function\s+' + re.escape(name) + r'\s*\(')
m = pat.search(js)
if not m:
return js
brace = js.find('{', m.end())
if brace == -1:
return js
depth = 1
j = brace + 1
n = len(js)
while depth > 0 and j < n:
if js[j] == '{': depth += 1
elif js[j] == '}': depth -= 1
j += 1
return js[:m.start()] + js[j:]
def remove_call(js, name):
return re.sub(r'^[ \t]*' + re.escape(name) + r'\(\).*?$', '', js, flags=re.M)
def fix(html):
is_carousel = 'id="cardsSlider"' in html
html = remove_metrics(html)
html = process_styles(html, is_carousel)
if 'function initStarRatings' in html and 'initStarRatings' in html:
html = remove_call(html, 'initStarRatings')
html = remove_function(html, 'initStarRatings')
html = remove_function(html, 'setStarRating')
return html
def main(files):
for path in files:
with open(path, encoding='utf-8') as f:
html = f.read()
out = fix(html)
changed = out != html
with open(path, 'w', encoding='utf-8') as f:
f.write(out)
print(('CHANGED ' if changed else 'same ') + os.path.basename(path))
if __name__ == '__main__':
main(sys.argv[1:])

View File

@@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
"""Inject a collapsible 题目讲解 panel (题目 / 孩子代码 / 答案 / 解析) into each
student's OJ section on the two CSP04 class pages (0830 & 1400). Additive only.
Usage: python inject_prob_details.py <page1.html> <page2.html> ...
"""
import sys, os, json, html, re, copy
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent.parent.parent
TMP = ROOT / '.claude' / 'memory' / 'temp'
CODE = json.load(open(TMP / 'student_code_CSP04_L01.json', encoding='utf-8'))
META = json.load(open(TMP / 'problems_meta.json', encoding='utf-8'))
# display prefix -> numeric pid (as used in fetched codes)
PIDNUM = {v.split(' ')[0]: k for k, v in CODE['pid_map'].items()}
PROB_ORDER = ['S0401P1', 'S0401P2', 'S0401P3', 'S0401P4', 'S0401P5']
STATUS_TXT = {'AC': '✅ 已通过 AC', 'WA': '❌ 答案错误 WA', 'CE': '❌ 编译错误 CE',
'RE': '❌ 运行错误 RE', 'TLE': '❌ 超时 TLE', 'PE': '⚠️ 格式错误 PE', 'MLE': '❌ 超内存 MLE'}
CSS_BLOCK = '''
/* ===== 题目讲解(题目/孩子代码/答案/解析) ===== */
.oj-explains{margin-top:16px;}
.oj-explains-title{font-size:0.9em;font-weight:600;color:var(--ink);margin-bottom:8px;display:flex;align-items:center;gap:6px;}
.prob-detail{border:1px solid var(--border);border-radius:10px;margin-bottom:8px;overflow:hidden;background:var(--cream);}
.prob-head{display:flex;justify-content:space-between;align-items:center;gap:10px;padding:10px 14px;cursor:pointer;font-size:0.85em;}
.prob-head:hover{background:var(--paper-warm);}
.prob-title{font-weight:600;color:var(--ink);}
.prob-sub{font-size:0.74em;color:var(--ink-soft);flex:1;text-align:right;}
.prob-caret{font-size:0.85em;color:var(--ink-soft);transition:transform 0.2s ease;}
.prob-detail.open .prob-caret{transform:rotate(90deg);}
.prob-body{display:none;padding:12px 14px;border-top:1px solid var(--border);}
.prob-detail.open .prob-body{display:block;}
.prob-sec{margin-bottom:12px;}
.prob-sec:last-child{margin-bottom:0;}
.prob-sec-h{font-size:0.78em;font-weight:700;color:var(--ink-soft);margin-bottom:5px;}
.prob-sec-c{font-size:0.83em;line-height:1.75;color:var(--ink-soft);background:var(--paper);border-radius:8px;padding:8px 11px;}
.prob-code{background:#1b2733;color:#e6eef7;border-radius:8px;padding:10px 12px;font-size:0.76em;line-height:1.6;overflow:auto;white-space:pre;max-height:240px;font-family:Consolas,'Courier New',monospace;}
/* 未提交 -> 课后作业(不展开、不做分析) */
.prob-detail.homework{background:var(--paper-warm);border-style:dashed;}
.prob-detail.homework .prob-head{cursor:default;}
.prob-detail.homework .prob-sub{color:#a8842c;font-weight:600;}
'''
JS_BLOCK = '\n function toggleProb(el){el.classList.toggle("open");var c=el.querySelector(".prob-caret");if(c)c.textContent=el.classList.contains("open")?"▼":"▶";}\n'
def esc(t):
return html.escape(str(t))
def build_panels(student):
panels = ['<div class="oj-explains">',
'<div class="oj-explains-title">📖 题目讲解(已提交的题 · 题目 / 孩子代码 / 参考答案 / 解析)</div>']
codes = CODE['students'].get(student, {})
for pid in PROB_ORDER:
meta = META.get(pid)
if not meta:
continue
entry = codes.get(PIDNUM.get(pid, ''), {})
code = entry.get('code', '')
status = entry.get('status', '')
attempts = entry.get('attempts', 0)
if code:
sub = '%s · %d次提交' % (STATUS_TXT.get(status, status), attempts)
panels.append(
'<div class="prob-detail" onclick="toggleProb(this)">'
'<div class="prob-head">'
'<span class="prob-title">%s</span>'
'<span class="prob-sub">%s</span>'
'<span class="prob-caret">▶</span>'
'</div>'
'<div class="prob-body">'
'<div class="prob-sec"><div class="prob-sec-h">📋 题目</div><div class="prob-sec-c">%s</div></div>'
'<div class="prob-sec"><div class="prob-sec-h">👦 孩子的代码</div><pre class="prob-code">%s</pre></div>'
'<div class="prob-sec"><div class="prob-sec-h">✅ 参考答案</div><pre class="prob-code">%s</pre></div>'
'<div class="prob-sec"><div class="prob-sec-h">💡 解析</div><div class="prob-sec-c">%s</div></div>'
'</div></div>' % (esc(meta['key']), sub, esc(meta['statement']), esc(code), esc(meta['ref_code']), esc(meta['key_points'])))
else:
# 未提交 -> 只标为课后作业,不做分析
panels.append(
'<div class="prob-detail homework">'
'<div class="prob-head">'
'<span class="prob-title">%s</span>'
'<span class="prob-sub">📚 未提交 · 课后作业</span>'
'</div></div>' % esc(meta['key']))
panels.append('</div>')
return '\n'.join(panels)
def find_oj_section(html, start):
"""Return end index (after the matching </div>) for the oj-section starting at `start`."""
n = len(html)
depth = 1
i = start + len('<div class="oj-section"')
while depth > 0 and i < n:
o = html.find('<div', i)
c = html.find('</div>', i)
if c == -1:
return -1
if o != -1 and o < c:
depth += 1
i = o + 4
else:
depth -= 1
i = c + 6
return i
def inject_style(html, css):
idx = html.rfind('</style>')
if idx == -1:
return html
return html[:idx] + css + html[idx:]
def inject_script(html, js):
idx = html.rfind('</script>')
if idx == -1:
return html
return html[:idx] + js + html[idx:]
def process(html):
# inject CSS/JS once
if '.prob-detail' not in html:
html = inject_style(html, CSS_BLOCK)
if 'function toggleProb' not in html:
html = inject_script(html, JS_BLOCK)
# inject panels per student oj-section (insert RIGHT-TO-LEFT so earlier
# positions stay valid after the html string changes length)
pat = re.compile(r'<div class="oj-section" data-oj-section="([^"]+)">')
matches = [(m.group(1), m.start()) for m in pat.finditer(html)]
for name, start in reversed(matches):
end = find_oj_section(html, start)
if end == -1:
continue
closing = end - 6 # position of the </div> that closes oj-section
panels = build_panels(name)
html = html[:closing] + panels + '\n' + html[closing:]
return html
def main(files):
for p in files:
orig = open(p, encoding='utf-8').read()
out = process(orig)
changed = out != orig
open(p, 'w', encoding='utf-8').write(out)
print(('CHANGED ' if changed else 'same ') + os.path.basename(p))
if __name__ == '__main__':
main(sys.argv[1:])

View File

@@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
"""Probe OJ: login, list records for lesson-01 tid, and test whether a single
record exposes the submission code. Prints discoveries."""
import io, sys, re, json, httpx
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace')
from pathlib import Path
env = {}
for line in (Path('.env')).read_text(encoding='utf-8').split('\n'):
line = line.strip()
if line and not line.startswith('#') and '=' in line:
k, v = line.split('=', 1)
env[k] = v
base = env.get('OJ_BASE_URL', 'https://oj.qonnwolf.com')
TID = '6a8c6a8b8499477a04169f85' # CSP04 lesson 01 基础回顾
client = httpx.Client(base_url=base, follow_redirects=True, timeout=30)
r = client.post('/login', json={'uname': env.get('OJ_USERNAME'), 'password': env.get('OJ_PASSWORD')})
ok = any(c.name == 'sid' for c in client.cookies.jar)
print('LOGIN:', 'OK' if ok else 'FAIL', 'status', r.status_code)
if not ok:
raise SystemExit('login failed')
# 1. record list via JSON API
r = client.get(f'/d/system/record?tid={TID}&page=1', headers={'Accept': 'application/json'})
print('RECORD LIST status', r.status_code)
try:
data = r.json()
except Exception as e:
print('NOT JSON:', r.text[:300])
data = {}
rdocs = data.get('rdocs', [])
print('rdocs count', len(rdocs))
if rdocs:
rec = rdocs[0]
print('RECORD KEYS:', sorted(rec.keys()))
for k in ('_id','uid','pid','score','status','judgeAt','code'):
print(' ', k, '=', repr(rec.get(k))[:80])
# pick the record that has a code-like field or pick any
sample = rec
rid = sample.get('_id')
print('USING rid =', rid, 'pid =', sample.get('pid'))
# 2. try single-record detail endpoints
for ep in (f'/d/system/record/{rid}', f'/record/{rid}', f'/d/system/submission/{rid}'):
try:
rr = client.get(ep, headers={'Accept': 'application/json'})
txt = rr.text
has_code = 'code' in txt or '"code"' in txt
print(f'DETAIL {ep} status={rr.status_code} has_code_field={has_code} len={len(txt)}')
try:
j = rr.json()
keys = sorted(j.keys()) if isinstance(j, dict) else 'list'
print(' detail keys:', keys if isinstance(keys, list) else keys)
if isinstance(j, dict) and 'code' in j:
print(' CODE snippet:', repr(j['code'])[:200])
except Exception:
print(' (not json) snippet:', txt[:160].replace('\n',' '))
except Exception as e:
print(' DETAIL err', ep, e)
client.close()

View File

@@ -0,0 +1,42 @@
{
"S0401P1": {
"key": "S0401P1 小杨的回文串",
"title": "小杨的回文串",
"statement": "给定一个只含英文字母、大小写混合的字符串,问三件事:①把所有字母统一转小写后,它是不是回文串(是Yes/否No);②原串里有多少个大写字母;③原串里有多少个小写字母。回文就是正读倒读一样,如 abba、abcba。",
"key_points": "先统计后转换(统计的是原串的大写/小写个数);大写字母 +32 = 小写字母;用双指针 l/r 向中间夹,发现一次不相等就判否;三行输出顺序是 回文结果/大写个数/小写个数。",
"code_file": "小杨的回文串.cpp",
"ref_code": "#include <bits/stdc++.h>\n#define endl '\\n'\nusing namespace std;\n\nstring s;\nint cnt1, cnt2; // cnt1大写 cnt2小写 \n\nint main(){\n\tcin >> s;\n\t\n\tint len = s.size();\n\tfor(int i = 0; i < len; i++){\n\t\t// 先数小写的个数 \n\t\tif(islower(s[i])){\n\t\t\tcnt2++;\n\t\t} \n\t\t// 再数大写的个数 \n\t\tif(isupper(s[i])){\n\t\t\tcnt1++;\n\t\t\t// 转换成小写\n\t\t\ts[i] = s[i] + 32; \n\t\t}\n\t}\n\t\n\tint l = 0, r = len - 1;\n\tbool ok = true;\n\twhile(l <= r){\n\t\tif(s[l] != s[r]){\n\t\t\tok = false;\n\t\t\tbreak;\n\t\t}\n\t\tl++, r--;\n\t}\n\t\n\tif(ok){\n\t\tcout << \"Yes\";\n\t} else {\n\t\tcout << \"No\";\n\t}\n\t\n\tcout << endl << cnt1 << endl << cnt2;\n\treturn 0;\n}"
},
"S0401P2": {
"key": "S0401P2 小杨有序去重",
"title": "小杨有序去重",
"statement": "给定一份非降序的成绩单(相邻可能相等),去掉连续的重复成绩,得到“出现过的不同成绩”列表。用双指针在数组上原地完成:慢指针 j 指向已保留部分的末尾,快指针 i 向后扫,遇到 a[i] ≠ a[j] 就把 a[i] 复制到 a[j+1]。输出两行:去重后的列表;不同成绩的个数。",
"key_points": "前提是“有序”,只去相邻重复;比较对象是 a[j](保留区末尾),不是 a[i-1];j 从 1 开始、i 从 2 开始(第一个数无条件保留);n 最大 1e5,必须一遍扫完。",
"code_file": "小杨有序去重.cpp",
"ref_code": "#include <bits/stdc++.h>\n#define endl '\\n'\nusing namespace std;\n\nconst int MAXN = 100010;\nint n;\nint arr[MAXN];\n\nint main(){\n\n cin >> n;\n for(int i = 1; i <= n; i++){\n cin >> arr[i];\n }\n\n if(n == 0){\n cout << endl << 0 << endl;\n return 0;\n }\n \t\n\tint j = 1; // 慢指针\n\tfor(int i = 2; i <= n; i++){\n\t\t// i表示快指针,一直向后移动\n\t\tif(arr[i] == arr[j]) continue;\n\t\t// 如果不相同\n\t\tarr[j+1] = arr[i];\n\t\tj++; \n\t} \n\t\n\tfor(int i = 1; i <= j; i++){\n\t\tcout << arr[i] << \" \";\n\t}\n\tcout << endl << j;\n return 0;\n}"
},
"S0401P3": {
"key": "S0401P3 小杨的进制数位",
"title": "小杨的进制数位",
"statement": "把十进制数 n 转换成 k 进制(2≤k≤16),并统计表示里的字符构成:①k 进制表示(超过 9 的数位用大写 A~F 表示 10~15);②表示中数字字符(0~9)的个数;③表示中字母字符(A~F)的个数。",
"key_points": "除 k 取余、余数倒着拼(out = S[余数] + out);查表 “0123456789ABCDEF”;n=0 要特判输出 0;统计的是 k 进制表示里的字符,不是十进制原数。",
"code_file": "小杨的进制数位.cpp",
"ref_code": "#include <bits/stdc++.h>\n#define endl '\\n'\nusing namespace std;\n\nint num, k;\nstring out;\nstring S = \"0123456789ABCDEF\";\nint cnt1 = 0,cnt2 = 0;\n\nint main(){\n\tcin >> num >> k;\n\t\n\tif(num == 0){\n\t\tcout << 0 << endl << 1 << endl << 0;\n\t\treturn 0;\n\t}\n\t\n\tint t = num;\n\twhile(t > 0){\n\t\tint g = t % k;\n\t\t\n\t\tout = S[g] + out;\n\t\t\n\t\tt /= k;\n\t}\n\t\n\tfor(char c : out){\n\t\tif(isupper(c)){\n\t\t\tcnt2++;\n\t\t}else if(isdigit(c)){\n\t\t\tcnt1++;\n\t\t}\n\t}\n\tcout << out << endl << cnt1 << endl << cnt2;\n\treturn 0;\n}"
},
"S0401P4": {
"key": "S0401P4 小杨的幸运数字",
"title": "小杨的幸运数字",
"statement": "有些正整数的二进制表示里恰好只有 1 个 1(如 1=1、2=10、8=1000),这样的数叫“幸运数”,也就是 2 的幂。给 n 个正整数,统计:①这 n 个数里幸运数的个数;②这 n 个数的二进制表示中 1 的总个数。",
"key_points": "对每个数单独数它的 1 的个数(cnt1 每轮要清零);sum 累计的是“1 的个数”,cnt 累计的是“满足条件的数”,别混;1(=2^0)也是幸运数;进阶可用 n&(n-1)==0 判断/__builtin_popcount 数 1。",
"code_file": "小杨的幸运数字.cpp",
"ref_code": "#include <bits/stdc++.h>\n#define endl '\\n'\nusing namespace std;\n\nint n, num, cnt = 0, sum = 0;\nstring str = \"01\";\n\nint main() {\n\tcin >> n;\n\n\tfor(int i = 1; i <= n; i++) {\n\t\tcin >> num;\n\t\tint t = num;\n\t\t\n\t\tstring out = \"\";\n\t\tint cnt1 = 0;// 判断1的个数 \n\t\t\n\t\twhile(t > 0) {\n\t\t\tint g = t % 2;\n\t\t\t\n\t\t\tif(g == 1){\n\t\t\t\tsum++; // 总数加一 \n\t\t\t\tcnt1++; // 个数加一 \n\t\t\t}\n\t\t\t\n\t\t\tout = str[g] + out;\n\t\t\tt /= 2;\n\t\t}\n\t\t\n\t\tif(cnt1 == 1){\n\t\t\tcnt++; \n\t\t} \n\t}\n\t\n\tcout << cnt << endl << sum;\n\n\n\treturn 0;\n}"
},
"S0401P5": {
"key": "S0401P5 小杨的报数游戏",
"title": "小杨的报数游戏",
"statement": "n 个小朋友围成一圈,编号 1~n。从 1 号开始沿顺时针从 1 报数,报到 k 的小朋友出列,出列者下一位重新从 1 报数……直到全部出列。按出列顺序输出编号(约瑟夫问题)。",
"key_points": "数组 arr[i] 记状态(0 在场/1 出列);只有 arr[idx]==0 的人才报数;报满 k 出列后 cnt 归零、p--;idx 越界就回绕 idx>n→idx=1;边界 k=1 依次出列 1 2 3…n。",
"code_file": "小杨的报数游戏.cpp",
"ref_code": "#include <iostream>\nusing namespace std;\n\nint main() {\n\tint n, k;\n\tcin >> n >> k;\n\tint arr[110] = {0}; // 0表示当前这个同学还在,1表示这个同学出列了\n\tint idx = 1; // 表示当前这个叫到第几个同学\n\tint cnt = 0; // 本轮报数的计数器\n\tint p = n; // 当前人数 \n\t\n\twhile(p != 0){\n\t\t// 先判断当前这个人是不是出列了\n\t\tif(arr[idx] == 0){\n\t\t\tcnt++;\n\t\t\tif(cnt == k){\n\t\t\t\t// 这个人出列\n\t\t\t\tcout << idx << \" \"; // 当前这个人出列\n\t\t\t\tarr[idx] = 1; // 修改当前这个人出列状态\n\t\t\t\tp--;\n\t\t\t\tcnt = 0; \n\t\t\t}\n\t\t} \n\t\tidx++;\n\t\tif(idx > n){\n\t\t\tidx = 1;\n\t\t}\n\t} \n\treturn 0;\n}"
}
}

View File

@@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
import io, re, sys
f = sys.argv[1]; name = sys.argv[2]
c = io.open(f, encoding='utf-8').read()
i = c.find('data-oj-section="%s"' % name)
j = c.find('oj-explains', i)
seg = c[j:j+1800]
seg = re.sub(r'<[^>]+>', ' ', seg)
seg = re.sub(r'\s+', ' ', seg)
print('--- %s 题目讲解(前段) ---' % name)
print(seg)

View File

@@ -0,0 +1,330 @@
{
"tid": "6a8c6a8b8499477a04169f85",
"classes": {
"0830": [
"欧俊宇",
"汪子杰",
"谢明泓",
"王佳琳",
"魏铭轩",
"张立坤"
],
"1400": [
"郑子煜",
"张雨禾",
"苏俊宇",
"卢华琛",
"鲍佳音"
]
},
"pid_map": {
"6775": "S0401P1 小杨的回文串",
"6776": "S0401P2 小杨有序去重",
"6777": "S0401P3 小杨的进制数位",
"6968": "S0401P4 小杨的幸运数字",
"6969": "S0401P5 小杨的报数游戏"
},
"students": {
"汪子杰": {
"6968": {
"key": "S0401P4 小杨的幸运数字",
"code": "#include <bits/stdc++.h>\nusing namespace std;\n\nint main() {\n int n;\n cin >> n;\n int sum1 = 0, sum2 = 0;\n for (int i = 0; i < n; i++) {\n int x = 0;\n cin >> x;\n \n \n int t = x;\n while (t % 2 == 0) {\n t /= 2;\n }\n if (t == 1) sum1++;\n \n while (x > 0) {\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n sum2 += x & 1;\n x >>= 1;\n }\n }\n cout<<sum1<<endl;\n cout<<sum2<<endl;\n return 0;\n}\n\n\n\n\n\n\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-06T05:54:19.538Z"
},
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nstring s;\nint n,k;\nint sh,z;\nstring str=\"0123456789ABCDEF\";\nint main(){\n\tcin>>n>>k;\n\tint t=n;\n\tif(n==0){\n\t\tcout<<0<<endl<<1<<endl<<0;\n\t\treturn 0;\n\t}\n\twhile(t>0){\n\t\tint g=t%k;\n\t\tif(g<=9){\n\t\t\tsh++;\t\n\t\t}else{\n\t\t\tz++;\n\t\t}\n\t\ts=str[g]+s;\n\t\tt/=k;\n\t}\n\tcout<<s<<endl;\n\tcout<<sh<<endl;\n\tcout<<z;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T02:54:53.592Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n;\nint a[101000];\nint cnt1=0,cnt2=0;\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>a[i];\n\t}\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(a[i]!=a[j]){\n\t\t\ta[j+1]=a[i];\n\t\t\tj++;\n\t\t}\n\t\t\n\t}\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<a[i]<<\" \"; \n\t}\n\t\n\tcout<<endl<<j;\n\t\n\treturn 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T02:25:01.427Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nstring s;\nstring neww;\nint cnt1=0,cnt2=0;\nint main(){\n\tcin>>s;\n\tint n=s.size();\n\tfor(int i=0;i<=n-1;i++){\n\t\tchar c=s[i];\n\t\tif(c>='A'&&c<='Z'){\n\t\t\tcnt1++;\n\t\t\tc=c+32;\n\t\t}else if(c>='a'&&c<='z'){\n\t\t\tcnt2++; \n\t\t}\n\t\tneww+=c;\n\t}\n\n\t\n\tint l=0,r=s.size()-1;\n\tbool ok=true;\n\twhile(l<=r){\n\t\tif(neww[l]!=neww[r]){\n\t\t\tok=false;\n\t\t\tbreak;\n\t\t}\n\t\tl++,r--;\n\t}\n\t\n\t\n\tif(ok!=0){\n\t\tcout<<\"Yes\"<<endl;\n\t}else{\n\t\tcout<<\"No\"<<endl;\n\t}\n\tcout<<cnt1<<endl;\n\tcout<<cnt2;\n\t\n\t\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 3,
"judgeAt": "2026-09-05T01:54:20.081Z"
}
},
"卢华琛": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n,k,c1 = 0,c2 = 0;\nstring str = \"0123456789ABCDEF\" , s; \nint main(){\n\tcin >> n >> k;\n\tif(n == 0){\n\t\tcout << 0 << endl;\n\t\tcout << 1 << endl;\n\t\tcout << 0 << endl;\n\t\treturn 0;\n\t}\n\tint t = n;\n\twhile(t > 0){\n\t\tint g = t % k;\n\t\tif(g >= 10){\n\t\t\tc1++;\n\t\t}else{\n\t\t\tc2++;\n\t\t}\n\t\ts = str[g] + s;\n\t\tt /= k;\n\t}\n\tcout << s << endl;\n\tcout << c2 << endl;\n\tcout << c1 << endl;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-06T04:27:56.437Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n;\nint arr[100010];\nint main(){\n\tcin >> n;\n\tfor(int i = 1; i <= n; i++){\n\t\tcin >> arr[i];\n\t}\n\tint j = 1;\n\tfor(int i = 2; i <= n; i++){\n\t\tif(arr[j] != arr [i]){\n\t\t\tarr[j + 1] = arr[i];\n\t\t\tj++;\n\t\t}\n\t}\n\tfor(int i = 1; i <= j; i++){\n\t\tcout << arr[i] << \" \";\n\t}\n\tcout << endl << j;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-06T03:45:54.958Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nstring s;\nint a1 = 0, a2 = 0;\nint main(){\n\tcin >> s;\n\tint len = s.size(); \n\tfor(int i = 0;i <= len - 1;i++){\n\t\tchar c = s[i];\n\t\tif(c >= 'A' && c <= 'Z'){\n\t\t\ta1++;\n\t\t\ts[i] = c - 'A' + 'a';\n\t\t}else if(c >= 'a' && c <= 'z'){\n\t\t\ta2++;\n\t\t}\n\t}\n\tint l = 0, r = len - 1;\n\tbool o = true;\n\twhile(l <= r){\n\t\tif(s[l] != s[r]){\n\t\to = false;\n\t\tbreak;\n\t\t}\n\t\tl++,r--;\n\t}\n\tif(o == true){\n\t\tcout << \"Yes\" << endl;\n\t}else{\n\t\tcout << \"No\" << endl;\n\t}\n\tcout << a1 << endl;\n\tcout << a2 << endl;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-06T03:20:43.028Z"
}
},
"欧俊宇": {
"6969": {
"key": "S0401P5 小杨的报数游戏",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint main(){\n int a,b;\n cin>>a>>b;\n int d[110];\n for(int i=0;i<=a-1;i++){\n \td[i]=i+1;\n\t}\n\tint l=a; \n int p=0;\n\twhile(l>0){\n p=(p+b-1)%l;\n cout<<d[p]<<\" \";\n\n \n for(int i=p;i<=l-2;i++){\n d[i]=d[i+1];\n }\n l--;\n }\n \n\treturn 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T12:23:44.711Z"
},
"6968": {
"key": "S0401P4 小杨的幸运数字",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint main(){\n int n;\n cin>>n;\n int lucky=0; \n int one=0; \n for(int i=1;i<=n;i++){\n int x;\n cin>>x;\n\n int c=0; \n int t=x;\n\n while(t>0){\n if(t%2==1){\n c=c+1;\n }\n t/=2; \n }\n\n one=one+c; \n\n if(c==1){\n lucky+=1;\n }\n }\n\n cout<<lucky<<endl<<one;\n \n return 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T11:53:23.849Z"
},
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n,k;\nstring s;\nint sh,z;\nstring str=\"0123456789ABCDEFG\";\nint main(){\n cin>>n>>k;\n int t=n;\n if(n==0){\n \tcout<<0<<endl<<1<<endl<<0;\n \treturn 0;\n\t}\n while(t>0){\n \tint g=t%k;\n\t\tif(g<=9){\n\t\t\tsh++;\n\t\t} else{\n\t\t\tz++;\n\t\t}\n\t\ts=str[g]+s;\n\t\tt/=k;\n\t}\n\tcout<<s<<endl;\n\tcout<<sh<<endl;\n\tcout<<z;\n\treturn 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T02:56:50.501Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n,a[110000];\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>a[i];\n\t}\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(a[i]!=a[j]){\n\t\t\ta[j+1]=a[i];\n\t\t\tj++;\n\t\t}\n\t}\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<a[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n\treturn 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T02:30:47.942Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint main(){\n\tstring a;\n\tcin>>a;\n\tint b=a.size()-1;\n\tbool c=true;\n\tint ad=0;\n\tint ax=0;\n\tfor(int i=0;i<=b;i++){\n\t\tif(a[i]>='a'&&a[i]<='z'){\n\t\t\tax++;\n\t\t}\n\t\tif(a[i]>='A'&&a[i]<='Z'){\n\t\t\tad++;\n\t\t}\n\t\tif(a[i]>='A'&&a[i]<='Z'){\n\t\t\ta[i]+=32;\n\t\t}\n\t}\n\t\n\t\n\tfor(int j=0;j<=b/2;j++){\n\t\tint n=a[j];\n\t\tint m=a[b-j];\n\t\tif(n!=m){\n\t\t\tc=false;\n\t\t\t\n\t\t}\n\t}\n\tif(c==1){\n\t\tcout<<\"Yes\"<<endl;\n\t}else{\n\t\tcout<<\"No\"<<endl;\n\t}\n\tcout<<ad<<endl;\n\tcout<<ax;\n\treturn 0;\n}\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T01:42:05.562Z"
}
},
"张雨禾": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n;\nint main(){\n\tint n,k,cnt1=0,cnt2=0;\n\tstring s;\n\tstring str=\"0123456789ABCDEF0\";\n\tcin>>n>>k;\n\t\n\tif(n==0){\n\t\tcout<<0<<endl<<1<<endl<<0;\n\t\treturn 0;\n\t}\n\t\n\tint t=n;\n\tint g;\n\twhile(t>0){\n\t\t g=t%k;\n\t\tif(g>9){\n\t\t\tcnt2++;\n\t\t}else{\n\t\t\tcnt1++;\n\t\t}\n\t\ts=str[g]+s;\n\t\n\tt/=k;\n\t\n\t}\n\t\n\tcout<<s<<endl<<cnt1<<endl<<cnt2;\n\t\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T08:00:02.371Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n;\nint arr[1000100]; \n \nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>arr[i];\n\t}\n\t\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(arr[i]!=arr[j]){\n\t\t\tarr[j+1]=arr[i];\n\t\t\tj++;\n\t\t}\n\t}\n\t\n\t\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<arr[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T07:21:43.279Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nstring s;\nint da,xiao;\n\nint main(){\n\tcin>>s;\n\tint len = s.size();\n\tfor(int i = 0;i < len; i++){\n\t\tchar c=s[i];\n\t\tif(c>='A'&&c<='Z'){\n\t\t\tda++;\n\t\t\ts[i]=c-'A'+'a'; \n\t\t}else if(c>='a'&&c<='z'){\n\t\t\txiao++;\n\t\t}\n\t}\n\t\n\t\n\tint l=0,r=len-1;\n\tbool ok=true;\n\twhile(l<=r){\n\t\tif(s[l] !=s[r]){\n\t\t\tok=false;\n\t\t\tbreak;\n\t\t}\n\t\tr--,l++;\n\t}\n\t\n\tif(ok==true){\n\t\tcout<<\"Yes\";\n\t}else{\n\t\tcout<<\"No\";\n\t}\n\tcout<<endl;\n\tcout<<da<<endl;\n\tcout<<xiao<<endl;\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\t\n\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T06:43:25.148Z"
}
},
"郑子煜": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nstring op=\"123456789ABCDEF\";\nint main (){\n\tint x, y, num = 0;\n\tstring n;\n\tcin >> x >> y >> n;\n\tint len = n.size();\n\tfor(int i=0; i<len; i++){\n\t\tint g;\n\t\tif(n[i] >= 'A'){\n\t\t\tg = n[i] - 'A'+10;\n\t\t}\n\t\telse{\n\t\t\tg = n[i]-'0';\n\t\t}\n\t\tnum = num*x + g;\n\t}\n\tint t=num;\n\tstring ans = \" \";\n\twhile(t > 0){\n\t\tint g= t % y;\n\t\tans = op[g] + ans;\n\t\tt/=y;\n\t}\n\tcout << ans;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "WA",
"score": 0,
"attempts": 1,
"judgeAt": "2026-09-05T07:58:50.666Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include <bits/stdc++.h>\nusing namespace std;\n\nint main()\n{\n\tint cnt1=0,cnt2=0;\n\tstring s;\n\tcin >> s;\n int len = s.size();\n for(int i = 0; i < len;i++){\n \tchar c = s[i];\n \tif(c >= 'A' && c <= 'Z'){\n \t\tcnt1++;\n \t\ts[i] = c - 'A' + 'a';\n\t\t}else if(c >= 'a' && c <= 'z'){\n\t\t\tcnt2++;\n\t\t}\n\t\t\n\t}\n\tint l = 0,r = len - 1;\n\tbool ok = true;\n\twhile(l <= r ){\n\t\t\tif(s[l] != s[r]){\n\t\t\t\tok = false;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tl++,r--;\n\t\t}\n\tif(ok){\n\t\tcout << \"Yes\";\n\t}else\n\t \tcout << \"No\";\n\t \tcout << endl;\n\t \tcout << cnt1 << endl;\n\t\tcout << cnt2 << endl;\n return 0;\n\n} \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T07:55:11.601Z"
}
},
"鲍佳音": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include <bits/stdc++.h>\nusing namespace std;\nint n,k,c1,c2;\nstring s,s1=\"0123456789ABCDEF\";\nint main(){\n\tcin>>n>>k;\n\tif(n==0){\n\t\tcout<<0<<endl<<1<<endl<<0;\n\t\treturn 0;\n\t}\n\tint t=n;\n\twhile(t>0){\n\t\tint g=t%k;\n\t\tif(g>9){\n\t\t\tc2++;\n\t\t}else{\n\t\t\tc1++;\n\t\t}\n\t\ts=s1[g]+s;\n\t\tt/=k;\n\t}\n cout<<s<<endl<<c1<<endl<<c2;\n return 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T07:55:31.183Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include <bits/stdc++.h>\nusing namespace std;\nint a[1000010],n,js;\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>a[i];\n\t}\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(a[i]!=a[j]){\n\t\t\ta[j+1]=a[i];\n\t\t\tj++;\n\t }\n\t}\n\t\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<a[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T07:21:35.839Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include <bits/stdc++.h>\nusing namespace std;\nint d,x;\nstring s,a; \nint main(){\n\tcin>>s;\n\tfor(int i=0;i<s.size();i++){\n\t\tif(s[i]>='a'&&s[i]<='z') x++;\n\t\telse if(s[i]>='A'&&s[i]<='Z'){\n\t\t\td++;\n\t\t\ts[i]=s[i]-'A'+'a';\n\t\t};\n\t}\n\ta=s;\n\treverse(a.begin(),a.end());\n\tif(s==a){\n\t\tcout<<\"Yes\"<<endl;\n\t}else{\n\t\tcout<<\"No\"<<endl;\n\t}\n\tcout<<d<<endl<<x;\n\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T06:35:05.876Z"
}
},
"苏俊宇": {
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint n;\nint arr[1000100];\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>arr[i];\n\t}\n\t\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(arr[i]!=arr[j]){\n\t\t\tarr[j+1]=arr[i];\n\t\t\tj++; \n\t\t}\n\t}\n\t\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<arr[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n\treturn 0;\n} ",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T07:33:04.703Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint cnt1,cnt2;\nstring s;\nint main(){\n\tcin>>s;\n\tint len=s.size();\n\t\n\tfor(int i=0;i<len;i++){\n\t\tchar c=s[i];\n\t\tif(c>='A'&&'Z'>=c){\n\t\t\tcnt1++;\n\t\t\ts[i]=c-'A'+'a'; \n\t\t}else if('a'<=c&&'z'>=c){\n\t\t\tcnt2++;\n\t\t}\n\t}\n\t\n\tint l=0,r=len-1;\n\tbool ok=true;\n\twhile(l<=r){\n\t\tif(s[l]!=s[r]){\n\t\t\tok=false;\n\t\t\tbreak;\n\t\t}\n\t\tl++,r--;\n\t}\n\t\n\tif(ok){\n\t\tcout<<\"Yes\"<<endl<<cnt1<<endl<<cnt2;\n\t}else{\n\t\tcout<<\"No\"<<endl<<cnt1<<endl<<cnt2;\n\t}\n\treturn 0;\n} ",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T07:15:29.944Z"
}
},
"王佳琳": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include <bits/stdc++.h> \nusing namespace std;\nint n,k,cnt1=0,cnt2=0;\nstring s;\nstring str=\"0123456789ABCDEF\";\nint main(){\n\tcin>>n>>k;\n\tif(n==0){\n\t\tcout<<0<<endl<<1<<endl<<0;\n\t\treturn 0;\n\t}\n\tint t=n;\n\twhile(t>0){\n\t\tint g=t%k;\n\t\tif(g<=9){\n\t\t\tcnt1++;\n\t\t}else{\n\t\t\tcnt2++;\n\t\t}\n\t\ts=str[g]+s;\n\t\tt/=k;\n\t}\n\tcout<<s<<endl;\n\tcout<<cnt1<<endl<<cnt2;\n\treturn 0;\n}\n\t\n\t\t\n\t",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 3,
"judgeAt": "2026-09-05T03:18:13.216Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include <bits/stdc++.h> \nusing namespace std;\nint n;\nint arr[100010];\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>arr[i];\n\t}\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(arr[i] != arr[j]){\n\t\t\tarr[j+1]=arr[i];\n\t\t\tj++;\n\t\t}\n\t}\n\tfor(int i=1; i<=j;i++){\n\t\n\t\tcout<<arr[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n}\n\t\n\t\t\n\t",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 5,
"judgeAt": "2026-09-05T02:48:35.600Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include <bits/stdc++.h> \nusing namespace std;\nstring n,t;\nint cnt1,cnt2;\nint main(){\n\t\n\tcin>>n;\n\tfor(int i=0;i<n.size();i++){\n\t\tchar c=n[i];\n\t\tif(n[i]>='A' && n[i]<='Z'){\n\t\t\tcnt1++;\n\t\t\tc=c-'A'+'a';\n\t\t\t\n\t\t}else if(n[i]>='a' && n[i]<='z'){\n\t\t\tcnt2++;\n\t\t}\n\t\tt+=c;\n\t}\n\tint l=0,r=n.size()-1;\n\tbool ok=true;\n\twhile(l<=r){\n\t\tif(t[l] != t[r]){\n\t\t\tok=0;\n\t\t\tbreak;\n\t\t}\n\t\tl++,r--;\n\t}\n\tif(ok){\n\t\tcout<<\"Yes\"<<endl;\n\t}else{\n\t\tcout<<\"No\"<<endl;\n\t}\n\t\n\tcout<<cnt1<<endl;\n\tcout<<cnt2<<endl;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T02:03:00.115Z"
}
},
"谢明泓": {
"6777": {
"key": "S0401P3 小杨的进制数位",
"code": "#include<bits/stdc++.h>\nusing namespace std;\n\nint main(){\n int n,k;\n cin >> n >> k;\n if(n == 0){\n \tcout << 0 << endl << 1 << endl << 0;\n \treturn 0;\n\t}\n string s = \"\";\n string st = \"0123456789ABCDEF\";\n int t = n,sum = 0,cnt = 0;\n while(t){\n \tint g = t%k;\n \tif(g <= 9)sum++;\n \telse cnt++;\n \ts = st[g] + s;\n \tt /= k;\n\t}cout << s << endl << sum << endl << cnt;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 5,
"judgeAt": "2026-09-05T02:49:29.829Z"
},
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint l[100100];\nint main(){\n int n;\n cin >> n;\n for(int i = 1;i <= n;i++)\n \tcin >> l[i];\n int j = 1;\n for(int i = 2;i <= n;i++){\n \tif(l[i] != l[j]){\n \t\tl[j+1] = l[i];\n \t\tj++;\n\t\t}\n\t}\n\tfor(int i = 1;i <= j;i++)\n\t\tcout << l[i] << \" \";\n\tcout << endl << j;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T02:20:26.121Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\n\nint main(){\n\tstring s;\n\tcin >> s;\n\tint sum = 0,cnt = 0;\n\tstring n = s;\n\tfor(int i = 0;i < s.size();i++){\n\t\tif(isupper(s[i])){\t\n\t\t\ts[i] = tolower(s[i]);\n\t\t\tsum++;\n\t\t}\n\t\telse if(islower(s[i]))cnt++;\n\t}\n\tbool b = true;\n\tfor(int i = 0;i <= s.size()/2;i++){\n\t\tif(s[i] != s[s.size()-1-i]){\n\t\t\tb = false;\n\t\t\tcout << \"No\" << endl;\n\t\t\tbreak;\n\t\t}\n\t}if(b)cout << \"Yes\" << endl;\n\tcout << sum << endl << cnt;\n\treturn 0;\n}",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 1,
"judgeAt": "2026-09-05T01:48:24.232Z"
}
},
"张立坤": {
"6776": {
"key": "S0401P2 小杨有序去重",
"code": "#include <bits/stdc++.h>\nusing namespace std;\nint d,x,n,a[100010];\nint main(){\n\tcin>>n;\n\tfor(int i=1;i<=n;i++){\n\t\tcin>>a[i];\n\t}\n\tint j=1;\n\tfor(int i=2;i<=n;i++){\n\t\tif(a[i]!=a[j]){\n\t\t\ta[j+1]=a[i];\n\t\t\tj++;\n\t\t}\n\t}\n\tfor(int i=1;i<=j;i++){\n\t\tcout<<a[i]<<\" \";\n\t}\n\tcout<<endl<<j;\n} ",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 2,
"judgeAt": "2026-09-05T02:21:21.152Z"
},
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include <bits/stdc++.h>\nusing namespace std;\nstring s,a;\nint d,x;\nint main(){\n\tcin>>s;\n\tfor(int i=0;i<=s.size()-1;i++){\n\t\tif(char(s[i])>='A'&&char(s[i])<='Z'){\n\t\t\td++;\n\t\t\ts[i]=char(int(s[i])+32);\n\t\t}\n\t\telse if(char(s[i])>='a'&&char(s[i])<='z'){\n\t\t\tx++;\n\t\t}\n\t}\n\tint l=0,r=s.size()-1;\n\tbool ok=true;\n\twhile(l<=r){\n\t\tif(s[l]!=s[r]){\n\t\t\tok=false;\n\t\t\tbreak;\n\t\t}\n\t\tl++,r--;\n\t}\n\tif(ok==1){\n\t\tcout<<\"Yes\"<<endl<<d<<endl<<x;\n\t}\n\telse{\n\t\tcout<<\"No\"<<endl<<d<<endl<<x;\n\t}\n\t\n} ",
"lang": "cc.cc14o2",
"status": "AC",
"score": 100,
"attempts": 3,
"judgeAt": "2026-09-05T01:47:08.198Z"
}
},
"魏铭轩": {
"6775": {
"key": "S0401P1 小杨的回文串",
"code": "#include<bits/stdc++.h>\nusing namespace std;\nint cnt2=0;\nint cnt1=0;\nstring neww;\nchar ch[1010];\nstring s;\nint main(){\n\tgetline(cin,s);\n\tint len=s.size();\n\tfor(int i=0;i<len;i++){\n\t\tchar S=s[i];\n\t\tif(S>='A'&&S<='Z'){\n\t\t\tS=S+32;\n\t\t\tcnt1++;\n\t\t}else if(S>='a'&&S<='z'){\n\t\t\tcnt2++;\n\t\t}\n\t\tneww+=s;\n\t}\n\tint l=0,r=s.size()-1\n\tbool ok=tyue;\n\twhile(l<=r){\n\t\tif(neww[l]!=neww[r]){\n\t\t\tok=fales;\n\t\t\tbreak;\n\t\t}\n\t\t\n\n\t\t\n\t}\n\tl++,r--;\n\tcout<<ok;",
"lang": "cc.cc14o2",
"status": "PE",
"score": 0,
"attempts": 1,
"judgeAt": "2026-09-05T02:00:56.839Z"
}
}
}
}

View File

@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
import io, re, sys
for f in sys.argv[1:]:
c = io.open(f, encoding='utf-8').read()
print('===', f.replace('\\', '/').split('/')[-1])
print(' oj-explains:', c.count('class="oj-explains"'),
'| prob-detail:', c.count('class="prob-detail"'),
'| prob-sec-h:', c.count('class="prob-sec-h"'))
print(' ★star leftover:', c.count('star-rating'), c.count('class="star '),
'| backdrop-filter:', c.count('backdrop-filter'))
print(' student-card display:none:', '.student-card { display: none; }' in c,
'| active block:', '.student-card.active { display: block; position: relative; pointer-events: auto; }' in c)
opens = c.count('<div'); closes = c.count('</div>')
print(' div balance:', opens, '/', closes, 'OK' if opens == closes else 'MISMATCH')
mjs = re.search(r'<script[^>]*>(.*)</script>', c, re.S)
js = mjs.group(1)
print(' js braces:', js.count('{'), '/', js.count('}'),
'parens:', js.count('('), '/', js.count(')'))
print(' toggleProb present:', 'function toggleProb' in c)
# which student owns first panel
m = re.search(r'data-oj-section="([^"]+)">', c)
first_stu = m.group(1) if m else '?'
idx = c.find(first_stu)
print(' first student:', first_stu)

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
import os, sys, re
folder = os.path.abspath(sys.argv[1]) if len(sys.argv) > 1 else os.getcwd()
files = [f for f in os.listdir(folder) if f.endswith('.html') and f != '总览.html']
for name in sorted(files):
p = os.path.join(folder, name)
with open(p, encoding='utf-8') as f:
c = f.read()
star_html = (len(c.split('<div class="metrics">')) - 1) + c.count('class="star ') + c.count('class="star-rating')
star_css = len(re.findall(r'\.star-rating \{|\.metric-item \{|\.metric-label \{|\.star \{|\.star\.filled|\.half-filled\.', c))
star_js = len(re.findall(r'function initStarRatings|function setStarRating|initStarRatings\(\);', c))
bf = c.count('backdrop-filter')
car = 'id="cardsSlider"' in c
sc_dn = '.student-card { display: none; }' in c
opens = c.count('<div'); closes = c.count('</div>')
bal = 'OK' if opens == closes else 'MISMATCH %d/%d' % (opens, closes)
print('%-46s carousel=%-5s starHTML=%d starCSS=%d starJS=%d backdrop=%d scdn=%s div=%s' % (
name, car, star_html, star_css, star_js, bf, sc_dn if car else 'n/a(scroll)', bal))

View File

@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
import io, re, sys
for f in sys.argv[1:]:
c = io.open(f, encoding='utf-8').read()
opens = c.count('<div'); closes = c.count('</div>')
print('===', f.replace('\\', '/').split('/')[-1])
print(' oj-explains blocks:', c.count('class="oj-explains"'))
print(' prob-detail panels:', c.count('class="prob-detail"'))
print(' oj-sections:', c.count('data-oj-section='))
print(' CSS present:', '.prob-detail {' in c)
print(' toggleProb:', 'function toggleProb' in c)
print(' prob-sec-h count:', c.count('class="prob-sec-h"'))
print(' div balance:', opens, '/', closes, 'OK' if opens == closes else 'MISMATCH')
# sample first panel body
m = re.search(r'<div class="oj-explains">(.*?)</div>\s*\n', c, re.S)
if m:
blk = m.group(1)
print(' sample has 题目:', '📋 题目' in blk, '| 孩子代码:', '👦 孩子的代码' in blk, '| 答案:', '✅ 参考答案' in blk, '| 解析:', '💡 解析' in blk)

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
import io, sys
for f in sys.argv[1:]:
c = io.open(f, encoding='utf-8').read()
print('===', f.replace('\\', '/').split('/')[-1])
for label, needle in [
('CSS .prob-detail', '.prob-detail{border'),
('CSS .prob-body', '.prob-body{display:none'),
('CSS .prob-code', '.prob-code{background'),
('📋 题目', '📋 题目'),
('👦 孩子的代码', '👦 孩子的代码'),
('✅ 参考答案', '✅ 参考答案'),
('💡 解析', '💡 解析'),
('题目讲解标题', '题目讲解'),
]:
print(' %-18s count=%d' % (label, c.count(needle)))
# show a real panel sample (find first prob-body, strip tags for a peek)
import re
m = re.search(r'<div class="prob-body">(.*?)</div></div></div>', c, re.S)
if m:
txt = re.sub(r'<[^>]+>', ' ', m.group(1))
txt = re.sub(r'\s+', ' ', txt)
print(' first-panel text snippet:', txt[:180])

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
import io, re, sys
def find_oj_section(html, start):
n = len(html)
depth = 1
i = start + len('<div class="oj-section"')
while depth > 0 and i < n:
o = html.find('<div', i)
c = html.find('</div>', i)
if c == -1:
return -1
if o != -1 and o < c:
depth += 1
i = o + 4
else:
depth -= 1
i = c + 6
return i
for f in sys.argv[1:]:
c = io.open(f, encoding='utf-8').read()
pat = re.compile(r'<div class="oj-section" data-oj-section="([^"]+)">')
print('===', f.replace('\\', '/').split('/')[-1])
total_panels = 0
bad = []
for m in pat.finditer(c):
name = m.group(1)
end = find_oj_section(c, m.start())
blk = c[m.start():end]
expl = blk.count('class="oj-explains"')
panels = blk.count('class="prob-detail"')
total_panels += panels
if expl != 1 or panels != 5:
bad.append('%s: expl=%d panels=%d' % (name, expl, panels))
print(' oj-sections:', c.count('data-oj-section='), '| total prob-detail:', total_panels)
if bad:
print(' MISMATCH blocks:', bad)
else:
print(' OK: every student has exactly 1 题目讲解 block with 5 panels')
print(' div balance:', c.count('<div'), '/', c.count('</div>'))

View File

@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import io, re, sys
def find_oj_section(html, start):
n = len(html)
depth = 1
i = start + len('<div class="oj-section"')
while depth > 0 and i < n:
o = html.find('<div', i)
c = html.find('</div>', i)
if c == -1:
return -1
if o != -1 and o < c:
depth += 1
i = o + 4
else:
depth -= 1
i = c + 6
return i
for f in sys.argv[1:]:
c = io.open(f, encoding='utf-8').read()
pat = re.compile(r'<div class="oj-section" data-oj-section="([^"]+)">')
print('===', f.replace('\\', '/').split('/')[-1])
for m in pat.finditer(c):
name = m.group(1)
end = find_oj_section(c, m.start())
blk = c[m.start():end]
expl = blk.count('class="oj-explains"')
full = blk.count('class="prob-detail" onclick')
hw = blk.count('class="prob-detail homework"')
mark = 'OK' if (expl == 1 and full + hw == 5) else 'BAD'
print(' %-4s expl=%d full=%d homework=%d %s' % (name, expl, full, hw, mark))
print(' total homework-note count:', c.count('未提交 · 课后作业'))
print(' div balance:', c.count('<div'), '/', c.count('</div>'),
'OK' if c.count('<div') == c.count('</div>') else 'MISMATCH')