Skip to content

Commit f1b083a

Browse files
feat: add mock statistics
1 parent 92c14a6 commit f1b083a

File tree

1 file changed

+87
-42
lines changed

1 file changed

+87
-42
lines changed

src/lib/problem_ui.py

Lines changed: 87 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from rich.style import Style
88
from rich.text import Text
99
from rich.align import Align
10-
from bs4 import BeautifulSoup
10+
from bs4 import BeautifulSoup, Tag
1111
import json
1212
from dataclasses import dataclass
1313
from typing import List, Dict, Optional
@@ -36,7 +36,6 @@ def __init__(self, problem_data: dict):
3636
)
3737
self.code_snippets: List[Dict] = problem_data['codeSnippets']
3838

39-
# Parse metadata
4039
self.function_metadata: Optional[FunctionMetadata] = None
4140
try:
4241
metadata = json.loads(problem_data['metaData'])
@@ -48,6 +47,10 @@ def __init__(self, problem_data: dict):
4847
except Exception:
4948
pass
5049

50+
self.total_accepted: int = problem_data.get('totalAccepted', 0)
51+
self.total_submissions: int = problem_data.get('totalSubmissions', 0)
52+
self.acceptance_rate: float = problem_data.get('acRate', 0)
53+
5154
self._parse_content()
5255
self.console_width = console.width
5356

@@ -82,16 +85,6 @@ def _parse_content(self):
8285
else:
8386
current_section.append(text)
8487

85-
@property
86-
def formatted_description(self) -> str:
87-
"""Get the formatted problem description"""
88-
sections = [
89-
' '.join(self.description),
90-
*self.examples,
91-
*self.constraints
92-
]
93-
return '\n'.join(line for line in sections if line.strip())
94-
9588
@property
9689
def available_languages(self) -> List[str]:
9790
"""Get list of available programming languages"""
@@ -138,17 +131,16 @@ def _create_header(self):
138131
}
139132
difficulty_color = difficulty_colors.get(self.difficulty, 'white')
140133

141-
header = Text()
142-
header.append(f"{self.question_id}. {self.title}", style="bold cyan")
143-
header.append(" ", style="dim")
144-
header.append(self.difficulty, style=difficulty_color)
134+
header = (
135+
f"[bold cyan]{self.question_id}. {self.title}[/] "
136+
f"[{difficulty_color}]{self.difficulty}[/]"
137+
)
145138

146-
return Align.center(header)
139+
return header
147140

148141
def _format_description(self, html_content: str) -> str:
149142
"""Format the problem description, removing example test cases"""
150143
soup = BeautifulSoup(html_content, 'html.parser')
151-
typer.echo(soup.prettify())
152144

153145
# Remove all pre tags and example sections
154146
for pre in soup.find_all('pre'):
@@ -163,9 +155,16 @@ def _format_description(self, html_content: str) -> str:
163155
for code in soup.find_all('code'):
164156
code.replace_with(BeautifulSoup(f'`{code.text}`', 'html.parser'))
165157

166-
# Format strong and em tags
167-
for strong in soup.find_all('strong'):
168-
strong.replace_with(BeautifulSoup(f'**{strong.text}**', 'html.parser'))
158+
# Format HTML formatting tags
159+
for tag in soup.find_all(['strong', 'em', 'b', 'i']):
160+
if not isinstance(tag, Tag):
161+
continue
162+
text = tag.text.strip()
163+
if tag.name in ['strong', 'b']:
164+
replacement = f"**{text}**"
165+
elif tag.name in ['em', 'i']:
166+
replacement = f"_{text}_"
167+
tag.replace_with(BeautifulSoup(replacement, 'html.parser'))
169168

170169
for em in soup.find_all('em'):
171170
em.replace_with(BeautifulSoup(f'_{em.text}_', 'html.parser'))
@@ -184,49 +183,87 @@ def _format_test_cases(self):
184183

