增加比赛的判题

This commit is contained in:
virusdefender 2015-08-23 18:28:30 +08:00
parent 86d33dd974
commit 7a22d78631
7 changed files with 175 additions and 11 deletions

View File

@ -58,3 +58,20 @@ class ContestProblemTestCase(models.Model):
class Meta: class Meta:
db_table = "contest_problem_test_case" db_table = "contest_problem_test_case"
class ContestSubmission(models.Model):
"""
用于保存比赛提交和排名的一些数据加快检索速度
"""
user = models.ForeignKey(User)
problem = models.ForeignKey(ContestProblem)
contest = models.ForeignKey(Contest)
total_submission_number = models.IntegerField(default=1)
# 这道题是 AC 还是没过
ac = models.BooleanField()
# 总的时间用于acm 类型的,也需要保存罚时
total_time = models.IntegerField(default=0)
class Meta:
db_table = "contest_submission"

View File

@ -1,10 +1,13 @@
# coding=utf-8 # coding=utf-8
import logging import logging
import redis import redis
from judge.judger_controller.settings import redis_config from judge.judger_controller.settings import redis_config
from judge.judger.result import result from judge.judger.result import result
from submission.models import Submission from submission.models import Submission
from problem.models import Problem from problem.models import Problem
from contest.models import ContestProblem, Contest, ContestSubmission
logger = logging.getLogger("app_info") logger = logging.getLogger("app_info")
@ -22,16 +25,74 @@ class MessageQueue(object):
submission = Submission.objects.get(id=submission_id) submission = Submission.objects.get(id=submission_id)
except Submission.DoesNotExist: except Submission.DoesNotExist:
logger.warning("Submission does not exist, submission_id: " + submission_id) logger.warning("Submission does not exist, submission_id: " + submission_id)
pass continue
if submission.result == result["accepted"]: if submission.result == result["accepted"] and not submission.contest_id:
# 更新题目的 ac 计数器 # 更新普通题目的 ac 计数器
try: try:
problem = Problem.objects.get(id=submission.problem_id) problem = Problem.objects.get(id=submission.problem_id)
problem.total_accepted_number += 1 problem.total_accepted_number += 1
problem.save() problem.save()
except Problem.DoesNotExist: except Problem.DoesNotExist:
logger.warning("Submission problem does not exist, submission_id: " + submission_id) logger.warning("Submission problem does not exist, submission_id: " + submission_id)
# 普通题目的话,到这里就结束了
continue
# 能运行到这里的都是比赛题目
try:
contest = Contest.objects.get(id=submission.contest_id)
contest_problem = ContestProblem.objects.get(contest=contest, id=submission.problem_id)
except Contest.DoesNotExist:
logger.warning("Submission contest does not exist, submission_id: " + submission_id)
continue
except ContestProblem.DoesNotExist:
logger.warning("Submission problem does not exist, submission_id: " + submission_id)
continue
try:
contest_submission = ContestSubmission.objects.get(user_id=submission.user_id, contest=contest,
problem_id=contest_problem.id)
# 如果这道题已经有提交记录了总的提交次数计数器加1
contest_submission.total_submission_number += 1
if submission.result == result["accepted"]:
# 避免这道题已经 ac 了,但是又重新提交了一遍
if not contest_submission.result:
# 这种情况是这个题目前处于错误状态,就使用已经存储了的罚时加上这道题的实际用时
contest_submission.total_time += int((submission.create_time - contest.start_time).seconds / 60)
# 标记为已经通过
contest_submission.ac = True
# contest problem ac 计数器加1
contest_problem.total_accepted_number += 1
else:
# 如果这个提交是错误的就罚时20分钟
contest_submission.ac = False
contest_submission.total_time += 20
contest_submission.save()
contest_problem.save()
except ContestSubmission.DoesNotExist:
# 第一次提交
is_ac = submission.result == result["accepted"]
# 增加题目总提交数计数器
contest_problem.total_submit_number += 1
if is_ac:
total_time = 0
# 增加题目总的ac数计数器
contest_problem.total_accepted_number += 1
contest_problem.save()
else:
# 没过罚时20分钟
total_time = 20
ContestSubmission.objects.create(user_id=submission.user_id, contest=contest, problem=contest_problem,
ac=is_ac, total_time=total_time)
except ContestSubmission.DoesNotExist:
pass pass

View File

@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('submission', '0003_auto_20150821_1654'),
]
operations = [
migrations.RemoveField(
model_name='submission',
name='is_counted',
),
]

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('submission', '0004_remove_submission_is_counted'),
]
operations = [
migrations.AddField(
model_name='submission',
name='contest_id',
field=models.IntegerField(null=True, blank=True),
),
]

