1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * π LeetCode Progress Counter
5
+ * Automatically counts solved problems and tracks progress
6
+ */
7
+
8
+ const fs = require ( 'fs' ) ;
9
+ const path = require ( 'path' ) ;
10
+
11
+ class LeetCodeTracker {
12
+ constructor ( ) {
13
+ this . contestDir = 'Daily-contest' ;
14
+ this . startDate = new Date ( '2025-10-01' ) ;
15
+ this . targetDays = 90 ;
16
+ }
17
+
18
+ /**
19
+ * Count all solved problems (.java files)
20
+ */
21
+ countProblems ( ) {
22
+ let problemCount = 0 ;
23
+ let folderCount = 0 ;
24
+
25
+ try {
26
+ if ( ! fs . existsSync ( this . contestDir ) ) {
27
+ console . log ( `π Creating ${ this . contestDir } directory...` ) ;
28
+ fs . mkdirSync ( this . contestDir ) ;
29
+ return { problems : 0 , folders : 0 } ;
30
+ }
31
+
32
+ const folders = fs . readdirSync ( this . contestDir ) ;
33
+
34
+ folders . forEach ( folder => {
35
+ const folderPath = path . join ( this . contestDir , folder ) ;
36
+
37
+ if ( fs . statSync ( folderPath ) . isDirectory ( ) ) {
38
+ folderCount ++ ;
39
+ const files = fs . readdirSync ( folderPath ) ;
40
+
41
+ // Count .java files as solved problems
42
+ const javaFiles = files . filter ( file => file . endsWith ( '.java' ) ) ;
43
+ problemCount += javaFiles . length ;
44
+
45
+ console . log ( `π ${ folder } : ${ javaFiles . length } problems` ) ;
46
+ }
47
+ } ) ;
48
+
49
+ } catch ( error ) {
50
+ console . error ( 'β Error counting problems:' , error . message ) ;
51
+ return { problems : 0 , folders : 0 } ;
52
+ }
53
+
54
+ return { problems : problemCount , folders : folderCount } ;
55
+ }
56
+
57
+ /**
58
+ * Calculate current challenge day
59
+ */
60
+ getCurrentDay ( ) {
61
+ const today = new Date ( ) ;
62
+ const diffTime = today . getTime ( ) - this . startDate . getTime ( ) ;
63
+ const diffDays = Math . ceil ( diffTime / ( 1000 * 60 * 60 * 24 ) ) ;
64
+
65
+ // Ensure we stay within challenge bounds
66
+ return Math . max ( 1 , Math . min ( diffDays , this . targetDays ) ) ;
67
+ }
68
+
69
+ /**
70
+ * Generate comprehensive stats
71
+ */
72
+ generateStats ( ) {
73
+ const { problems, folders } = this . countProblems ( ) ;
74
+ const currentDay = this . getCurrentDay ( ) ;
75
+ const successRate = currentDay > 0 ? Math . round ( ( problems / currentDay ) * 100 ) : 0 ;
76
+ const daysRemaining = Math . max ( 0 , this . targetDays - currentDay ) ;
77
+ const averageProblemsPerDay = currentDay > 0 ? ( problems / currentDay ) . toFixed ( 2 ) : 0 ;
78
+
79
+ const stats = {
80
+ totalProblems : problems ,
81
+ foldersCreated : folders ,
82
+ currentDay : currentDay ,
83
+ successRate : successRate ,
84
+ challengeStartDate : this . startDate . toISOString ( ) . split ( 'T' ) [ 0 ] ,
85
+ lastUpdated : new Date ( ) . toISOString ( ) ,
86
+ daysRemaining : daysRemaining ,
87
+ targetProblems : this . targetDays ,
88
+ averageProblemsPerDay : parseFloat ( averageProblemsPerDay ) ,
89
+ progressPercentage : Math . round ( ( currentDay / this . targetDays ) * 100 ) ,
90
+ completionStatus : currentDay >= this . targetDays ? 'Completed' : 'In Progress'
91
+ } ;
92
+
93
+ return stats ;
94
+ }
95
+
96
+ /**
97
+ * Save stats to JSON file
98
+ */
99
+ saveStats ( ) {
100
+ const stats = this . generateStats ( ) ;
101
+
102
+ try {
103
+ fs . writeFileSync ( 'stats.json' , JSON . stringify ( stats , null , 2 ) ) ;
104
+ console . log ( 'β
Stats saved to stats.json' ) ;
105
+ return stats ;
106
+ } catch ( error ) {
107
+ console . error ( 'β Error saving stats:' , error . message ) ;
108
+ return null ;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Display progress summary
114
+ */
115
+ displayProgress ( ) {
116
+ const stats = this . generateStats ( ) ;
117
+
118
+ console . log ( '\nπ === LeetCode Challenge Progress === π' ) ;
119
+ console . log ( `ποΈ Challenge Day: ${ stats . currentDay } /${ this . targetDays } ` ) ;
120
+ console . log ( `β
Problems Solved: ${ stats . totalProblems } ` ) ;
121
+ console . log ( `π Days Documented: ${ stats . foldersCreated } ` ) ;
122
+ console . log ( `π Success Rate: ${ stats . successRate } %` ) ;
123
+ console . log ( `β‘ Average Problems/Day: ${ stats . averageProblemsPerDay } ` ) ;
124
+ console . log ( `β° Days Remaining: ${ stats . daysRemaining } ` ) ;
125
+ console . log ( `π― Progress: ${ stats . progressPercentage } % Complete` ) ;
126
+ console . log ( `π Status: ${ stats . completionStatus } ` ) ;
127
+
128
+ // Progress bar
129
+ const progressBar = 'β' . repeat ( Math . floor ( stats . progressPercentage / 5 ) ) +
130
+ 'β' . repeat ( 20 - Math . floor ( stats . progressPercentage / 5 ) ) ;
131
+ console . log ( `π [${ progressBar } ] ${ stats . progressPercentage } %` ) ;
132
+
133
+ console . log ( '\nπ₯ Keep up the great work! π₯\n' ) ;
134
+
135
+ return stats ;
136
+ }
137
+ }
138
+
139
+ // Main execution
140
+ if ( require . main === module ) {
141
+ const tracker = new LeetCodeTracker ( ) ;
142
+
143
+ // Check command line arguments
144
+ const args = process . argv . slice ( 2 ) ;
145
+
146
+ if ( args . includes ( '--save' ) || args . includes ( '-s' ) ) {
147
+ tracker . saveStats ( ) ;
148
+ }
149
+
150
+ if ( args . includes ( '--quiet' ) || args . includes ( '-q' ) ) {
151
+ // Just generate stats without display
152
+ const stats = tracker . generateStats ( ) ;
153
+ console . log ( JSON . stringify ( stats , null , 2 ) ) ;
154
+ } else {
155
+ // Default: display progress
156
+ tracker . displayProgress ( ) ;
157
+ }
158
+ }
159
+
160
+ module . exports = LeetCodeTracker ;
0 commit comments