new_bug_contest #23
@@ -2,33 +2,133 @@ from django.core.management.base import BaseCommand
|
|||||||
|
|
||||||
from contest.models import Contest, ContestQuestion, Question, QuestionVersion
|
from contest.models import Contest, ContestQuestion, Question, QuestionVersion
|
||||||
|
|
||||||
|
import random
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_beginner():
|
||||||
|
"""入门:100以内加减乘除,约 400 题。"""
|
||||||
|
questions = []
|
||||||
|
ops = [
|
||||||
|
("+", lambda a, b: a + b),
|
||||||
|
("-", lambda a, b: a - b),
|
||||||
|
("×", lambda a, b: a * b),
|
||||||
|
("÷", lambda a, b: a // b if b != 0 and a % b == 0 else None),
|
||||||
|
]
|
||||||
|
idx = 0
|
||||||
|
for a in range(2, 100):
|
||||||
|
for b in range(2, min(a + 1, 100)):
|
||||||
|
for sym, fn in ops:
|
||||||
|
if idx >= 400:
|
||||||
|
return questions
|
||||||
|
if sym == "÷" and (b == 0 or a % b != 0):
|
||||||
|
continue
|
||||||
|
if sym == "-" and a < b:
|
||||||
|
continue
|
||||||
|
result = fn(a, b)
|
||||||
|
if result is None or result < 0 or result > 10000:
|
||||||
|
continue
|
||||||
|
slug = f"b-auto-{idx:04d}"
|
||||||
|
prompt = f"{a} {sym} {b}"
|
||||||
|
answer = str(result)
|
||||||
|
if (slug, prompt, answer) not in questions:
|
||||||
|
questions.append((slug, prompt, answer))
|
||||||
|
idx += 1
|
||||||
|
return questions[:400]
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_standard():
|
||||||
|
"""标准:两位数乘除、大数减法、平方,约 400 题。"""
|
||||||
|
questions = []
|
||||||
|
idx = 0
|
||||||
|
# 两位数乘法
|
||||||
|
for a in range(11, 100):
|
||||||
|
for b in range(11, min(a + 1, 100)):
|
||||||
|
if idx >= 150:
|
||||||
|
break
|
||||||
|
questions.append((f"s-auto-mul-{idx:04d}", f"{a} × {b}", str(a * b)))
|
||||||
|
idx += 1
|
||||||
|
# 三位数除法
|
||||||
|
for a in range(100, 1000, 7):
|
||||||
|
for b in range(11, 50):
|
||||||
|
if idx >= 300:
|
||||||
|
break
|
||||||
|
if a % b == 0:
|
||||||
|
questions.append((f"s-auto-div-{idx:04d}", f"{a} ÷ {b}", str(a // b)))
|
||||||
|
idx += 1
|
||||||
|
# 大数减法
|
||||||
|
for a in range(1000, 10000, 137):
|
||||||
|
b = random.randint(100, a - 1)
|
||||||
|
if idx >= 350:
|
||||||
|
break
|
||||||
|
questions.append((f"s-auto-sub-{idx:04d}", f"{a} - {b}", str(a - b)))
|
||||||
|
idx += 1
|
||||||
|
# 平方
|
||||||
|
for a in range(11, 100):
|
||||||
|
if idx >= 400:
|
||||||
|
break
|
||||||
|
questions.append((f"s-auto-sq-{idx:04d}", f"{a}²", str(a * a)))
|
||||||
|
idx += 1
|
||||||
|
return questions[:400]
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_advanced():
|
||||||
|
"""进阶:模运算、组合数、高次幂、开方、等差数列求和,约 200 题。"""
|
||||||
|
questions = []
|
||||||
|
idx = 0
|
||||||
|
# 模运算
|
||||||
|
for base in range(2, 20):
|
||||||
|
for exp in range(2, 13):
|
||||||
|
for mod in range(3, 20):
|
||||||
|
if idx >= 50:
|
||||||
|
break
|
||||||
|
result = pow(base, exp, mod)
|
||||||
|
questions.append((f"a-auto-mod-{idx:04d}", f"{base}^{exp} ÷ {mod} 的余数", str(result)))
|
||||||
|
idx += 1
|
||||||
|
# 组合数 C(n,k)
|
||||||
|
for n in range(5, 31):
|
||||||
|
for k in range(2, min(n // 2 + 1, 8)):
|
||||||
|
if idx >= 100:
|
||||||
|
break
|
||||||
|
from math import comb
|
||||||
|
questions.append((f"a-auto-comb-{idx:04d}", f"C({n},{k})", str(comb(n, k))))
|
||||||
|
idx += 1
|
||||||
|
# 高次幂
|
||||||
|
for base in range(2, 10):
|
||||||
|
for exp in range(3, 10):
|
||||||
|
if idx >= 130:
|
||||||
|
break
|
||||||
|
result = base ** exp
|
||||||
|
if result > 10**8:
|
||||||
|
continue
|
||||||
|
questions.append((f"a-auto-pow-{idx:04d}", f"{base}^{exp}", str(result)))
|
||||||
|
idx += 1
|
||||||
|
# 开方(完全平方数)
|
||||||
|
for n in range(10, 200):
|
||||||
|
if idx >= 160:
|
||||||
|
break
|
||||||
|
r = int(n**0.5)
|
||||||
|
if r * r == n:
|
||||||
|
questions.append((f"a-auto-sqrt-{idx:04d}", f"√{n}", str(r)))
|
||||||
|
idx += 1
|
||||||
|
# 等差数列求和 1..n
|
||||||
|
for n in range(10, 201, 5):
|
||||||
|
if idx >= 200:
|
||||||
|
break
|
||||||
|
result = n * (n + 1) // 2
|
||||||
|
questions.append((f"a-auto-sum-{idx:04d}", f"1 到 {n} 的整数和", str(result)))
|
||||||
|
idx += 1
|
||||||
|
return questions[:200]
|
||||||
|
|
||||||
|
|
||||||
QUESTIONS = {
|
QUESTIONS = {
|
||||||
Question.Track.BEGINNER: [
|
Question.Track.BEGINNER: _generate_beginner(),
|
||||||
("b-12-plus-19", "12 + 19", "31"),
|
Question.Track.STANDARD: _generate_standard(),
|
||||||
("b-8-times-7", "8 × 7", "56"),
|
Question.Track.ADVANCED: _generate_advanced(),
|
||||||
("b-90-minus-37", "90 - 37", "53"),
|
|
||||||
("b-144-div-12", "144 ÷ 12", "12"),
|
|
||||||
("b-25-times-4", "25 × 4", "100"),
|
|
||||||
],
|
|
||||||
Question.Track.STANDARD: [
|
|
||||||
("s-17-times-23", "17 × 23", "391"),
|
|
||||||
("s-625-div-25", "625 ÷ 25", "25"),
|
|
||||||
("s-48-times-15", "48 × 15", "720"),
|
|
||||||
("s-1000-minus-387", "1000 - 387", "613"),
|
|
||||||
("s-35-squared", "35²", "1225"),
|
|
||||||
],
|
|
||||||
Question.Track.ADVANCED: [
|
|
||||||
("a-mod-2pow10", "2¹⁰ 除以 7 的余数", "2"),
|
|
||||||
("a-sum-1-50", "1 到 50 的整数和", "1275"),
|
|
||||||
("a-15-choose-2", "C(15,2)", "105"),
|
|
||||||
("a-sqrt-2025", "√2025", "45"),
|
|
||||||
("a-3pow6", "3⁶", "729"),
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
help = "创建首批分层题目、实时 1v1、每日赛和单人练习"
|
help = "创建分层题库(入门/标准/进阶)和实时 1v1、每日赛、单人练习"
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
versions = {}
|
versions = {}
|
||||||
@@ -93,6 +193,9 @@ class Command(BaseCommand):
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
ContestQuestion.objects.filter(contest=contest).delete()
|
ContestQuestion.objects.filter(contest=contest).delete()
|
||||||
|
pool = list(versions[track])
|
||||||
|
random.shuffle(pool)
|
||||||
|
selected = pool[:8]
|
||||||
ContestQuestion.objects.bulk_create(
|
ContestQuestion.objects.bulk_create(
|
||||||
[
|
[
|
||||||
ContestQuestion(
|
ContestQuestion(
|
||||||
@@ -101,11 +204,14 @@ class Command(BaseCommand):
|
|||||||
order=index,
|
order=index,
|
||||||
points=100,
|
points=100,
|
||||||
)
|
)
|
||||||
for index, version in enumerate(versions[track], start=1)
|
for index, version in enumerate(selected, start=1)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
total = sum(map(len, QUESTIONS.values()))
|
||||||
self.stdout.write(
|
self.stdout.write(
|
||||||
self.style.SUCCESS(
|
self.style.SUCCESS(
|
||||||
f"已创建 {sum(map(len, QUESTIONS.values()))} 道题和 {len(contest_specs)} 场比赛"
|
f"已创建 {total} 道题(入门{len(QUESTIONS[Question.Track.BEGINNER])}、"
|
||||||
|
f"标准{len(QUESTIONS[Question.Track.STANDARD])}、"
|
||||||
|
f"进阶{len(QUESTIONS[Question.Track.ADVANCED])})和 {len(contest_specs)} 场比赛"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ function collectApiErrorMessages(value, messages = []) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function logApiError(error) {
|
function logApiError(error) {
|
||||||
|
if (error.status === 401 || error.status === 403) return;
|
||||||
console.error("[Hulumath API]", {
|
console.error("[Hulumath API]", {
|
||||||
method: error.method,
|
method: error.method,
|
||||||
path: error.path,
|
path: error.path,
|
||||||
|
|||||||
@@ -350,6 +350,9 @@
|
|||||||
result.append(outcome, score, timeLine, rating);
|
result.append(outcome, score, timeLine, rating);
|
||||||
root.append(result);
|
root.append(result);
|
||||||
|
|
||||||
|
// 刷新右上角用户 Rating 显示
|
||||||
|
if (typeof loadUser === "function") loadUser();
|
||||||
|
|
||||||
const review = document.createElement("div");
|
const review = document.createElement("div");
|
||||||
review.className = "realtime-review";
|
review.className = "realtime-review";
|
||||||
match.attempt.questions.forEach((question) => {
|
match.attempt.questions.forEach((question) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user