View File

@ -11,6 +11,7 @@ class Submission(models.Model):
result = models.IntegerField(default=result["waiting"]) result = models.IntegerField(default=result["waiting"])
language = models.IntegerField() language = models.IntegerField()
code = models.TextField() code = models.TextField()
contest_id = models.IntegerField(blank=True, null=True)
problem_id = models.IntegerField(db_index=True) problem_id = models.IntegerField(db_index=True)
# 这个字段可能存储很多数据 比如编译错误、系统错误的时候,存储错误原因字符串 # 这个字段可能存储很多数据 比如编译错误、系统错误的时候,存储错误原因字符串
# 正常运行的时候存储 lrun 的判题结果比如cpu时间内存之类的 # 正常运行的时候存储 lrun 的判题结果比如cpu时间内存之类的
@ -18,7 +19,6 @@ class Submission(models.Model):
accepted_answer_time = models.IntegerField(blank=True, null=True) accepted_answer_time = models.IntegerField(blank=True, null=True)
# 这个字段只有在题目是accepted 的时候才会用到,比赛题目的提交可能还会有得分等信息,存储在这里面 # 这个字段只有在题目是accepted 的时候才会用到,比赛题目的提交可能还会有得分等信息,存储在这里面
accepted_answer_info = models.TextField(blank=True, null=True) accepted_answer_info = models.TextField(blank=True, null=True)
is_counted = models.BooleanField(default=False)
class Meta: class Meta:
db_table = "submission" db_table = "submission"

View File

@ -20,3 +20,10 @@ class SubmissionSerializer(serializers.ModelSerializer):
def _get_submission_user(self, obj): def _get_submission_user(self, obj):
return User.objects.get(id=obj.user_id).username return User.objects.get(id=obj.user_id).username
class CreateContestSubmissionSerializer(serializers.Serializer):
contest_id = serializers.IntegerField()
problem_id = serializers.IntegerField()
language = serializers.IntegerField()
code = serializers.CharField(max_length=3000)

View File

@ -1,21 +1,22 @@
# coding=utf-8 # coding=utf-8
import json import json
import redis
import redis
from django.shortcuts import render from django.shortcuts import render
from django.core.paginator import Paginator
from rest_framework.views import APIView from rest_framework.views import APIView
from judge.judger.result import result from problem.models import Problem
from judge.judger_controller.tasks import judge from judge.judger_controller.tasks import judge
from judge.judger_controller.settings import redis_config from judge.judger_controller.settings import redis_config
from account.decorators import login_required from account.decorators import login_required
from account.models import SUPER_ADMIN from account.models import SUPER_ADMIN
from problem.models import Problem from contest.models import Contest, ContestProblem
from contest.decorators import check_user_contest_permission
from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate from utils.shortcuts import serializer_invalid_response, error_response, success_response, error_page, paginate
from .models import Submission from .models import Submission
from .serializers import CreateSubmissionSerializer, SubmissionSerializer from .serializers import CreateSubmissionSerializer, SubmissionSerializer, CreateContestSubmissionSerializer
from django.core.paginator import Paginator
class SubmissionAPIView(APIView): class SubmissionAPIView(APIView):
@ -136,3 +137,44 @@ def my_submission_list_page(request, page=1):
return render(request, "oj/submission/my_submissions_list.html", return render(request, "oj/submission/my_submissions_list.html",
{"submissions": current_page, "page": int(page), {"submissions": current_page, "page": int(page),
"previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20}) "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20})
class ContestSubmissionAPIView(APIView):
@check_user_contest_permission
def post(self, request):
"""
创建比赛的提交
---
request_serializer: ConestSubmissionSerializer
"""
serializer = CreateContestSubmissionSerializer(data=request.data)
if serializer.is_valid():
data = serializer.data
try:
contest = Contest.objects.get(id=data["contest_id"])
except Contest.DoesNotExist:
return error_response(u"比赛不存在")
try:
problem = ContestProblem.objects.get(contest=contest, id=data["problem_id"])
# 更新题目提交计数器
problem.total_submit_number += 1
problem.save()
except Problem.DoesNotExist:
return error_response(u"题目不存在")
submission = Submission.objects.create(user_id=request.user.id, language=int(data["language"]),
contest_id=contest.id, code=data["code"], problem_id=problem.id)
try:
judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id)
except Exception:
return error_response(u"提交判题任务失败")
# 增加redis 中判题队列长度的计数器
r = redis.Redis(host=redis_config["host"], port=redis_config["port"], db=redis_config["db"])
r.incr("judge_queue_length")
return success_response({"submission_id": submission.id})
else:
return serializer_invalid_response(serializer)