Mhdeusi commited on
Commit
6ed882e
·
verified ·
1 Parent(s): c0768a8

Create logic.js

Browse files
Files changed (1) hide show
  1. js/logic/logic.js +403 -0
js/logic/logic.js ADDED
@@ -0,0 +1,403 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class LearningLogic {
2
+ constructor() {
3
+ this.currentDay = 1;
4
+ this.maxDays = 10;
5
+ this.rewardSystem = new RewardSystem();
6
+ this.utils = Utils;
7
+ this.userProgress = this.loadUserProgress();
8
+ }
9
+
10
+ loadUserProgress() {
11
+ const defaultProgress = {
12
+ totalScore: 0,
13
+ completedLessons: [],
14
+ quizScores: {},
15
+ exerciseScores: {},
16
+ lessonScores: {},
17
+ currentStreak: 0,
18
+ lastActivityDate: null,
19
+ achievements: [],
20
+ level: 1,
21
+ timeSpent: 0
22
+ };
23
+
24
+ const savedProgress = this.utils.loadFromLocalStorage('userProgress');
25
+ return { ...defaultProgress, ...savedProgress };
26
+ }
27
+
28
+ saveUserProgress() {
29
+ return this.utils.saveToLocalStorage('userProgress', this.userProgress);
30
+ }
31
+
32
+ async loadLesson(day) {
33
+ try {
34
+ const lessonData = await this.utils.loadJSON(`data/lessons/day${day}.json`);
35
+ return lessonData;
36
+ } catch (error) {
37
+ console.error(`Error loading lesson day ${day}:`, error);
38
+ return null;
39
+ }
40
+ }
41
+
42
+ async loadQuiz(day) {
43
+ try {
44
+ const quizData = await this.utils.loadJSON(`data/quizzes/day${day}.json`);
45
+ return quizData;
46
+ } catch (error) {
47
+ console.error(`Error loading quiz day ${day}:`, error);
48
+ return null;
49
+ }
50
+ }
51
+
52
+ async loadExercise(day) {
53
+ try {
54
+ const exerciseData = await this.utils.loadJSON(`data/exercises/day${day}.json`);
55
+ return exerciseData;
56
+ } catch (error) {
57
+ console.error(`Error loading exercise day ${day}:`, error);
58
+ return null;
59
+ }
60
+ }
61
+
62
+ calculateStreak(results) {
63
+ // محاسبه استریک بر اساس نتایج پی در پی صحیح
64
+ let currentStreak = 0;
65
+ let maxStreak = 0;
66
+
67
+ for (const result of results) {
68
+ if (result.isCorrect) {
69
+ currentStreak++;
70
+ maxStreak = Math.max(maxStreak, currentStreak);
71
+ } else {
72
+ currentStreak = 0;
73
+ }
74
+ }
75
+
76
+ return maxStreak;
77
+ }
78
+
79
+ checkQuizAnswers(day, userAnswers, timeSpent = 0) {
80
+ return this.loadQuiz(day).then(quizData => {
81
+ if (!quizData) {
82
+ throw new Error('Quiz data not found');
83
+ }
84
+
85
+ let correctCount = 0;
86
+ const results = [];
87
+
88
+ quizData.questions.forEach((question, index) => {
89
+ const userAnswer = userAnswers[index];
90
+ const isCorrect = userAnswer === question.correct_index;
91
+
92
+ if (isCorrect) {
93
+ correctCount++;
94
+ }
95
+
96
+ results.push({
97
+ questionId: question.id,
98
+ questionText: question.question,
99
+ userAnswer: userAnswer,
100
+ correctAnswer: question.correct_index,
101
+ isCorrect: isCorrect,
102
+ explanation: question.explanation || ''
103
+ });
104
+ });
105
+
106
+ const totalQuestions = quizData.questions.length;
107
+ const streak = this.calculateStreak(results);
108
+ const reward = this.rewardSystem.calculateQuizReward(
109
+ correctCount,
110
+ totalQuestions,
111
+ timeSpent,
112
+ streak
113
+ );
114
+
115
+ // به‌روزرسانی پیشرفت کاربر
116
+ this.updateUserProgress({
117
+ score: reward,
118
+ completedQuiz: `day_${day}`,
119
+ correctAnswers: correctCount,
120
+ totalQuestions: totalQuestions
121
+ });
122
+
123
+ const feedback = this.rewardSystem.getRewardFeedback(
124
+ reward,
125
+ totalQuestions * 3,
126
+ 'quiz'
127
+ );
128
+
129
+ return {
130
+ results: results,
131
+ correctCount: correctCount,
132
+ totalQuestions: totalQuestions,
133
+ reward: reward,
134
+ feedback: feedback,
135
+ streak: streak
136
+ };
137
+ });
138
+ }
139
+
140
+ checkExerciseAnswer(day, userAnswer) {
141
+ return this.loadExercise(day).then(exerciseData => {
142
+ if (!exerciseData) {
143
+ throw new Error('Exercise data not found');
144
+ }
145
+
146
+ const exercise = exerciseData.exercise;
147
+ const userAnswerLower = userAnswer.toLowerCase();
148
+
149
+ let matches = 0;
150
+ const matchedKeywords = [];
151
+
152
+ exercise.expected_keywords.forEach(keyword => {
153
+ const keywordLower = keyword.toLowerCase();
154
+ // جستجوی کلمات کلیدی در پاسخ کاربر
155
+ if (userAnswerLower.includes(keywordLower)) {
156
+ matches++;
157
+ matchedKeywords.push(keyword);
158
+ }
159
+ });
160
+
161
+ const matchThreshold = exercise.match_threshold || 0.6;
162
+ const isCorrect = matches >= exercise.expected_keywords.length * matchThreshold;
163
+
164
+ const reward = this.rewardSystem.calculateExerciseReward(
165
+ isCorrect,
166
+ matches,
167
+ exercise.expected_keywords.length,
168
+ exercise.complexity || 1
169
+ );
170
+
171
+ // به‌روزرسانی پیشرفت کاربر
172
+ if (isCorrect) {
173
+ this.updateUserProgress({
174
+ score: reward,
175
+ completedExercise: `day_${day}`,
176
+ keywordMatches: matches,
177
+ totalKeywords: exercise.expected_keywords.length
178
+ });
179
+ }
180
+
181
+ const feedback = this.rewardSystem.getRewardFeedback(
182
+ reward,
183
+ 25,
184
+ 'exercise'
185
+ );
186
+
187
+ return {
188
+ isCorrect: isCorrect,
189
+ matchedKeywords: matchedKeywords,
190
+ expectedKeywords: exercise.expected_keywords,
191
+ reward: reward,
192
+ feedback: feedback,
193
+ hint: exercise.hint || ''
194
+ };
195
+ });
196
+ }
197
+
198
+ completeLesson(day, duration, interactions = 0) {
199
+ const reward = this.rewardSystem.calculateLessonReward(duration, interactions);
200
+
201
+ this.updateUserProgress({
202
+ score: reward,
203
+ completedLesson: day,
204
+ lessonDuration: duration,
205
+ interactions: interactions
206
+ });
207
+
208
+ const feedback = this.rewardSystem.getRewardFeedback(reward, 20, 'lesson');
209
+
210
+ return {
211
+ reward: reward,
212
+ feedback: feedback,
213
+ completed: true
214
+ };
215
+ }
216
+
217
+ updateUserProgress(updates) {
218
+ const previousScore = this.userProgress.totalScore;
219
+ const previousStreak = this.userProgress.currentStreak;
220
+
221
+ // به‌روزرسانی امتیاز
222
+ if (updates.score) {
223
+ this.userProgress.totalScore += updates.score;
224
+ }
225
+
226
+ // به‌روزرسانی درس‌های تکمیل شده
227
+ if (updates.completedLesson && !this.userProgress.completedLessons.includes(updates.completedLesson)) {
228
+ this.userProgress.completedLessons.push(updates.completedLesson);
229
+ }
230
+
231
+ // به‌روزرسانی نتایج کوییز
232
+ if (updates.completedQuiz) {
233
+ this.userProgress.quizScores[updates.completedQuiz] = {
234
+ score: updates.score,
235
+ correctAnswers: updates.correctAnswers,
236
+ totalQuestions: updates.totalQuestions,
237
+ completedAt: new Date().toISOString()
238
+ };
239
+ }
240
+
241
+ // به‌روزرسانی نتایج تمرین
242
+ if (updates.completedExercise) {
243
+ this.userProgress.exerciseScores[updates.completedExercise] = {
244
+ score: updates.score,
245
+ keywordMatches: updates.keywordMatches,
246
+ totalKeywords: updates.totalKeywords,
247
+ completedAt: new Date().toISOString()
248
+ };
249
+ }
250
+
251
+ // به‌روزرسانی استریک
252
+ this.updateStreak();
253
+
254
+ // بررسی دستاوردها
255
+ this.checkAchievements();
256
+
257
+ // محاسبه سطح
258
+ const levelInfo = this.rewardSystem.calculateLevel(this.userProgress.totalScore);
259
+ this.userProgress.level = levelInfo.level;
260
+
261
+ // ذخیره پیشرفت
262
+ this.saveUserProgress();
263
+
264
+ // بازگشت اطلاعات تغییرات
265
+ return {
266
+ scoreIncrease: this.userProgress.totalScore - previousScore,
267
+ streakIncrease: this.userProgress.currentStreak - previousStreak,
268
+ newLevel: levelInfo.level !== Math.floor(this.rewardSystem.calculateLevel(previousScore).level),
269
+ levelInfo: levelInfo
270
+ };
271
+ }
272
+
273
+ updateStreak() {
274
+ const today = this.utils.getCurrentDate();
275
+ const lastActivity = this.userProgress.lastActivityDate;
276
+
277
+ if (lastActivity === today) {
278
+ return; // امروز قبلاً فعالیت داشته
279
+ }
280
+
281
+ if (!lastActivity) {
282
+ // اولین فعالیت
283
+ this.userProgress.currentStreak = 1;
284
+ } else {
285
+ const lastDate = new Date(lastActivity);
286
+ const currentDate = new Date(today);
287
+ const diffTime = currentDate - lastDate;
288
+ const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
289
+
290
+ if (diffDays === 1) {
291
+ // فعالیت متوالی
292
+ this.userProgress.currentStreak++;
293
+ } else if (diffDays > 1) {
294
+ // شکستن استریک
295
+ this.userProgress.currentStreak = 1;
296
+ }
297
+ }
298
+
299
+ this.userProgress.lastActivityDate = today;
300
+ }
301
+
302
+ checkAchievements() {
303
+ const achievements = [];
304
+ const currentAchievements = this.userProgress.achievements || [];
305
+
306
+ // دستاورد اولین درس
307
+ if (this.userProgress.completedLessons.length >= 1 &&
308
+ !currentAchievements.includes('first_lesson')) {
309
+ achievements.push('first_lesson');
310
+ }
311
+
312
+ // دستاورد استاد کوییز
313
+ const perfectQuizzes = Object.values(this.userProgress.quizScores)
314
+ .filter(quiz => quiz.correctAnswers === quiz.totalQuestions).length;
315
+ if (perfectQuizzes >= 5 && !currentAchievements.includes('quiz_master')) {
316
+ achievements.push('quiz_master');
317
+ }
318
+
319
+ // دستاورد تمرین کامل
320
+ const completedExercises = Object.keys(this.userProgress.exerciseScores).length;
321
+ if (completedExercises >= 3 && !currentAchievements.includes('exercise_pro')) {
322
+ achievements.push('exercise_pro');
323
+ }
324
+
325
+ // دستاورد استریک
326
+ if (this.userProgress.currentStreak >= 7 &&
327
+ !currentAchievements.includes('week_streak')) {
328
+ achievements.push('week_streak');
329
+ }
330
+
331
+ // اضافه کردن دستاوردهای جدید
332
+ achievements.forEach(achievement => {
333
+ if (!currentAchievements.includes(achievement)) {
334
+ this.userProgress.achievements.push(achievement);
335
+ // اعطای پاداش دستاورد
336
+ const reward = this.rewardSystem.getAchievementReward(achievement);
337
+ this.userProgress.totalScore += reward;
338
+ }
339
+ });
340
+
341
+ return achievements;
342
+ }
343
+
344
+ getUserStats() {
345
+ const completedLessons = this.userProgress.completedLessons.length;
346
+ const completedQuizzes = Object.keys(this.userProgress.quizScores).length;
347
+ const completedExercises = Object.keys(this.userProgress.exerciseScores).length;
348
+
349
+ const totalQuizzes = Object.values(this.userProgress.quizScores).reduce(
350
+ (sum, quiz) => sum + quiz.totalQuestions, 0
351
+ );
352
+ const correctQuizzes = Object.values(this.userProgress.quizScores).reduce(
353
+ (sum, quiz) => sum + quiz.correctAnswers, 0
354
+ );
355
+
356
+ const accuracy = totalQuizzes > 0 ? (correctQuizzes / totalQuizzes) * 100 : 0;
357
+
358
+ return {
359
+ totalScore: this.userProgress.totalScore,
360
+ level: this.userProgress.level,
361
+ streak: this.userProgress.currentStreak,
362
+ completedLessons: completedLessons,
363
+ completedQuizzes: completedQuizzes,
364
+ completedExercises: completedExercises,
365
+ accuracy: Math.round(accuracy),
366
+ achievements: this.userProgress.achievements.length,
367
+ rank: this.rewardSystem.getRankTitle(this.userProgress.level)
368
+ };
369
+ }
370
+
371
+ resetProgress() {
372
+ this.userProgress = {
373
+ totalScore: 0,
374
+ completedLessons: [],
375
+ quizScores: {},
376
+ exerciseScores: {},
377
+ lessonScores: {},
378
+ currentStreak: 0,
379
+ lastActivityDate: null,
380
+ achievements: [],
381
+ level: 1,
382
+ timeSpent: 0
383
+ };
384
+ this.saveUserProgress();
385
+ return this.userProgress;
386
+ }
387
+
388
+ getLeaderboard(limit = 10) {
389
+ // در این نسخه ساده، فقط کاربر فعلی نمایش داده می‌شود
390
+ // در نسخه‌های آینده می‌توان از سرور استفاده کرد
391
+ const stats = this.getUserStats();
392
+ return [{
393
+ username: 'شما',
394
+ score: stats.totalScore,
395
+ level: stats.level,
396
+ rank: stats.rank,
397
+ streak: stats.streak
398
+ }];
399
+ }
400
+ }
401
+
402
+ // ایجاد نمونه اصلی
403
+ const learningLogic = new LearningLogic();