From 2e0753587cc2840260099c8559e102b085a4e289 Mon Sep 17 00:00:00 2001 From: Zareian Date: Mon, 12 Oct 2026 12:56:47 +0330 Subject: [PATCH] Like/dislike + report under every question and lesson, lesson reports and vote columns in admin; practice islands refresh from file; audit fixes Co-Authored-By: Claude Sonnet 5.5 --- CLAUDE.md | 8 + config/settings.py | 1 + content/admin.py | 59 +- .../0023_lesson_report_content_vote.py | 46 + content/models.py | 47 + content/seed/questions.json | 1888 ++++++++--------- content/seed_sync.py | 60 + content/serializers.py | 7 +- content/tests_feedback.py | 52 + content/tests_seed_content.py | 32 + content/urls.py | 6 + content/views.py | 76 +- 12 files changed, 1331 insertions(+), 951 deletions(-) create mode 100644 content/migrations/0023_lesson_report_content_vote.py create mode 100644 content/tests_feedback.py diff --git a/CLAUDE.md b/CLAUDE.md index dd9c84b..20b6d7d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -465,6 +465,14 @@ anyone who can read this repo can forge a token for any user.** سوال در `question_io`؛ (۲) migration `content.0021` روی سوال/گزینه/درس/پیام‌های دستیارِ دیتابیس (و حذفِ سوالِ تکراریِ بعد از تبدیل)؛ (۳) `rag.services.mathtext.to_plain` روی پاسخِ زنده و تاریخچه‌ی دستیار (`ai_tutor/views.py`)؛ (۴) `MathApp_frontend/src/lib/plainMath.ts` در `MathText` به‌عنوانِ آخرین تور (دو پیاده‌سازی باید هم‌رفتار بمانند). توانِ پیچیده به‌صورتِ «a به توانِ (…)» نوشته می‌شود، نه `^`. تست: `content/tests_plain_math.py` (seed بدونِ نشانه)، `ai_tutor/tests_plain_history.py`. +- **بازخوردِ دانش‌آموز** (`content.0023`): زیرِ هر سوالِ آزمون و هر درس سه دکمه است: 👍 «خوب بود»، 👎 «خوب نبود»، «گزارشِ ایراد» + (`MathApp_frontend/src/components/FeedbackBar.tsx`). `POST /api/questions/{id}/vote` و `/api/lessons/{id}/vote` (`value` ۱/−۱/۰)، + `POST /api/lessons/{id}/report` (جدیدِ درس) و `…/questions/{id}/report` (از قبل). ادمین: ستونِ 👍/👎 در فهرستِ سوال‌ها و درس‌ها، + صفِ «گزارش‌های سوال» و «گزارش‌های درس». رأی هر کاربر روی هر هدف یکی و تغییرپذیر است (`ContentVote`). +- **اصلاحِ جزیره‌های تمرین از فایل:** `seed_sync._refresh_practice` گزینه‌های سوالِ موجودِ «تمرین: …» را در جا (همان idها) با فایل یکی می‌کند + و سوالِ تحویل‌شده‌ی حذف‌شده از فایل را اگر جوابی ندارد پاک می‌کند؛ سوالِ دستیِ ادمین هرگز. +- **بازبینیِ خودکارِ سریع** (۲۰۲۶-۱۰-۱۲): بازحسابِ مستقلِ ۳۴۲ سوالِ حسابِ ساده برابرِ کلید بود؛ ۱۲ سوالِ گزینه‌ی هم‌ارزِ جواب (۰/۳ و ۰) و ۵ درسِ + با سوگیریِ «جوابِ درست بلندترین گزینه» پیدا و اصلاح شد. این جایگزینِ بازبینیِ معلم نیست. - جزیره‌های تمرین آخرِ هر فصل‌اند و قفلِ ترتیبی دارند؛ فصلِ اولِ هر کتاب رایگان است، پس تمرین‌هایش هم رایگان‌اند. ## کتاب‌ها (Subject)، جزیره‌های بیشتر و شکلِ درس‌های کتاب‌های تازه — ۲۰۲۶-۱۰-۱۲ diff --git a/config/settings.py b/config/settings.py index 7c9f965..5815e7b 100644 --- a/config/settings.py +++ b/config/settings.py @@ -575,6 +575,7 @@ REST_FRAMEWORK = { 'token_refresh': os.environ.get('TOKEN_REFRESH_IP_RATE', '600/hour'), 'question_answer': '60/min', 'question_report': '20/hour', + 'content_vote': '300/hour', # هر درس اینجا یک نوع مسئله است با یکی-دو سوال، نه یک جلسه‌ی درسی؛ # ۱۰ در ساعت را دانش‌آموزِ عادی می‌زد و پیشرفتش ۴۲۹ می‌گرفت. 'lesson_complete': '120/hour', diff --git a/content/admin.py b/content/admin.py index 15561e7..4b431c5 100644 --- a/content/admin.py +++ b/content/admin.py @@ -15,7 +15,7 @@ from .curriculum_io import parse as parse_curriculum from .question_io import ImportError_, export_questions, import_questions, parse from .models import ( - Choice, Grade, Lesson, Node, NodeProgress, Question, QuestionReport, Subject, Unit, + Choice, ContentVote, Grade, Lesson, LessonReport, Node, NodeProgress, Question, QuestionReport, Subject, Unit, UserAnswer, UserLessonCompletion, ) @@ -108,9 +108,57 @@ class NodeAdmin(admin.ModelAdmin): search_fields = ('title', 'unit__title') +def _vote_counts(kind): + """Subquery: (likes, dislikes) برای هر هدف؛ ContentVote ارجاعِ سبک است، پس annotate مستقیم ممکن نیست.""" + from django.db.models import IntegerField, OuterRef, Subquery + from django.db.models.functions import Coalesce + + def sub(value): + return Coalesce(Subquery( + ContentVote.objects.filter(kind=kind, target_id=OuterRef('pk'), value=value) + .order_by().values('target_id').annotate(n=Count('id')).values('n'), + output_field=IntegerField()), 0) + return sub(1), sub(-1) + + +class VoteColumnsMixin: + vote_kind = '' + + def get_queryset(self, request): + likes, dislikes = _vote_counts(self.vote_kind) + return super().get_queryset(request).annotate(_likes=likes, _dislikes=dislikes) + + @admin.display(description='👍', ordering='_likes') + def likes(self, obj): + return obj._likes or '—' + + @admin.display(description='👎', ordering='_dislikes') + def dislikes(self, obj): + if not obj._dislikes: + return '—' + return format_html('{}', obj._dislikes) + + +@admin.register(LessonReport) +class LessonReportAdmin(admin.ModelAdmin): + """گزارشِ دانش‌آموزان روی متنِ درس‌ها.""" + + list_display = ('id', 'lesson', 'reason', 'status', 'note', 'created_at') + list_filter = ('status', 'reason', 'lesson__node__unit__grade') + search_fields = ('lesson__title', 'note') + autocomplete_fields = ['lesson'] + actions = ['mark_resolved'] + + @admin.action(description='علامت زدن به‌عنوانِ بررسی‌شده', permissions=['change']) + def mark_resolved(self, request, queryset): + updated = queryset.update(status='resolved', resolved_at=timezone.now()) + self.message_user(request, f'{updated} گزارش بررسی‌شده علامت خورد.', messages.SUCCESS) + + @admin.register(Lesson) -class LessonAdmin(admin.ModelAdmin): - list_display = ('id', 'title', 'node') +class LessonAdmin(VoteColumnsMixin, admin.ModelAdmin): + vote_kind = 'lesson' + list_display = ('id', 'title', 'node', 'likes', 'dislikes') list_filter = ('node',) # بدونِ این، انتخابِ درس در فرمِ سوال یک دراپ‌داونِ بیش از هزارتایی است # که عملاً غیرقابلِ استفاده است. @@ -118,7 +166,8 @@ class LessonAdmin(admin.ModelAdmin): @admin.register(Question) -class QuestionAdmin(admin.ModelAdmin): +class QuestionAdmin(VoteColumnsMixin, admin.ModelAdmin): + vote_kind = 'question' """ سوال‌ها علاوه بر ویرایشِ تکی، از همین‌جا فله‌ای وارد و خارج می‌شوند. @@ -127,7 +176,7 @@ class QuestionAdmin(admin.ModelAdmin): می‌پذیرد، پس چرخه‌ی ویرایش بسته است. """ - list_display = ('id', 'prompt', 'lesson', 'type', 'open_reports', 'wrong_percent') + list_display = ('id', 'prompt', 'lesson', 'type', 'open_reports', 'likes', 'dislikes', 'wrong_percent') list_filter = ('type', 'lesson__node__unit__grade', 'lesson__node__unit') inlines = [ChoiceInline] actions = ['export_selected'] diff --git a/content/migrations/0023_lesson_report_content_vote.py b/content/migrations/0023_lesson_report_content_vote.py new file mode 100644 index 0000000..8030743 --- /dev/null +++ b/content/migrations/0023_lesson_report_content_vote.py @@ -0,0 +1,46 @@ +# Generated by Django 5.2.17 on 2026-10-12 09:21 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('content', '0022_plain_math_messages_again'), + ] + + operations = [ + migrations.CreateModel( + name='ContentVote', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('kind', models.CharField(choices=[('question', 'سوال'), ('lesson', 'درس')], max_length=10)), + ('target_id', models.IntegerField()), + ('user_id', models.IntegerField()), + ('value', models.SmallIntegerField()), + ('updated_at', models.DateTimeField(auto_now=True)), + ], + options={ + 'indexes': [models.Index(fields=['kind', 'target_id'], name='content_con_kind_87301f_idx')], + 'constraints': [models.UniqueConstraint(fields=('kind', 'target_id', 'user_id'), name='one_vote_per_user_target')], + }, + ), + migrations.CreateModel( + name='LessonReport', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('user_id', models.IntegerField(db_index=True)), + ('reason', models.CharField(choices=[('wrong_content', 'مطلبِ درس اشتباه است'), ('unclear', 'توضیح گنگ است'), ('typo', 'غلطِ املایی/نگارشی'), ('bad_figure', 'شکل اشکال دارد'), ('other', 'موردِ دیگر')], default='other', max_length=20)), + ('note', models.TextField(blank=True)), + ('status', models.CharField(choices=[('open', 'باز'), ('resolved', 'بررسی\u200cشده'), ('rejected', 'رد شد')], db_index=True, default='open', max_length=15)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('resolved_at', models.DateTimeField(blank=True, null=True)), + ('lesson', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reports', to='content.lesson')), + ], + options={ + 'ordering': ['-created_at'], + 'indexes': [models.Index(fields=['lesson', 'status'], name='content_les_lesson__a6a0ce_idx')], + }, + ), + ] diff --git a/content/models.py b/content/models.py index 14f1a7e..fa19781 100644 --- a/content/models.py +++ b/content/models.py @@ -398,3 +398,50 @@ class SeedRecord(models.Model): def __str__(self): return f'seed-{self.kind}-{self.key[:8]}' + + +class LessonReport(models.Model): + """گزارشِ ایراد روی متنِ یک درس (توضیح، مثال، قدم‌ها)؛ همتای `QuestionReport`.""" + + REASON_CHOICES = [ + ('wrong_content', 'مطلبِ درس اشتباه است'), + ('unclear', 'توضیح گنگ است'), + ('typo', 'غلطِ املایی/نگارشی'), + ('bad_figure', 'شکل اشکال دارد'), + ('other', 'موردِ دیگر'), + ] + STATUS_CHOICES = [('open', 'باز'), ('resolved', 'بررسی‌شده'), ('rejected', 'رد شد')] + + lesson = models.ForeignKey(Lesson, on_delete=models.CASCADE, related_name='reports') + user_id = models.IntegerField(db_index=True) # ارجاع سبک به accounts.User + reason = models.CharField(max_length=20, choices=REASON_CHOICES, default='other') + note = models.TextField(blank=True) + status = models.CharField(max_length=15, choices=STATUS_CHOICES, default='open', db_index=True) + created_at = models.DateTimeField(auto_now_add=True) + resolved_at = models.DateTimeField(null=True, blank=True) + + class Meta: + ordering = ['-created_at'] + indexes = [models.Index(fields=['lesson', 'status'])] + + def __str__(self): + return f'report on lesson {self.lesson_id} ({self.get_reason_display()})' + + +class ContentVote(models.Model): + """ + لایک/دیسلایکِ دانش‌آموز روی یک سوال یا یک درس. هر کاربر روی هر هدف یک رأی دارد (تغییرپذیر). + ارجاعِ سبک (kind + target_id) تا یک جدول هر دو را بپوشاند؛ شمارش در ادمین با Subquery است. + """ + + KIND_CHOICES = [('question', 'سوال'), ('lesson', 'درس')] + + kind = models.CharField(max_length=10, choices=KIND_CHOICES) + target_id = models.IntegerField() + user_id = models.IntegerField() + value = models.SmallIntegerField() # ۱ = لایک، −۱ = دیسلایک + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + constraints = [models.UniqueConstraint(fields=['kind', 'target_id', 'user_id'], name='one_vote_per_user_target')] + indexes = [models.Index(fields=['kind', 'target_id'])] diff --git a/content/seed/questions.json b/content/seed/questions.json index 15e78d2..8959a69 100644 --- a/content/seed/questions.json +++ b/content/seed/questions.json @@ -98441,9 +98441,9 @@ "type": "multiple_choice", "choices": [ "۰", - "−√۲/۲", - "۱/۲", - "−√۳" + "−۱", + "−√۳", + "√۳" ], "correct": 0 }, @@ -98475,9 +98475,9 @@ "type": "multiple_choice", "choices": [ "۰", - "√۲/۲", - "√۳", - "−√۲/۲" + "−√۲/۲", + "−√۳/۲", + "√۳/۲" ], "correct": 0 }, @@ -98753,6 +98753,23 @@ ], "correct": 3 }, + { + "path": [ + "پایه دوازدهم", + "فصل ۲: مثلثات", + "تمرین: مقادیرِ مثلثاتی", + "مقادیرِ مثلثاتی زوایای مهم (درجه)" + ], + "prompt": "مقدارِ tan(۲۲۵°) کدام است؟", + "type": "multiple_choice", + "choices": [ + "۱", + "√۳/۲", + "۱/۲", + "−۱/۲" + ], + "correct": 0 + }, { "path": [ "پایه دوازدهم", @@ -98804,23 +98821,6 @@ ], "correct": 0 }, - { - "path": [ - "پایه دوازدهم", - "فصل ۲: مثلثات", - "تمرین: مقادیرِ مثلثاتی", - "مقادیرِ مثلثاتی زوایای مهم (درجه)" - ], - "prompt": "مقدارِ tan(۲۴۰°) کدام است؟", - "type": "multiple_choice", - "choices": [ - "−√۳/۲", - "√۳", - "۱/۲", - "−√۲/۲" - ], - "correct": 1 - }, { "path": [ "پایه دوازدهم", @@ -110425,10 +110425,10 @@ "prompt": "معادله‌ی x² + ۵x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -110442,10 +110442,10 @@ "prompt": "معادله‌ی ۴x² − x + ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110459,10 +110459,10 @@ "prompt": "معادله‌ی x² − ۸x − ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110476,10 +110476,10 @@ "prompt": "معادله‌ی −۳x² − ۹x − ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110493,10 +110493,10 @@ "prompt": "معادله‌ی −x² + x + ۱ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110510,10 +110510,10 @@ "prompt": "معادله‌ی ۲x² + ۷x − ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -110527,10 +110527,10 @@ "prompt": "معادله‌ی ۴x² − ۸x − ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110544,10 +110544,10 @@ "prompt": "معادله‌ی −۳x² − ۵x + ۸ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -110561,10 +110561,10 @@ "prompt": "معادله‌ی −۲x² − ۴x − ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110578,10 +110578,10 @@ "prompt": "معادله‌ی −۳x² − ۹x + ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -110595,10 +110595,10 @@ "prompt": "معادله‌ی ۴x² + ۷x − ۱ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110612,10 +110612,10 @@ "prompt": "معادله‌ی −۳x² − ۲x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -110629,10 +110629,10 @@ "prompt": "معادله‌ی x² − ۷x + ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -110646,10 +110646,10 @@ "prompt": "معادله‌ی ۴x² − ۵x + ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110663,10 +110663,10 @@ "prompt": "معادله‌ی ۳x² + ۶x + ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110680,10 +110680,10 @@ "prompt": "معادله‌ی −۳x² + ۴x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -110697,10 +110697,10 @@ "prompt": "معادله‌ی ۴x² − x − ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110714,10 +110714,10 @@ "prompt": "معادله‌ی x² − ۹x + ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110731,10 +110731,10 @@ "prompt": "معادله‌ی ۵x² − ۳x + ۱ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -110748,10 +110748,10 @@ "prompt": "معادله‌ی −۲x² + ۵x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -110765,10 +110765,10 @@ "prompt": "معادله‌ی −۳x² + ۹x − ۵ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110782,10 +110782,10 @@ "prompt": "معادله‌ی −۲x² − ۴x − ۸ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -110799,10 +110799,10 @@ "prompt": "معادله‌ی x² − ۹x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110816,10 +110816,10 @@ "prompt": "معادله‌ی −۳x² + ۳x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -110833,10 +110833,10 @@ "prompt": "معادله‌ی −۲x² + ۷x + ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -110850,10 +110850,10 @@ "prompt": "معادله‌ی ۳x² + ۲x − ۸ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -110867,10 +110867,10 @@ "prompt": "معادله‌ی ۲x² − ۴x − ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110884,10 +110884,10 @@ "prompt": "معادله‌ی ۲x² + ۳x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -110901,10 +110901,10 @@ "prompt": "معادله‌ی ۴x² + ۳x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -110918,10 +110918,10 @@ "prompt": "معادله‌ی −x² − ۳x + ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -121153,9 +121153,9 @@ "type": "multiple_choice", "choices": [ "۰", - "−√۳", - "−√۳/۲", - "√۲/۲" + "۱/۲", + "√۳/۲", + "√۳" ], "correct": 0 }, @@ -121271,10 +121271,10 @@ "prompt": "مقدارِ tan(۰°) کدام است؟", "type": "multiple_choice", "choices": [ - "√۲/۲", - "۱/۲", + "−۱", + "−√۳/۳", "۰", - "−۰" + "۱" ], "correct": 2 }, @@ -121373,12 +121373,12 @@ "prompt": "مقدارِ sin(۰°) کدام است؟", "type": "multiple_choice", "choices": [ - "−√۳/۲", - "√۲/۲", - "−√۳", - "۰" + "√۳/۲", + "۰", + "√۳", + "−√۲/۲" ], - "correct": 3 + "correct": 1 }, { "path": [ @@ -121387,13 +121387,30 @@ "تمرین: رادیان و نسبت‌های مثلثاتی", "نسبت‌های مثلثاتیِ زوایای مهم" ], - "prompt": "مقدارِ cos(۱۳۵°) کدام است؟", + "prompt": "مقدارِ cos(۳۰°) کدام است؟", "type": "multiple_choice", "choices": [ - "√۳", - "۱", - "−√۲/۲", - "−√۳" + "√۳/۲", + "۱/۲", + "√۲/۲", + "−√۳/۳" + ], + "correct": 0 + }, + { + "path": [ + "پایه یازدهم", + "فصل ۴: مثلثات", + "تمرین: رادیان و نسبت‌های مثلثاتی", + "نسبت‌های مثلثاتیِ زوایای مهم" + ], + "prompt": "مقدارِ cos(۱۲۰°) کدام است؟", + "type": "multiple_choice", + "choices": [ + "√۲/۲", + "√۳/۲", + "−۱/۲", + "−√۳/۲" ], "correct": 2 }, @@ -121414,23 +121431,6 @@ ], "correct": 0 }, - { - "path": [ - "پایه یازدهم", - "فصل ۴: مثلثات", - "تمرین: رادیان و نسبت‌های مثلثاتی", - "نسبت‌های مثلثاتیِ زوایای مهم" - ], - "prompt": "مقدارِ tan(۲۱۰°) کدام است؟", - "type": "multiple_choice", - "choices": [ - "۱", - "۰", - "۱/۲", - "√۳/۳" - ], - "correct": 3 - }, { "path": [ "پایه یازدهم", @@ -138662,10 +138662,10 @@ "prompt": "مخرجِ کسرِ ۳/√۶ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۶/۳", + "۱۸√۶/۶", "۳√۶/۶", - "۳√۶", - "۱۸√۶" + "√۶/۱۸", + "۳√۶/۳" ], "correct": 1 }, @@ -138679,10 +138679,10 @@ "prompt": "مخرجِ کسرِ ۳/√۷ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۲۱√۷", + "۳√۷/۳", "۳√۷/۷", - "۳√۷", - "√۷/۳" + "√۷/۲۱", + "۲۱√۷/۷" ], "correct": 1 }, @@ -138696,10 +138696,10 @@ "prompt": "مخرجِ کسرِ ۱/√۲ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۱/۲", - "۱√۲", + "۱√۲/۴", + "√۲/۲", "۱√۲/۲", - "۲√۲" + "۱√۲/۱" ], "correct": 2 }, @@ -138713,10 +138713,10 @@ "prompt": "مخرجِ کسرِ ۵/√۶ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۵/۶", + "۵√۶/۳۶", "۵√۶/۶", - "۵√۶", - "√۶/۵" + "√۶/۳۰", + "۳۰√۶/۶" ], "correct": 1 }, @@ -138731,9 +138731,9 @@ "type": "multiple_choice", "choices": [ "۱√۶/۶", - "√۶/۱", - "۶√۶", - "۱√۶" + "۶√۶/۶", + "۱√۶/۱", + "√۶/۶" ], "correct": 0 }, @@ -138747,9 +138747,9 @@ "prompt": "مخرجِ کسرِ ۶/√۲ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۲/۶", - "۱۲√۲", - "۶/۲", + "۱۲√۲/۲", + "۶√۲/۶", + "۶√۲/۴", "۶√۲/۲" ], "correct": 3 @@ -138764,10 +138764,10 @@ "prompt": "مخرجِ کسرِ ۲/√۵ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۵/۲", + "۱۰√۵/۵", "۲√۵/۵", - "۲√۵", - "۲/۵" + "√۵/۱۰", + "۲√۵/۲۵" ], "correct": 1 }, @@ -138781,9 +138781,9 @@ "prompt": "مخرجِ کسرِ ۲/√۳ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۲/۳", - "۶√۳", - "۲√۳", + "۲√۳/۹", + "۲√۳/۲", + "√۳/۶", "۲√۳/۳" ], "correct": 3 @@ -138799,9 +138799,9 @@ "type": "multiple_choice", "choices": [ "۳√۵/۵", - "۱۵√۵", - "√۵/۳", - "۳√۵" + "۳√۵/۳", + "۱۵√۵/۵", + "√۵/۱۵" ], "correct": 0 }, @@ -138815,10 +138815,10 @@ "prompt": "مخرجِ کسرِ ۲/√۷ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۱۴√۷", + "۲√۷/۲", "۲√۷/۷", - "√۷/۲", - "۲√۷" + "۱۴√۷/۷", + "√۷/۱۴" ], "correct": 1 }, @@ -138832,10 +138832,10 @@ "prompt": "مخرجِ کسرِ ۴/√۶ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۲۴√۶", - "۴/۶", + "۴√۶/۴", + "۴√۶/۳۶", "۴√۶/۶", - "۴√۶" + "√۶/۲۴" ], "correct": 2 }, @@ -138849,10 +138849,10 @@ "prompt": "مخرجِ کسرِ ۴/√۵ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۴√۵", - "۲۰√۵", + "√۵/۲۰", + "۴√۵/۴", "۴√۵/۵", - "√۵/۴" + "۲۰√۵/۵" ], "correct": 2 }, @@ -138867,9 +138867,9 @@ "type": "multiple_choice", "choices": [ "۱√۳/۳", - "۱/۳", - "۱√۳", - "۳√۳" + "۱√۳/۹", + "√۳/۳", + "۱√۳/۱" ], "correct": 0 }, @@ -138884,9 +138884,9 @@ "type": "multiple_choice", "choices": [ "۳√۲/۲", - "۳/۲", - "۳√۲", - "√۲/۳" + "۳√۲/۴", + "√۲/۶", + "۶√۲/۲" ], "correct": 0 }, @@ -138900,10 +138900,10 @@ "prompt": "مخرجِ کسرِ ۶/√۵ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۵/۶", - "۳۰√۵", + "۳۰√۵/۵", + "۶√۵/۶", "۶√۵/۵", - "۶/۵" + "۶√۵/۲۵" ], "correct": 2 }, @@ -138917,10 +138917,10 @@ "prompt": "مخرجِ کسرِ ۵/√۲ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۱۰√۲", + "۵√۲/۵", "۵√۲/۲", - "√۲/۵", - "۵√۲" + "۱۰√۲/۲", + "√۲/۱۰" ], "correct": 1 }, @@ -138934,9 +138934,9 @@ "prompt": "مخرجِ کسرِ ۶/√۳ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۳/۶", - "۱۸√۳", - "۶√۳", + "۱۸√۳/۳", + "۶√۳/۶", + "√۳/۱۸", "۶√۳/۳" ], "correct": 3 @@ -138951,44 +138951,10 @@ "prompt": "مخرجِ کسرِ ۴/√۲ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۲/۴", + "۴√۲/۴", "۴√۲/۲", - "۴√۲", - "۸√۲" - ], - "correct": 1 - }, - { - "path": [ - "پایه دهم", - "فصل ۳: توان‌های گویا و عبارت‌های جبری", - "تمرین: رادیکال‌ها", - "گویاسازیِ مخرج" - ], - "prompt": "مخرجِ کسرِ ۵/√۳ را گویا کنید.", - "type": "multiple_choice", - "choices": [ - "۵√۳", - "۵/۳", - "۵√۳/۳", - "۱۵√۳" - ], - "correct": 2 - }, - { - "path": [ - "پایه دهم", - "فصل ۳: توان‌های گویا و عبارت‌های جبری", - "تمرین: رادیکال‌ها", - "گویاسازیِ مخرج" - ], - "prompt": "مخرجِ کسرِ ۱/√۷ را گویا کنید.", - "type": "multiple_choice", - "choices": [ - "√۷/۱", - "۱√۷/۷", - "۱√۷", - "۱/۷" + "۸√۲/۲", + "√۲/۸" ], "correct": 1 }, @@ -139002,13 +138968,47 @@ "prompt": "مخرجِ کسرِ ۵/√۷ را گویا کنید.", "type": "multiple_choice", "choices": [ - "√۷/۵", - "۳۵√۷", - "۵√۷/۷", - "۵√۷" + "۳۵√۷/۷", + "۵√۷/۵", + "۵√۷/۴۹", + "۵√۷/۷" + ], + "correct": 3 + }, + { + "path": [ + "پایه دهم", + "فصل ۳: توان‌های گویا و عبارت‌های جبری", + "تمرین: رادیکال‌ها", + "گویاسازیِ مخرج" + ], + "prompt": "مخرجِ کسرِ ۵/√۳ را گویا کنید.", + "type": "multiple_choice", + "choices": [ + "√۳/۱۵", + "۵√۳/۹", + "۵√۳/۳", + "۵√۳/۵" ], "correct": 2 }, + { + "path": [ + "پایه دهم", + "فصل ۳: توان‌های گویا و عبارت‌های جبری", + "تمرین: رادیکال‌ها", + "گویاسازیِ مخرج" + ], + "prompt": "مخرجِ کسرِ ۱/√۷ را گویا کنید.", + "type": "multiple_choice", + "choices": [ + "۷√۷/۷", + "۱√۷/۷", + "√۷/۷", + "۱√۷/۴۹" + ], + "correct": 1 + }, { "path": [ "پایه دهم", @@ -139019,10 +139019,10 @@ "prompt": "مخرجِ کسرِ ۲/√۶ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۲√۶", - "۱۲√۶", + "√۶/۱۲", + "۲√۶/۲", "۲√۶/۶", - "√۶/۲" + "۱۲√۶/۶" ], "correct": 2 }, @@ -139036,9 +139036,9 @@ "prompt": "مخرجِ کسرِ ۱/√۵ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۱√۵", - "۵√۵", - "۱/۵", + "√۵/۵", + "۱√۵/۱", + "۱√۵/۲۵", "۱√۵/۵" ], "correct": 3 @@ -139053,10 +139053,10 @@ "prompt": "مخرجِ کسرِ ۶/√۷ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۴۲√۷", - "۶/۷", + "۶√۷/۶", + "۶√۷/۴۹", "۶√۷/۷", - "۶√۷" + "√۷/۴۲" ], "correct": 2 }, @@ -139070,9 +139070,9 @@ "prompt": "مخرجِ کسرِ ۴/√۳ را گویا کنید.", "type": "multiple_choice", "choices": [ - "۴/۳", - "۱۲√۳", - "۴√۳", + "۴√۳/۹", + "۴√۳/۴", + "√۳/۱۲", "۴√۳/۳" ], "correct": 3 @@ -139088,9 +139088,9 @@ "type": "multiple_choice", "choices": [ "۴√۷/۷", - "۴/۷", - "۲۸√۷", - "۴√۷" + "۴√۷/۴۹", + "۴√۷/۴", + "√۷/۲۸" ], "correct": 0 }, @@ -141144,10 +141144,10 @@ "prompt": "معادله‌ی −۳x² + ۳x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -141161,10 +141161,10 @@ "prompt": "معادله‌ی ۲x² − ۲x + ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141178,10 +141178,10 @@ "prompt": "معادله‌ی x² − ۴x + ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141195,10 +141195,10 @@ "prompt": "معادله‌ی ۳x² − ۳x − ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -141212,10 +141212,10 @@ "prompt": "معادله‌ی −۲x² + x − ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141229,10 +141229,10 @@ "prompt": "معادله‌ی x² + ۵x − ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -141246,10 +141246,10 @@ "prompt": "معادله‌ی −۴x² + ۶x + ۱ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -141263,10 +141263,10 @@ "prompt": "معادله‌ی −۲x² − x − ۸ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141280,10 +141280,10 @@ "prompt": "معادله‌ی −۳x² − ۸x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141297,10 +141297,10 @@ "prompt": "معادله‌ی −۲x² − x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141314,10 +141314,10 @@ "prompt": "معادله‌ی −۴x² − ۸x − ۸ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141331,10 +141331,10 @@ "prompt": "معادله‌ی ۲x² − ۷x − ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -141348,10 +141348,10 @@ "prompt": "معادله‌ی ۲x² − ۹x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141365,10 +141365,10 @@ "prompt": "معادله‌ی ۴x² − ۹x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -141382,10 +141382,10 @@ "prompt": "معادله‌ی x² − ۲x − ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141399,10 +141399,10 @@ "prompt": "معادله‌ی ۳x² − ۶x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141416,10 +141416,10 @@ "prompt": "معادله‌ی −۲x² + ۷x + ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141433,10 +141433,10 @@ "prompt": "معادله‌ی −x² + x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب", - "جوابِ حقیقی ندارد" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز", + "بدونِ جوابِ حقیقی" ], "correct": 3 }, @@ -141450,10 +141450,10 @@ "prompt": "معادله‌ی −۴x² + ۲x − ۲ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141467,10 +141467,10 @@ "prompt": "معادله‌ی −x² + ۲x − ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141484,10 +141484,10 @@ "prompt": "معادله‌ی −۲x² + ۴x − ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -141501,10 +141501,10 @@ "prompt": "معادله‌ی −x² + ۸x + ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141518,10 +141518,10 @@ "prompt": "معادله‌ی ۳x² + ۲x − ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -141535,10 +141535,10 @@ "prompt": "معادله‌ی −x² + ۴x + ۳ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب", - "دو جوابِ حقیقیِ متمایز" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز", + "دو جوابِ متمایز" ], "correct": 3 }, @@ -141552,10 +141552,10 @@ "prompt": "معادله‌ی −۲x² − ۸x − ۹ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141569,10 +141569,10 @@ "prompt": "معادله‌ی ۴x² + ۷x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "سه جواب" + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141586,10 +141586,10 @@ "prompt": "معادله‌ی −۲x² + ۹x + ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141603,10 +141603,10 @@ "prompt": "معادله‌ی ۴x² + ۶x − ۴ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "دو جوابِ حقیقیِ متمایز", - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "سه جواب" + "دو جوابِ متمایز", + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 0 }, @@ -141620,10 +141620,10 @@ "prompt": "معادله‌ی ۴x² − ۷x − ۷ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "جوابِ حقیقی ندارد", - "دو جوابِ حقیقیِ متمایز", - "سه جواب" + "یک جوابِ مضاعف", + "بدونِ جوابِ حقیقی", + "دو جوابِ متمایز", + "سه جوابِ متمایز" ], "correct": 2 }, @@ -141637,10 +141637,10 @@ "prompt": "معادله‌ی −۳x² − ۲x + ۶ = ۰ چند جوابِ حقیقی دارد؟", "type": "multiple_choice", "choices": [ - "یک جوابِ حقیقیِ مضاعف", - "دو جوابِ حقیقیِ متمایز", - "جوابِ حقیقی ندارد", - "سه جواب" + "یک جوابِ مضاعف", + "دو جوابِ متمایز", + "بدونِ جوابِ حقیقی", + "سه جوابِ متمایز" ], "correct": 1 }, @@ -224979,10 +224979,10 @@ "prompt": "نقطه‌ی (۴، −۲) نسبت به دایره‌ی (x + ۱)² + (y + ۱)² = ۹ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -224996,10 +224996,10 @@ "prompt": "نقطه‌ی (۵، ۱) نسبت به دایره‌ی (x − ۳)² + (y + ۳)² = ۴ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225013,10 +225013,10 @@ "prompt": "نقطه‌ی (۴، ۵) نسبت به دایره‌ی (x − ۱)² + (y + ۲)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225030,10 +225030,10 @@ "prompt": "نقطه‌ی (۶، −۱) نسبت به دایره‌ی (x − ۱)² + (y + ۳)² = ۹ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225047,10 +225047,10 @@ "prompt": "نقطه‌ی (−۲، ۰) نسبت به دایره‌ی (x + ۱)² + (y − ۱)² = ۱۶ …", "type": "multiple_choice", "choices": [ - "درون دایره است", - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "درونِ دایره", + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225064,10 +225064,10 @@ "prompt": "نقطه‌ی (۶، ۴) نسبت به دایره‌ی (x + ۳)² + (y + ۳)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225081,10 +225081,10 @@ "prompt": "نقطه‌ی (۶، ۵) نسبت به دایره‌ی (x − ۲)² + (y + ۳)² = ۳۶ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225098,10 +225098,10 @@ "prompt": "نقطه‌ی (−۳، ۳) نسبت به دایره‌ی (x − ۳)² + (y + ۳)² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "درون دایره است", - "مرکزِ دایره است" + "روی دایره", + "بیرونِ دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 1 }, @@ -225115,10 +225115,10 @@ "prompt": "نقطه‌ی (۱، ۵) نسبت به دایره‌ی x² + (y − ۲)² = ۴ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225132,10 +225132,10 @@ "prompt": "نقطه‌ی (−۱، ۲) نسبت به دایره‌ی (x + ۳)² + (y − ۱)² = ۳۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 1 }, @@ -225149,10 +225149,10 @@ "prompt": "نقطه‌ی (−۵، ۱) نسبت به دایره‌ی (x + ۲)² + (y − ۱)² = ۴ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225166,10 +225166,10 @@ "prompt": "نقطه‌ی (۶، ۲) نسبت به دایره‌ی (x − ۲)² + (y + ۱)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "روی دایره است" + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "روی دایره" ], "correct": 3 }, @@ -225180,13 +225180,30 @@ "تمرین: دایره", "وضعیتِ نقطه نسبت به دایره" ], - "prompt": "نقطه‌ی (۵، −۳) نسبت به دایره‌ی (x + ۲)² + (y − ۲)² = ۹ …", + "prompt": "نقطه‌ی (۱، ۲) نسبت به دایره‌ی (x − ۱)² + (y − ۲)² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است", - "بیرونِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" + ], + "correct": 1 + }, + { + "path": [ + "پایه دوازدهم", + "فصل ۲: آشنایی با مقاطع مخروطی", + "تمرین: دایره", + "وضعیتِ نقطه نسبت به دایره" + ], + "prompt": "نقطه‌ی (۵، −۳) نسبت به دایره‌ی (x − ۲)² + (y − ۳)² = ۹ …", + "type": "multiple_choice", + "choices": [ + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره", + "بیرونِ دایره" ], "correct": 3 }, @@ -225200,10 +225217,10 @@ "prompt": "نقطه‌ی (−۴، −۶) نسبت به دایره‌ی (x + ۲)² + (y + ۳)² = ۹ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225217,10 +225234,10 @@ "prompt": "نقطه‌ی (۶، ۵) نسبت به دایره‌ی (x − ۱)² + (y − ۱)² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225234,10 +225251,10 @@ "prompt": "نقطه‌ی (−۶، −۱) نسبت به دایره‌ی (x − ۱)² + y² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225251,10 +225268,10 @@ "prompt": "نقطه‌ی (−۱، ۰) نسبت به دایره‌ی (x − ۱)² + (y + ۳)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "درون دایره است" + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "درونِ دایره" ], "correct": 3 }, @@ -225268,10 +225285,10 @@ "prompt": "نقطه‌ی (۲، −۴) نسبت به دایره‌ی (x + ۲)² + y² = ۲۵ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225285,10 +225302,10 @@ "prompt": "نقطه‌ی (۵، ۶) نسبت به دایره‌ی (x − ۲)² + y² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225302,10 +225319,10 @@ "prompt": "نقطه‌ی (۵، −۳) نسبت به دایره‌ی (x − ۳)² + (y + ۲)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "درون دایره است" + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "درونِ دایره" ], "correct": 3 }, @@ -225319,10 +225336,10 @@ "prompt": "نقطه‌ی (−۲، −۱) نسبت به دایره‌ی x² + (y − ۳)² = ۳۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "درون دایره است" + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "درونِ دایره" ], "correct": 3 }, @@ -225336,10 +225353,10 @@ "prompt": "نقطه‌ی (۰، ۳) نسبت به دایره‌ی x² + (y − ۲)² = ۲۵ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "درون دایره است" + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "درونِ دایره" ], "correct": 3 }, @@ -225353,10 +225370,10 @@ "prompt": "نقطه‌ی (۵، ۰) نسبت به دایره‌ی (x − ۳)² + (y + ۲)² = ۹ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است", - "درون دایره است" + "روی دایره", + "بیرونِ دایره", + "روی مرکزِ دایره", + "درونِ دایره" ], "correct": 3 }, @@ -225370,10 +225387,10 @@ "prompt": "نقطه‌ی (۶، ۴) نسبت به دایره‌ی (x − ۳)² + (y − ۱)² = ۱۶ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225387,10 +225404,10 @@ "prompt": "نقطه‌ی (−۱، −۳) نسبت به دایره‌ی (x − ۲)² + (y + ۳)² = ۴ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225404,10 +225421,10 @@ "prompt": "نقطه‌ی (۴، −۱) نسبت به دایره‌ی (x − ۱)² + (y + ۳)² = ۹ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" + "روی دایره", + "درونِ دایره", + "بیرونِ دایره", + "روی مرکزِ دایره" ], "correct": 2 }, @@ -225421,10 +225438,10 @@ "prompt": "نقطه‌ی (−۲، ۴) نسبت به دایره‌ی (x − ۳)² + (y + ۳)² = ۹ …", "type": "multiple_choice", "choices": [ - "بیرونِ دایره است", - "روی دایره است", - "درون دایره است", - "مرکزِ دایره است" + "بیرونِ دایره", + "روی دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 0 }, @@ -225438,10 +225455,10 @@ "prompt": "نقطه‌ی (−۶، ۶) نسبت به دایره‌ی x² + (y + ۲)² = ۹ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "درون دایره است", - "مرکزِ دایره است" + "روی دایره", + "بیرونِ دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 1 }, @@ -225455,30 +225472,13 @@ "prompt": "نقطه‌ی (−۲، −۶) نسبت به دایره‌ی x² + y² = ۱۶ …", "type": "multiple_choice", "choices": [ - "روی دایره است", - "بیرونِ دایره است", - "درون دایره است", - "مرکزِ دایره است" + "روی دایره", + "بیرونِ دایره", + "درونِ دایره", + "روی مرکزِ دایره" ], "correct": 1 }, - { - "path": [ - "پایه دوازدهم", - "فصل ۲: آشنایی با مقاطع مخروطی", - "تمرین: دایره", - "وضعیتِ نقطه نسبت به دایره" - ], - "prompt": "نقطه‌ی (۳، −۳) نسبت به دایره‌ی (x + ۲)² + (y − ۲)² = ۴ …", - "type": "multiple_choice", - "choices": [ - "روی دایره است", - "درون دایره است", - "بیرونِ دایره است", - "مرکزِ دایره است" - ], - "correct": 2 - }, { "path": [ "پایه دوازدهم", @@ -262495,15 +262495,15 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۱/۳ − ۱/۳ کدام است؟", + "prompt": "حاصلِ ۵/۸ − ۲/۸ کدام است؟", "type": "multiple_choice", "choices": [ - "۱/۳", - "۰/۴", - "۰", - "۲/۳" + "۱۰/۸", + "۳/۸", + "۷/۸", + "۳/۹" ], - "correct": 2 + "correct": 1 }, { "path": [ @@ -262512,30 +262512,13 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۱۰/۱۲ − ۱/۱۲ کدام است؟", + "prompt": "حاصلِ ۴/۱۲ − ۱/۱۲ کدام است؟", "type": "multiple_choice", "choices": [ - "۹/۱۲", - "۱۰/۱۲", - "۹/۲۴", - "۹/۱۳" - ], - "correct": 0 - }, - { - "path": [ - "پایه چهارم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمعِ کسرها" - ], - "prompt": "حاصلِ ۸/۱۲ − ۳/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۵/۲۴", - "۵/۱۳", - "۱۱/۱۲", - "۵/۱۲" + "۴/۱۲", + "۳/۲۴", + "۳/۱۳", + "۳/۱۲" ], "correct": 3 }, @@ -262546,30 +262529,13 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۳/۵ + ۱/۵ کدام است؟", + "prompt": "حاصلِ ۲/۹ + ۶/۹ کدام است؟", "type": "multiple_choice", "choices": [ - "۴/۲۵", - "۳/۵", - "۵/۵", - "۴/۵" - ], - "correct": 3 - }, - { - "path": [ - "پایه چهارم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمعِ کسرها" - ], - "prompt": "حاصلِ ۲/۴ − ۱/۴ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۳/۴", - "۱/۵", - "۱/۴", - "۱/۸" + "۱۲/۹", + "۸/۸۱", + "۸/۹", + "۹/۹" ], "correct": 2 }, @@ -262580,13 +262546,47 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۲/۵ − ۲/۵ کدام است؟", + "prompt": "حاصلِ ۷/۱۰ + ۱/۱۰ کدام است؟", "type": "multiple_choice", "choices": [ - "۰", - "۰/۱۰", - "۴/۵", - "۰/۶" + "۹/۱۰", + "۷/۱۰", + "۸/۲۰", + "۸/۱۰" + ], + "correct": 3 + }, + { + "path": [ + "پایه چهارم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمعِ کسرها" + ], + "prompt": "حاصلِ ۳/۱۲ + ۵/۱۲ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۸/۲۴", + "۸/۱۲", + "۱۵/۱۲", + "۸/۱۴۴" + ], + "correct": 1 + }, + { + "path": [ + "پایه چهارم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمعِ کسرها" + ], + "prompt": "حاصلِ ۱/۶ + ۲/۶ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۳/۶", + "۳/۳۶", + "۲/۶", + "۴/۶" ], "correct": 0 }, @@ -262641,23 +262641,6 @@ ], "correct": 2 }, - { - "path": [ - "پایه چهارم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمعِ کسرها" - ], - "prompt": "حاصلِ ۲/۹ + ۶/۹ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۸/۱۸", - "۸/۹", - "۸/۸۱", - "۱۲/۹" - ], - "correct": 1 - }, { "path": [ "پایه چهارم", @@ -262699,15 +262682,15 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۲/۱۲ − ۲/۱۲ کدام است؟", + "prompt": "حاصلِ ۳/۵ + ۱/۵ کدام است؟", "type": "multiple_choice", "choices": [ - "۰/۲۴", - "۴/۱۲", - "۰/۱۳", - "۰" + "۴/۵", + "۳/۵", + "۴/۲۵", + "۵/۵" ], - "correct": 3 + "correct": 0 }, { "path": [ @@ -262716,13 +262699,13 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۱/۴ + ۱/۴ کدام است؟", + "prompt": "حاصلِ ۱/۹ + ۳/۹ کدام است؟", "type": "multiple_choice", "choices": [ - "۱/۴", - "۲/۴", - "۲/۸", - "۲/۱۶" + "۵/۹", + "۴/۹", + "۳/۹", + "۴/۸۱" ], "correct": 1 }, @@ -262733,16 +262716,33 @@ "تمرین: کسر", "جمعِ کسرها" ], - "prompt": "حاصلِ ۶/۱۲ − ۵/۱۲ کدام است؟", + "prompt": "حاصلِ ۶/۱۲ + ۱/۱۲ کدام است؟", "type": "multiple_choice", "choices": [ - "۱/۱۲", - "۱/۲۴", - "۱۱/۱۲", - "۳۰/۱۲" + "۷/۱۲", + "۷/۲۴", + "۸/۱۲", + "۷/۱۴۴" ], "correct": 0 }, + { + "path": [ + "پایه چهارم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمعِ کسرها" + ], + "prompt": "حاصلِ ۳/۵ − ۱/۵ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۲/۶", + "۲/۱۰", + "۴/۵", + "۲/۵" + ], + "correct": 3 + }, { "path": [ "پایه چهارم", @@ -262760,6 +262760,23 @@ ], "correct": 1 }, + { + "path": [ + "پایه چهارم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمعِ کسرها" + ], + "prompt": "حاصلِ ۲/۴ − ۱/۴ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۳/۴", + "۱/۵", + "۱/۴", + "۲/۴" + ], + "correct": 2 + }, { "path": [ "پایه چهارم", @@ -262879,23 +262896,6 @@ ], "correct": 2 }, - { - "path": [ - "پایه چهارم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمعِ کسرها" - ], - "prompt": "حاصلِ ۲/۱۲ + ۲/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۴/۲۴", - "۴/۱۲", - "۴/۱۴۴", - "۵/۱۲" - ], - "correct": 1 - }, { "path": [ "پایه چهارم", @@ -275551,13 +275551,13 @@ "تمرین: کسر", "جمع و تفریقِ کسر" ], - "prompt": "حاصلِ ۱/۴ − ۱/۴ کدام است؟", + "prompt": "حاصلِ ۳/۷ + ۱/۷ کدام است؟", "type": "multiple_choice", "choices": [ - "۱/۴", - "۰", - "۲/۴", - "۰/۸" + "۵/۷", + "۴/۷", + "۴/۴۹", + "۴/۱۴" ], "correct": 1 }, @@ -275568,13 +275568,47 @@ "تمرین: کسر", "جمع و تفریقِ کسر" ], - "prompt": "حاصلِ ۱۰/۱۲ + ۱/۱۲ کدام است؟", + "prompt": "حاصلِ ۴/۷ − ۱/۷ کدام است؟", "type": "multiple_choice", "choices": [ - "۱۰/۱۲", - "۱۱/۱۲", - "۱۲/۱۲", - "۱۱/۱۴۴" + "۴/۷", + "۵/۷", + "۳/۷", + "۳/۱۴" + ], + "correct": 2 + }, + { + "path": [ + "پایه پنجم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریقِ کسر" + ], + "prompt": "حاصلِ ۵/۷ − ۱/۷ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۵/۷", + "۴/۱۴", + "۴/۷", + "۶/۷" + ], + "correct": 2 + }, + { + "path": [ + "پایه پنجم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریقِ کسر" + ], + "prompt": "حاصلِ ۳/۷ + ۲/۷ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۵/۱۴", + "۵/۷", + "۶/۷", + "۵/۴۹" ], "correct": 1 }, @@ -275585,13 +275619,47 @@ "تمرین: کسر", "جمع و تفریقِ کسر" ], - "prompt": "حاصلِ ۶/۱۰ + ۲/۱۰ کدام است؟", + "prompt": "حاصلِ ۷/۱۲ + ۱/۱۲ کدام است؟", "type": "multiple_choice", "choices": [ - "۸/۱۰", - "۸/۱۰۰", - "۹/۱۰", - "۱۲/۱۰" + "۸/۲۴", + "۹/۱۲", + "۸/۱۲", + "۸/۱۴۴" + ], + "correct": 2 + }, + { + "path": [ + "پایه پنجم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریقِ کسر" + ], + "prompt": "حاصلِ ۵/۹ − ۳/۹ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۲/۱۰", + "۲/۹", + "۲/۱۸", + "۸/۹" + ], + "correct": 1 + }, + { + "path": [ + "پایه پنجم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریقِ کسر" + ], + "prompt": "حاصلِ ۲/۷ − ۱/۷ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۱/۷", + "۱/۱۴", + "۲/۷", + "۳/۷" ], "correct": 0 }, @@ -275602,100 +275670,15 @@ "تمرین: کسر", "جمع و تفریقِ کسر" ], - "prompt": "حاصلِ ۵/۱۰ − ۱/۱۰ کدام است؟", + "prompt": "حاصلِ ۷/۱۰ + ۱/۱۰ کدام است؟", "type": "multiple_choice", "choices": [ - "۵/۱۰", - "۶/۱۰", - "۴/۱۰", - "۴/۱۱" + "۸/۱۰", + "۷/۱۰", + "۸/۲۰", + "۹/۱۰" ], - "correct": 2 - }, - { - "path": [ - "پایه پنجم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریقِ کسر" - ], - "prompt": "حاصلِ ۳/۵ − ۱/۵ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۲/۱۰", - "۲/۵", - "۲/۶", - "۳/۵" - ], - "correct": 1 - }, - { - "path": [ - "پایه پنجم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریقِ کسر" - ], - "prompt": "حاصلِ ۹/۱۲ − ۱/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۸/۱۳", - "۹/۱۲", - "۱۰/۱۲", - "۸/۱۲" - ], - "correct": 3 - }, - { - "path": [ - "پایه پنجم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریقِ کسر" - ], - "prompt": "حاصلِ ۱/۱۲ + ۵/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۶/۲۴", - "۷/۱۲", - "۶/۱۲", - "۵/۱۲" - ], - "correct": 2 - }, - { - "path": [ - "پایه پنجم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریقِ کسر" - ], - "prompt": "حاصلِ ۱/۴ + ۲/۴ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۴/۴", - "۳/۴", - "۳/۱۶", - "۳/۸" - ], - "correct": 1 - }, - { - "path": [ - "پایه پنجم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریقِ کسر" - ], - "prompt": "حاصلِ ۲/۵ − ۲/۵ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۰/۱۰", - "۴/۵", - "۰/۶", - "۰" - ], - "correct": 3 + "correct": 0 }, { "path": [ @@ -275714,6 +275697,23 @@ ], "correct": 3 }, + { + "path": [ + "پایه پنجم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریقِ کسر" + ], + "prompt": "حاصلِ ۳/۵ − ۱/۵ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۲/۱۰", + "۴/۵", + "۳/۵", + "۲/۵" + ], + "correct": 3 + }, { "path": [ "پایه پنجم", @@ -289338,13 +289338,13 @@ "تمرین: کسر", "جمع و تفریق" ], - "prompt": "حاصلِ ۱/۳ − ۱/۳ کدام است؟", + "prompt": "حاصلِ ۷/۱۰ − ۱/۱۰ کدام است؟", "type": "multiple_choice", "choices": [ - "۰/۴", - "۲/۳", - "۰/۶", - "۰" + "۸/۱۰", + "۷/۱۰", + "۶/۲۰", + "۶/۱۰" ], "correct": 3 }, @@ -289355,65 +289355,48 @@ "تمرین: کسر", "جمع و تفریق" ], - "prompt": "حاصلِ ۳/۶ + ۱/۶ کدام است؟", + "prompt": "حاصلِ ۲/۱۲ + ۹/۱۲ کدام است؟", "type": "multiple_choice", "choices": [ - "۴/۳۶", - "۴/۱۲", - "۵/۶", + "۱۱/۱۴۴", + "۱۱/۱۲", + "۱۱/۲۴", + "۱۸/۱۲" + ], + "correct": 1 + }, + { + "path": [ + "پایه ششم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریق" + ], + "prompt": "حاصلِ ۷/۱۲ − ۱/۱۲ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۸/۱۲", + "۶/۲۴", + "۶/۱۳", + "۶/۱۲" + ], + "correct": 3 + }, + { + "path": [ + "پایه ششم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریق" + ], + "prompt": "حاصلِ ۴/۶ − ۱/۶ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۳/۶", + "۳/۱۲", + "۳/۷", "۴/۶" ], - "correct": 3 - }, - { - "path": [ - "پایه ششم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریق" - ], - "prompt": "حاصلِ ۲/۸ + ۵/۸ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۱۰/۸", - "۷/۸", - "۷/۶۴", - "۷/۱۶" - ], - "correct": 1 - }, - { - "path": [ - "پایه ششم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریق" - ], - "prompt": "حاصلِ ۱/۸ + ۴/۸ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۵/۱۶", - "۵/۸", - "۴/۸", - "۵/۶۴" - ], - "correct": 1 - }, - { - "path": [ - "پایه ششم", - "فصل ۲: کسر", - "تمرین: کسر", - "جمع و تفریق" - ], - "prompt": "حاصلِ ۲/۵ + ۲/۵ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۴/۵", - "۴/۱۰", - "۴/۲۵", - "۵/۵" - ], "correct": 0 }, { @@ -289423,15 +289406,15 @@ "تمرین: کسر", "جمع و تفریق" ], - "prompt": "حاصلِ ۱/۴ + ۲/۴ کدام است؟", + "prompt": "حاصلِ ۲/۶ − ۱/۶ کدام است؟", "type": "multiple_choice", "choices": [ - "۳/۱۶", - "۳/۸", - "۲/۴", - "۳/۴" + "۲/۶", + "۱/۶", + "۱/۷", + "۱/۱۲" ], - "correct": 3 + "correct": 1 }, { "path": [ @@ -289440,15 +289423,32 @@ "تمرین: کسر", "جمع و تفریق" ], - "prompt": "حاصلِ ۲/۶ + ۳/۶ کدام است؟", + "prompt": "حاصلِ ۲/۷ + ۱/۷ کدام است؟", "type": "multiple_choice", "choices": [ - "۵/۱۲", - "۶/۶", - "۵/۳۶", - "۵/۶" + "۳/۷", + "۴/۷", + "۳/۱۴", + "۲/۷" ], - "correct": 3 + "correct": 0 + }, + { + "path": [ + "پایه ششم", + "فصل ۲: کسر", + "تمرین: کسر", + "جمع و تفریق" + ], + "prompt": "حاصلِ ۴/۹ + ۲/۹ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۶/۹", + "۶/۱۸", + "۶/۸۱", + "۸/۹" + ], + "correct": 0 }, { "path": [ @@ -320652,15 +320652,15 @@ "تمرین: عددهای صحیح و گویا", "عددهای گویا" ], - "prompt": "حاصلِ ۱/۳ − ۱/۳ کدام است؟", + "prompt": "حاصلِ ۶/۸ + ۱/۸ کدام است؟", "type": "multiple_choice", "choices": [ - "۰", - "۱/۳", - "۰/۴", - "۲/۳" + "۷/۱۶", + "۸/۸", + "۷/۸", + "۷/۶۴" ], - "correct": 0 + "correct": 2 }, { "path": [ @@ -320669,15 +320669,15 @@ "تمرین: عددهای صحیح و گویا", "عددهای گویا" ], - "prompt": "حاصلِ ۱/۴ − ۱/۴ کدام است؟", + "prompt": "حاصلِ ۳/۷ − ۱/۷ کدام است؟", "type": "multiple_choice", "choices": [ - "۰/۸", - "۲/۴", - "۰", - "۰/۵" + "۲/۱۴", + "۲/۸", + "۳/۷", + "۲/۷" ], - "correct": 2 + "correct": 3 }, { "path": [ @@ -320924,13 +320924,30 @@ "تمرین: عددهای صحیح و گویا", "عددهای گویا" ], - "prompt": "حاصلِ ۱/۴ + ۲/۴ کدام است؟", + "prompt": "حاصلِ ۲/۹ + ۲/۹ کدام است؟", "type": "multiple_choice", "choices": [ - "۲/۴", - "۳/۸", - "۳/۴", - "۳/۱۶" + "۴/۹", + "۴/۱۸", + "۴/۸۱", + "۵/۹" + ], + "correct": 0 + }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۱/۱۲ + ۵/۱۲ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۵/۱۲", + "۶/۲۴", + "۶/۱۲", + "۶/۱۴۴" ], "correct": 2 }, @@ -320992,67 +321009,67 @@ "تمرین: عددهای صحیح و گویا", "عددهای گویا" ], - "prompt": "حاصلِ ۲/۷ − ۲/۷ کدام است؟", + "prompt": "حاصلِ ۱/۸ + ۴/۸ کدام است؟", "type": "multiple_choice", "choices": [ - "۰/۱۴", - "۴/۷", - "۰", - "۰/۸" - ], - "correct": 2 - }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۲/۵ − ۱/۵ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۱/۱۰", - "۳/۵", - "۲/۵", - "۱/۵" - ], - "correct": 3 - }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۷/۱۲ − ۴/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۲۸/۱۲", - "۱۱/۱۲", - "۳/۱۳", - "۳/۱۲" - ], - "correct": 3 - }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۱/۱۲ + ۵/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۶/۱۲", - "۷/۱۲", - "۵/۱۲", - "۶/۱۴۴" + "۵/۸", + "۵/۱۶", + "۶/۸", + "۴/۸" ], "correct": 0 }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۳/۱۰ + ۴/۱۰ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۸/۱۰", + "۷/۲۰", + "۱۲/۱۰", + "۷/۱۰" + ], + "correct": 3 + }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۳/۷ + ۲/۷ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۵/۷", + "۵/۱۴", + "۶/۷", + "۵/۴۹" + ], + "correct": 0 + }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۳/۱۲ + ۳/۱۲ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۹/۱۲", + "۶/۱۴۴", + "۶/۱۲", + "۶/۲۴" + ], + "correct": 2 + }, { "path": [ "پایه هشتم", @@ -321070,57 +321087,6 @@ ], "correct": 2 }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۳/۱۲ + ۳/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۶/۱۴۴", - "۶/۱۲", - "۶/۲۴", - "۷/۱۲" - ], - "correct": 1 - }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۷/۱۲ − ۲/۱۲ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۹/۱۲", - "۵/۱۳", - "۱۴/۱۲", - "۵/۱۲" - ], - "correct": 3 - }, - { - "path": [ - "پایه هشتم", - "فصل ۱: عددهای صحیح و گویا", - "تمرین: عددهای صحیح و گویا", - "عددهای گویا" - ], - "prompt": "حاصلِ ۳/۷ + ۲/۷ کدام است؟", - "type": "multiple_choice", - "choices": [ - "۵/۱۴", - "۶/۷", - "۵/۴۹", - "۵/۷" - ], - "correct": 3 - }, { "path": [ "پایه هشتم", @@ -321138,6 +321104,40 @@ ], "correct": 3 }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۵/۷ + ۱/۷ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۶/۷", + "۶/۱۴", + "۷/۷", + "۶/۴۹" + ], + "correct": 0 + }, + { + "path": [ + "پایه هشتم", + "فصل ۱: عددهای صحیح و گویا", + "تمرین: عددهای صحیح و گویا", + "عددهای گویا" + ], + "prompt": "حاصلِ ۶/۹ + ۱/۹ کدام است؟", + "type": "multiple_choice", + "choices": [ + "۸/۹", + "۶/۹", + "۷/۱۸", + "۷/۹" + ], + "correct": 3 + }, { "path": [ "پایه هشتم", diff --git a/content/seed_sync.py b/content/seed_sync.py index df509b4..12cbc2c 100644 --- a/content/seed_sync.py +++ b/content/seed_sync.py @@ -204,6 +204,8 @@ def _sync_questions(rows, ledger, counts): to_create.append(({**{k: v for k, v in row.items() if k != 'path'}, 'lessonId': lesson_id}, qkey)) existing.add((lesson_id, prompt)) + _refresh_practice(rows, lessons, ledger, counts) + if missing: raise question_io.ImportError_( 'این درس‌ها در برنامه‌ی درسی پیدا نشدند (اول کوریکولوم را وارد کنید): ' @@ -216,3 +218,61 @@ def _sync_questions(rows, ledger, counts): counts['created'] += result['created'] for _row, qkey in to_create: ledger.record(qkey, 'question') + + +PRACTICE_PREFIX = 'تمرین: ' + + +def _refresh_practice(rows, lessons, ledger, counts): + """ + جزیره‌های «تمرین: …» را فایل می‌سازد و ادمین سوال‌هایش را کم‌وبیش دست نمی‌زند؛ پس اصلاحِ فایل + (گزینه‌ی هم‌ارزِ جواب، جوابِ غلط) باید به سوالِ موجود برسد، وگرنه سید فقط «سوالِ تازه» می‌سازد و نسخه‌ی + معیوب می‌ماند: + - همان صورت، گزینه‌ها/پاسخِ درست فرق دارد → گزینه‌ها جا به جا (همان idها) به‌روز می‌شود تا پاسخ‌های + ثبت‌شده نشکنند؛ + - سوالی که خودِ سید قبلاً تحویل داده (دفتر) و حالا در فایل نیست و کسی جوابش نداده → پاک می‌شود. + سوالِ دستیِ ادمین (در دفتر نیست) هرگز دست نمی‌خورد. آزموده: content/tests_seed_content.py. + """ + practice_lessons = { + lid for path, lid in lessons.items() if path[2].startswith(PRACTICE_PREFIX) + } + if not practice_lessons: + return + want = {} + file_keys = set() + for row in rows: + path = tuple(str(p).strip() for p in row.get('path', [])) + if len(path) != 4 or not path[2].startswith(PRACTICE_PREFIX): + continue + lid = lessons.get(path) + prompt = (row.get('prompt') or '').strip() + if lid is None: + continue + want[(lid, prompt)] = row + file_keys.add(_key('question', *path, prompt)) + by_id = {} + for lid, path in ((v, k) for k, v in lessons.items() if v in practice_lessons): + by_id[lid] = path + qs = Question.objects.filter(lesson_id__in=practice_lessons).prefetch_related('choices') + stale = [] + for q in qs.iterator(chunk_size=500): + row = want.get((q.lesson_id, q.prompt)) + if row is None: + if _key('question', *by_id[q.lesson_id], q.prompt) in ledger.known: + stale.append(q.pk) + continue + new_choices = [str(c).strip() for c in row['choices']] + old = sorted(q.choices.all(), key=lambda c: c.pk) + if len(old) != len(new_choices): + continue + for index, choice in enumerate(old): + value, correct = new_choices[index], index == row['correct'] + if choice.value != value or choice.is_correct != correct: + choice.value, choice.is_correct = value, correct + choice.save(update_fields=['value', 'is_correct']) + counts['updated'] += 1 + if stale: + removable = list(Question.objects.filter(pk__in=stale, answers__isnull=True).values_list('pk', flat=True)) + if removable: + Question.objects.filter(pk__in=removable).delete() + counts['retired'] += len(removable) diff --git a/content/serializers.py b/content/serializers.py index 31b630d..23b8ba8 100644 --- a/content/serializers.py +++ b/content/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers -from .models import Grade, QuestionReport +from .models import Grade, LessonReport, QuestionReport # ---- Grades ---- @@ -258,3 +258,8 @@ class QuestionReportResponseSerializer(serializers.Serializer): success = serializers.BooleanField() reportId = serializers.IntegerField() alreadyReported = serializers.BooleanField() + + +class LessonReportRequestSerializer(serializers.Serializer): + reason = serializers.ChoiceField(choices=LessonReport.REASON_CHOICES) + note = serializers.CharField(required=False, allow_blank=True, max_length=1000) diff --git a/content/tests_feedback.py b/content/tests_feedback.py new file mode 100644 index 0000000..d94f264 --- /dev/null +++ b/content/tests_feedback.py @@ -0,0 +1,52 @@ +"""لایک/دیسلایک و گزارشِ درس/سوال: API و ستون‌های ادمین.""" +from django.core.cache import cache +from django.test import TestCase + +from accounts.authentication import issue_access_token +from accounts.models import User +from content.models import Choice, ContentVote, Grade, Lesson, LessonReport, Node, Question, Unit + + +class FeedbackTests(TestCase): + def setUp(self): + cache.clear() + g = Grade.objects.create(title='پایه نهم', icon='', color='') + u = Unit.objects.create(grade=g, title='فصل ۱', order=1) + n = Node.objects.create(unit=u, title='مبحث', order=1) + self.lesson = Lesson.objects.create(node=n, title='درس') + self.q = Question.objects.create(lesson=self.lesson, type='multiple_choice', prompt='؟') + Choice.objects.create(question=self.q, value='الف', is_correct=True) + Choice.objects.create(question=self.q, value='ب', is_correct=False) + self.user = User.objects.create(phone='09120000051') + self.auth = {'HTTP_AUTHORIZATION': f'Bearer {issue_access_token(self.user.id)}'} + + def _post(self, url, body): + return self.client.post(url, body, content_type='application/json', **self.auth) + + def test_vote_toggle_and_retract(self): + url = f'/api/questions/{self.q.pk}/vote' + self.assertEqual(self._post(url, {'value': 1}).status_code, 200) + self.assertEqual(self._post(url, {'value': -1}).status_code, 200) + self.assertEqual(ContentVote.objects.get().value, -1) + self._post(url, {'value': 0}) + self.assertEqual(ContentVote.objects.count(), 0) + + def test_vote_rejects_bad_value_and_anonymous(self): + url = f'/api/lessons/{self.lesson.pk}/vote' + self.assertEqual(self._post(url, {'value': 5}).status_code, 400) + self.assertEqual(self.client.post(url, {'value': 1}, content_type='application/json').status_code, 401) + + def test_lesson_report_is_deduplicated(self): + url = f'/api/lessons/{self.lesson.pk}/report' + r1 = self._post(url, {'reason': 'typo', 'note': 'غلط'}) + r2 = self._post(url, {'reason': 'typo'}) + self.assertEqual((r1.status_code, r2.status_code), (201, 200)) + self.assertEqual(LessonReport.objects.count(), 1) + + def test_admin_lists_show_votes(self): + ContentVote.objects.create(kind='question', target_id=self.q.pk, user_id=self.user.id, value=-1) + from django.contrib.auth.models import User as DjUser + DjUser.objects.create_superuser('root', 'r@x.ir', 'pw') + self.client.login(username='root', password='pw') + for path in ('/admin/content/question/', '/admin/content/lesson/', '/admin/content/lessonreport/'): + self.assertEqual(self.client.get(path).status_code, 200, path) diff --git a/content/tests_seed_content.py b/content/tests_seed_content.py index fd1b36a..1286314 100644 --- a/content/tests_seed_content.py +++ b/content/tests_seed_content.py @@ -287,3 +287,35 @@ class SeedFilesInRepoTests(TestCase): positions = {row['correct'] for row in rows} self.assertGreater(len(positions), 2) + + +class PracticeRefreshTests(TestCase): + """اصلاحِ فایلِ جزیره‌ی تمرین به سوالِ موجود می‌رسد؛ سوالِ دستیِ ادمین دست نمی‌خورد.""" + + def _rows(self, choices, correct, prompt='۲ + ۳ = ؟'): + return [{'path': ['پایه سوم', 'فصل ۱', 'تمرین: جمع', 'درس'], 'prompt': prompt, 'type': 'multiple_choice', + 'choices': choices, 'correct': correct}] + + def _grades(self): + return [{'title': 'پایه سوم', 'icon': '', 'color': '', 'units': [{ + 'title': 'فصل ۱', 'order': 1, 'subject': 'ریاضی', 'blurb': '', 'nodes': [{ + 'title': 'تمرین: جمع', 'order': 1, 'lessons': [{ + 'title': 'درس', 'intro_text': 'متن', 'example': '', 'steps': []}]}]}]}] + + def test_changed_choices_update_in_place_and_stale_is_removed(self): + from content import seed_sync + from content.models import Choice, Question + seed_sync.sync(self._grades(), self._rows(['۴', '۵', '۶', '۷'], 1)) + q = Question.objects.get() + ids = list(q.choices.order_by('pk').values_list('pk', flat=True)) + seed_sync.sync(self._grades(), self._rows(['۴', '۵', '۸', '۷'], 3)) + q.refresh_from_db() + got = list(q.choices.order_by('pk').values_list('pk', 'value', 'is_correct')) + self.assertEqual([g[0] for g in got], ids) + self.assertEqual(got[3][1:], ('۷', True)) + # سوالی که از فایل رفته و جوابی ندارد پاک می‌شود؛ سوالِ دستی نه + manual = Question.objects.create(lesson=q.lesson, type='multiple_choice', prompt='دستی') + Choice.objects.create(question=manual, value='الف', is_correct=True) + seed_sync.sync(self._grades(), self._rows(['۱', '۲'], 0, prompt='سوالِ دیگر')) + self.assertFalse(Question.objects.filter(prompt='۲ + ۳ = ؟').exists()) + self.assertTrue(Question.objects.filter(prompt='دستی').exists()) diff --git a/content/urls.py b/content/urls.py index d7f2b20..09cb0cf 100644 --- a/content/urls.py +++ b/content/urls.py @@ -12,6 +12,9 @@ from .views import ( NodeProgressListView, QuestionAnswerView, QuestionReportView, + LessonReportView, + LessonVoteView, + QuestionVoteView, ) urlpatterns = [ @@ -22,6 +25,9 @@ urlpatterns = [ path('lessons//complete', LessonCompleteView.as_view(), name='lesson-complete'), path('questions//answer', QuestionAnswerView.as_view(), name='question-answer'), path('questions//report', QuestionReportView.as_view(), name='question-report'), + path('questions//vote', QuestionVoteView.as_view(), name='question-vote'), + path('lessons//vote', LessonVoteView.as_view(), name='lesson-vote'), + path('lessons//report', LessonReportView.as_view(), name='lesson-report'), path('nodes//lessons', NodeLessonsView.as_view(), name='node-lessons'), path('nodes//quiz', NodeQuizView.as_view(), name='node-quiz'), path('nodes//quiz/complete', NodeQuizCompleteView.as_view(), name='node-quiz-complete'), diff --git a/content/views.py b/content/views.py index 5121479..53453a7 100644 --- a/content/views.py +++ b/content/views.py @@ -26,7 +26,7 @@ from .services import ( playable_lesson_ids, quiz_completed_node_ids, verified_correct_count, ) from .models import ( - Choice, Grade, Lesson, Node, NodeProgress, Question, QuestionReport, Subject, UserAnswer, + Choice, ContentVote, Grade, Lesson, LessonReport, Node, NodeProgress, Question, QuestionReport, Subject, UserAnswer, UserLessonCompletion, UserNodeCompletion, ) from .serializers import ( @@ -37,6 +37,7 @@ from .serializers import ( LessonCompleteRequestSerializer, LessonCompleteResponseSerializer, LessonIntroResponseSerializer, + LessonReportRequestSerializer, LessonQuestionsResponseSerializer, NodeLessonsResponseSerializer, NodeQuizCompleteRequestSerializer, @@ -988,6 +989,79 @@ class QuestionReportView(APIView): ) +class _VoteBase(APIView): + """POST …/vote {value: 1|-1|0} — لایک/دیسلایکِ دانش‌آموز؛ ۰ یعنی رأی را پس می‌گیرد.""" + + permission_classes = [IsAuthenticated] + throttle_scope = 'content_vote' + throttle_classes = [ScopedRateThrottle] + kind = '' + + def _exists(self, target_id) -> bool: + raise NotImplementedError + + def post(self, request, **kwargs): + target_id = next(iter(kwargs.values())) + if not self._exists(target_id): + raise NotFound('پیدا نشد.') + value = request.data.get('value') + if value not in (1, -1, 0) or isinstance(value, bool): + raise ValidationError({'value': 'باید ۱، −۱ یا ۰ باشد.'}) + if value == 0: + ContentVote.objects.filter(kind=self.kind, target_id=target_id, user_id=request.user.id).delete() + else: + ContentVote.objects.update_or_create( + kind=self.kind, target_id=target_id, user_id=request.user.id, defaults={'value': value}) + return Response({'value': value}) + + +class QuestionVoteView(_VoteBase): + kind = 'question' + + @extend_schema(request=None, responses=OpenApiTypes.OBJECT, tags=['Curriculum (content)']) + def post(self, request, question_id: int): + return super().post(request, question_id=question_id) + + def _exists(self, target_id): + return Question.objects.filter(pk=target_id).exists() + + +class LessonVoteView(_VoteBase): + kind = 'lesson' + + @extend_schema(request=None, responses=OpenApiTypes.OBJECT, tags=['Curriculum (content)']) + def post(self, request, lesson_id: int): + return super().post(request, lesson_id=lesson_id) + + def _exists(self, target_id): + return Lesson.objects.filter(pk=target_id).exists() + + +class LessonReportView(APIView): + """POST /api/lessons/{id}/report — «متنِ این درس ایراد دارد» (همتای گزارشِ سوال).""" + + permission_classes = [IsAuthenticated] + throttle_scope = 'question_report' + throttle_classes = [ScopedRateThrottle] + + @extend_schema(request=LessonReportRequestSerializer, responses=QuestionReportResponseSerializer, + tags=['Curriculum (content)']) + def post(self, request, lesson_id: int): + lesson = Lesson.objects.filter(pk=lesson_id).first() + if lesson is None: + raise NotFound('درس یافت نشد.') + serializer = LessonReportRequestSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + report, created = LessonReport.objects.get_or_create( + lesson=lesson, user_id=request.user.id, status='open', + defaults={'reason': serializer.validated_data['reason'], 'note': serializer.validated_data.get('note', '')}, + ) + return Response( + QuestionReportResponseSerializer({'success': True, 'reportId': report.pk, 'alreadyReported': not created}).data, + status=status.HTTP_201_CREATED if created else status.HTTP_200_OK, + ) + + class NodeQuizView(APIView): """ GET /api/nodes/{id}/quiz — یک آزمونِ آماده برای کلِ مبحث.