Skip to content

Commit 5b2ea7b

Browse files
authored
Merge pull request #5 from gmickel:general-improvements
Refactor OpenEHR Quest into a dynamic, markdown-driven quiz application
2 parents dcc4d63 + c074ea4 commit 5b2ea7b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2027
-947
lines changed

.github/workflows/deploy.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ name: Deploy static content to Pages
44
on:
55
# Runs on pushes targeting the default branch
66
push:
7-
branches: ['main']
7+
branches: [main]
88

99
# Allows you to run this workflow manually from the Actions tab
1010
workflow_dispatch:
@@ -17,7 +17,7 @@ permissions:
1717

1818
# Allow one concurrent deployment
1919
concurrency:
20-
group: 'pages'
20+
group: pages
2121
cancel-in-progress: true
2222

2323
jobs:
@@ -44,7 +44,7 @@ jobs:
4444
uses: actions/upload-pages-artifact@v3
4545
with:
4646
# Upload dist folder
47-
path: './dist'
47+
path: ./dist
4848
- name: Deploy to GitHub Pages
4949
id: deployment
5050
uses: actions/deploy-pages@v4

bun.lockb

4.75 KB
Binary file not shown.

components.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
"components": "@/components",
1515
"utils": "@/lib/utils"
1616
}
17-
}
17+
}

example-question.md

+142
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
---
2+
title: The Ultimate Coding Challenge
3+
description: Test your programming skills across various languages and concepts!
4+
level: 1
5+
correctAnswer: 2
6+
difficulty: "Intermediate"
7+
timeLimit: 20
8+
---
9+
10+
## Context
11+
12+
### Introduction
13+
14+
Welcome to the Ultimate Coding Challenge! This quest will test your knowledge of **programming concepts, algorithms, and problem-solving skills**. Are you ready to prove your coding prowess?
15+
16+
Test of code highlighting:
17+
18+
inline code: `console.log('Hello, Alice!');`
19+
20+
```python
21+
def decorator(func):
22+
def wrapper(*args, **kwargs):
23+
print("Before function call")
24+
result = func(*args, **kwargs)
25+
print("After function call")
26+
return result
27+
return wrapper
28+
```
29+
30+
### Question
31+
32+
You're tasked with implementing a function to find the most frequent element in an array. The function should work efficiently for large arrays. Consider the following requirements:
33+
34+
1. The function should handle arrays of integers.
35+
2. If there are multiple elements with the same highest frequency, return any one of them.
36+
3. The function should have a time complexity better than O(n^2).
37+
38+
```go
39+
func mostFrequent(arr []int) int {
40+
maxCount := 0
41+
result := arr[0]
42+
for i := range arr {
43+
count := 0
44+
for j := range arr {
45+
if arr[i] == arr[j] {
46+
count++
47+
}
48+
}
49+
if count > maxCount {
50+
maxCount = count
51+
result = arr[i]
52+
}
53+
}
54+
return result
55+
}
56+
```
57+
58+
How would you implement this function?
59+
60+
### Outro
61+
62+
__Efficient__ array manipulation and understanding of data structures are crucial skills for any programmer. This problem tests your ability to balance time complexity with code readability.
63+
64+
## Answers
65+
66+
- Use nested loops to count occurrences of each element:
67+
68+
```python
69+
def most_frequent(arr):
70+
max_count = 0
71+
result = arr[0]
72+
for i in range(len(arr)):
73+
count = 0
74+
for j in range(len(arr)):
75+
if arr[i] == arr[j]:
76+
count += 1
77+
if count > max_count:
78+
max_count = count
79+
result = arr[i]
80+
return result
81+
```
82+
83+
- Use a hash map to count occurrences in a single pass:
84+
85+
```python
86+
from collections import defaultdict
87+
88+
def most_frequent(arr):
89+
count = defaultdict(int)
90+
for num in arr:
91+
count[num] += 1
92+
return max(count, key=count.get)
93+
```
94+
95+
- Sort the array and count consecutive elements:
96+
97+
```python
98+
def most_frequent(arr):
99+
arr.sort()
100+
max_count = 1
101+
res = arr[0]
102+
curr_count = 1
103+
for i in range(1, len(arr)):
104+
if arr[i] == arr[i-1]:
105+
curr_count += 1
106+
else:
107+
if curr_count > max_count:
108+
max_count = curr_count
109+
res = arr[i-1]
110+
curr_count = 1
111+
return res
112+
```
113+
114+
- Use a set to eliminate duplicates, then count occurrences:
115+
116+
```python
117+
def most_frequent(arr):
118+
return max(set(arr), key=arr.count)
119+
```
120+
121+
## Explanation
122+
123+
The correct answer is option 2: Using a hash map to count occurrences in a single pass.
124+
125+
This solution is optimal because:
126+
127+
1. It has a time complexity of O(n), where n is the length of the array.
128+
2. It only requires a single pass through the array.
129+
3. The space complexity is O(k), where k is the number of unique elements in the array.
130+
131+
Here's a breakdown of how the function works:
132+
133+
1. `defaultdict(int)` creates a dictionary where any new key is automatically initialized with a value of 0.
134+
2. The loop `for num in arr:` iterates through each element in the array.
135+
3. `count[num] += 1` increments the count for each number.
136+
4. `max(count, key=count.get)` returns the key (number) with the highest count.
137+
138+
This solution efficiently handles large arrays and meets all the specified requirements.
139+
140+
## Hint
141+
142+
Think about data structures that allow for fast lookups and updates. How can you keep track of counts while only passing through the array once?