185184
# Extract example explanations from HTML content
186185
soup = BeautifulSoup(self.content, 'html.parser')
187-
explanations = []
188-
for strong in soup.find_all('strong'):
189-
if 'Example' in strong.text:
190-
parent = strong.find_parent(['p', 'div'])
191-
if parent:
192-
explanations.append(parent.get_text())
193-
194-
# Combine test cases with their explanations
195-
for i, (test, explanation) in enumerate(zip(examples, explanations)):
196-
test_cases.append(
197-
f"[bold blue]Example {i + 1}:[/]\n"
198-
f"[cyan]Input:[/] {test}\n"
199-
f"{explanation.replace('Example ' + str(i + 1) + ':', '[yellow]Explanation:[/]')}"
186+
187+
examples_data = []
188+
189+
# Find all pre tags containing example data
190+
for pre in soup.find_all('pre'):
191+
# Extract input, output, and explanation
192+
if isinstance(pre, Tag):
193+
input_tag = pre.find('strong', text='Input:')
194+
output_tag = pre.find('strong', text='Output:')
195+
explanation_tag = pre.find('strong', text='Explanation:')
196+
197+
if input_tag and output_tag:
198+
input_text = str(input_tag.next_sibling).strip() if input_tag and input_tag.next_sibling else ""
199+
output_text = str(output_tag.next_sibling).strip() if output_tag and output_tag.next_sibling else ""
200+
explanation_text = str(explanation_tag.next_sibling).strip() if explanation_tag and explanation_tag.next_sibling else ""
201+
202+
examples_data.append({
203+
'input': input_text,
204+
'output': output_text,
205+
'explanation': explanation_text
206+
})
207+
208+
# Format the examples
209+
for i, example in enumerate(examples_data, 1):
210+
formatted_example = (
211+
f"[bold blue]Example {i}: [/]\n\n"
212+
f"[cyan]Input: [/]{example['input']}\n"
213+
f"[cyan]Output: [/]{example['output']}"
200214
)
215+
if example['explanation']:
216+
formatted_example += f"\n[yellow]Explanation: [/]{example['explanation']}"
217+
test_cases.append(formatted_example)
201218

202219
return "\n\n".join(test_cases)
203220

221+
def _format_stats(self) -> str:
222+
"""Format problem statistics"""
223+
acceptance_rate = f"{self.acceptance_rate:.1f}%" if self.acceptance_rate else "N/A"
224+
total_accepted = f"{self.total_accepted:,}" if self.total_accepted else "N/A"
225+
total_submissions = f"{self.total_submissions:,}" if self.total_submissions else "N/A"
226+
227+
return (
228+
"[bold blue]Problem Stats[/]\n\n"
229+
f"[cyan]Acceptance Rate:[/] {acceptance_rate}\n"
230+
f"[cyan]Total Accepted:[/] {total_accepted}\n"
231+
f"[cyan]Total Submissions:[/] {total_submissions}"
232+
)
233+
204234
def display(self):
205235
"""Display the problem details"""
206-
# Clear screen and show header
207236
console.clear()
208-
console.print(self._create_header())
209237
console.print()
210238

239+
test_cases = self._format_test_cases()
240+
stats = self._format_stats()
241+
211242
# Create main layout
212243
layout = Layout()
244+
245+
# Split into left and right sections
213246
layout.split_row(
214247
Layout(name="description", ratio=2),
215-
Layout(name="examples", ratio=1)
248+
Layout(name="right_panel", ratio=1)
249+
)
250+
251+
# Split right panel into examples and stats
252+
layout["right_panel"].split_column(
253+
Layout(name="examples"),
254+
Layout(name="stats", size=10)
216255
)
217256

218257
# Description panel
219-
description = self._format_description(self.content)
220258
layout["description"].update(Panel(
221-
Markdown(description),
259+
Markdown(self._format_description(self.content)),
222260
box=ROUNDED,
223-
title="[bold blue]Description",
261+
title=str(self._create_header()),
224262
border_style="blue",
225263
padding=(1, 2)
226264
))
227265

228266
# Example test cases panel
229-
test_cases = self._format_test_cases()
230267
layout["examples"].update(Panel(
231268
test_cases,
232269
box=ROUNDED,
@@ -235,5 +272,13 @@ def display(self):
235272
padding=(1, 2)
236273
))
237274

238-
# Display the layout
275+
# Stats panel
276+
layout["stats"].update(Panel(
277+
stats,
278+
box=ROUNDED,
279+
title="[bold blue]Statistics",
280+
border_style="blue",
281+
padding=(1, 2)
282+
))
283+
239284
console.print(layout)

0 commit comments

Comments
 (0)