package.json

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,22 @@
1818
},
1919
"dependencies": {
2020
"@radix-ui/react-alert-dialog": "1.1.1",
21+
"@radix-ui/react-collapsible": "1.1.0",
2122
"@radix-ui/react-progress": "1.1.0",
2223
"@radix-ui/react-slot": "1.1.0",
2324
"@radix-ui/react-tooltip": "1.1.2",
2425
"class-variance-authority": "0.7.0",
2526
"clsx": "2.1.1",
27+
"gray-matter": "^4.0.3",
2628
"lucide-react": "0.408.0",
29+
"marked": "^13.0.2",
2730
"react": "18.3.1",
2831
"react-confetti": "6.1.0",
2932
"react-dom": "18.3.1",
3033
"shiki": "1.10.3",
3134
"tailwind-merge": "2.4.0",
32-
"tailwindcss-animate": "1.0.7"
35+
"tailwindcss-animate": "1.0.7",
36+
"yaml": "^2.4.5"
3337
},
3438
"devDependencies": {
3539
"@antfu/eslint-config": "2.23.0",

src/App.css

-42
This file was deleted.

src/App.tsx

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
import OpenEHRQuest from '@/components/openEHRQuest';
1+
import Quiz from '@/components/Quiz';
22

33
function App() {
44
return (
5-
<div className="App">
6-
<OpenEHRQuest />
7-
</div>
5+
<Quiz />
86
);
97
}
108

src/components/CodeHighlight.tsx

+20-6
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@ import { codeToHtml } from 'shiki';
44
interface CodeHighlightProps {
55
code: string;
66
language: string;
7+
variant?: 'block' | 'inline';
78
}
89

9-
const CodeHighlight: React.FC<CodeHighlightProps> = ({ code, language }) => {
10+
const CodeHighlight: React.FC<CodeHighlightProps> = ({ code, language, variant = 'block' }) => {
1011
const [highlightedCode, setHighlightedCode] = useState<string>('');
1112
const [isLoading, setIsLoading] = useState(true);
1213

@@ -16,29 +17,42 @@ const CodeHighlight: React.FC<CodeHighlightProps> = ({ code, language }) => {
1617
try {
1718
const html = await codeToHtml(code, {
1819
lang: language,
19-
theme: 'github-dark', // You can change this to any theme you prefer
20+
theme: variant === 'inline' ? 'github-light' : 'night-owl',
2021
});
2122
setHighlightedCode(html);
2223
}
2324
catch (error) {
2425
console.error('Error highlighting code:', error);
25-
setHighlightedCode(`<pre><code>${code}</code></pre>`);
26+
setHighlightedCode(`<code>${code}</code>`);
2627
}
2728
finally {
2829
setIsLoading(false);
2930
}
3031
};
3132

3233
highlight();
33-
}, [code, language]);
34+
}, [code, language, variant]);
3435

3536
if (isLoading) {
36-
return <div>Loading...</div>;
37+
return <span>Loading...</span>;
38+
}
39+
40+
if (variant === 'inline') {
41+
// For inline, we'll strip the pre and code tags and just return the highlighted content
42+
43+
/*
44+
const strippedHtml = highlightedCode
45+
.replace(/<pre.*?>/g, '')
46+
.replace(/<\/pre>/g, '')
47+
.replace(/<code.*?>/g, '')
48+
.replace(/<\/code>/g, '');
49+
*/
50+
return <span dangerouslySetInnerHTML={{ __html: highlightedCode }} />;
3751
}
3852

3953
return (
4054
<div
41-
className="rounded-md overflow-hidden"
55+
className="overflow-hidden"
4256
dangerouslySetInnerHTML={{ __html: highlightedCode }}
4357
/>
4458
);

src/components/Quiz/Answers.tsx

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import React from 'react';
2+
import { Button } from '@/components/ui/button';
3+
import RenderContent from '@/components/RenderContent';
4+
import { cn } from '@/lib/utils';
5+
6+
interface AnswersProps {
7+
answers: string[];
8+
onAnswer: (index: number) => void;
9+
disabled: boolean;
10+
selectedAnswer: number | null;
11+
correctAnswer: number;
12+
answered: boolean;
13+
}
14+
15+
const Answers: React.FC<AnswersProps> = ({
16+
answers,
17+
onAnswer,
18+
disabled,
19+
selectedAnswer,
20+
correctAnswer,
21+
answered,
22+
}) => {
23+
return (
24+
<div className="space-y-4 mt-4">
25+
<h2 className="text-lg font-semibold">Answers</h2>
26+
{answers.map((answer, index) => {
27+
const isSelected = selectedAnswer === index;
28+
const isCorrect = correctAnswer - 1 === index;
29+
30+
let buttonClass = '';
31+
if (answered) {
32+
if (isCorrect) {
33+
buttonClass = 'bg-green-100 hover:bg-green-200 border-green-500';
34+
}
35+
else if (isSelected) {
36+
buttonClass = 'bg-red-100 hover:bg-red-200 border-red-500';
37+
}
38+
}
39+
40+
return (
41+
<Button
42+
key={`answer-${index}`}
43+
onClick={() => onAnswer(index)}
44+
className={cn(
45+
'w-full justify-start text-left h-auto whitespace-pre-wrap',
46+
buttonClass,
47+
)}
48+
variant="outline"
49+
disabled={disabled}
50+
>
51+
<div className="text-sm">
52+
<RenderContent content={answer} isInline={true} />
53+
</div>
54+
</Button>
55+
);
56+
})}
57+
</div>
58+
);
59+
};
60+
61+
export default Answers;

0 commit comments

Comments
 (0)