some more info and some difficulty added!
This commit is contained in:
13
app.py
13
app.py
@@ -41,13 +41,14 @@ def index():
|
||||
db_path = Path(__file__).parent / 'problems.sqlite3'
|
||||
conn = sqlite3.connect(db_path)
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT folder, description, test_code FROM problems')
|
||||
#<!-- The query was fucked up so it fetched the fucking testcode -->
|
||||
c.execute('SELECT folder, description, test_code, difficulty FROM problems')
|
||||
problems = c.fetchall()
|
||||
conn.close()
|
||||
# Get leaderboard entries
|
||||
leaderboard = get_leaderboard()
|
||||
# Map folder to title for display
|
||||
problem_titles = {folder: folder.replace('_', ' ').title() for folder, _, _ in problems}
|
||||
problem_titles = {folder: folder.replace('_', ' ').title() for folder, _, _, _ in problems}
|
||||
return render_template('index.html', problems=problems, leaderboard=leaderboard, problem_titles=problem_titles)
|
||||
|
||||
@app.route('/problem/new', methods=['GET', 'POST'])
|
||||
@@ -67,17 +68,21 @@ def view_problem(folder):
|
||||
db_path = Path(__file__).parent / 'problems.sqlite3'
|
||||
conn = sqlite3.connect(db_path)
|
||||
c = conn.cursor()
|
||||
c.execute('SELECT folder, description, test_code FROM problems WHERE folder = ?', (folder,))
|
||||
c.execute('SELECT folder, description,test_code , difficulty FROM problems WHERE folder = ?', (folder,))
|
||||
row = c.fetchone()
|
||||
conn.close()
|
||||
|
||||
if not row:
|
||||
return 'Problem not found', 404
|
||||
|
||||
problem = {
|
||||
'folder': row[0],
|
||||
'description': row[1],
|
||||
'test_code': row[2],
|
||||
'difficulty': row[2],
|
||||
'test_code': row[3], # This is used internally, not displayed
|
||||
'title': row[0].replace('_', ' ').title()
|
||||
}
|
||||
|
||||
result = None
|
||||
if request.method == 'POST':
|
||||
user_code = request.form['user_code']
|
||||
|
||||
@@ -35,6 +35,7 @@ class ProblemScannerThread(threading.Thread):
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
folder TEXT,
|
||||
description TEXT,
|
||||
difficulty TEXT,
|
||||
test_code TEXT
|
||||
)''')
|
||||
conn.commit()
|
||||
@@ -65,13 +66,18 @@ class ProblemScannerThread(threading.Thread):
|
||||
description = f.read()
|
||||
with open(test_path, 'r', encoding='utf-8') as f:
|
||||
test_code = f.read()
|
||||
with open(manifest_path, 'r', encoding='utf-8') as f:
|
||||
manifest = json.load(f)
|
||||
|
||||
difficulty = manifest.get('difficulty', 'unknown')
|
||||
|
||||
problems.append({
|
||||
'folder': folder.name,
|
||||
'description': description,
|
||||
'test_code': test_code
|
||||
'test_code': test_code,
|
||||
'difficulty': difficulty
|
||||
})
|
||||
print(f"Found problem: {folder.name}")
|
||||
print(f"Found problem: {folder.name} ; Difficulty: {difficulty}")
|
||||
except Exception as e:
|
||||
print(f"Error reading problem files for {folder.name}: {e}")
|
||||
else:
|
||||
@@ -99,8 +105,10 @@ class ProblemScannerThread(threading.Thread):
|
||||
|
||||
# Insert new problems
|
||||
for p in problems:
|
||||
c.execute('INSERT INTO problems (folder, description, test_code) VALUES (?, ?, ?)',
|
||||
(p['folder'], p['description'], p['test_code']))
|
||||
c.execute('''INSERT INTO problems
|
||||
(folder, description, difficulty, test_code)
|
||||
VALUES (?, ?, ?, ?)''',
|
||||
(p['folder'], p['description'], p['difficulty'], p['test_code']))
|
||||
|
||||
conn.commit()
|
||||
print(f"Updated database with {len(problems)} problems")
|
||||
|
||||
@@ -2,5 +2,6 @@
|
||||
"title": "Fibonacci Sequence",
|
||||
"description": "Calculate the n-th Fibonacci number using a function. The Fibonacci sequence is defined as follows: F(0) = 0, F(1) = 1, and F(n) = F(n-1) + F(n-2) for n > 1.",
|
||||
"description_md": "problems/fibonacisequence/description.md",
|
||||
"difficulty": "medium",
|
||||
"test_code": "problems/fibonacisequence/test.py"
|
||||
}
|
||||
@@ -2,5 +2,6 @@
|
||||
"title":"Reversed String",
|
||||
"description":"Reverse a String using a Function ; Try to write as little code as possible",
|
||||
"description_md":"problems/reversedstring/description.md",
|
||||
"difficulty":"easy",
|
||||
"test_code":"problems/reversedstring/test.py"
|
||||
}
|
||||
@@ -2,5 +2,6 @@
|
||||
"title": "Sort List",
|
||||
"description": "Sort a List with a Function (sortlist); the function is supposed to take the list as an argument and is supposed to return the sorted list and print it.",
|
||||
"description_md": "problems/sortlist/description.md",
|
||||
"difficulty": "easy",
|
||||
"test_code": "problems/sortlist/test.py"
|
||||
}
|
||||
54
readme.md
54
readme.md
@@ -6,23 +6,55 @@ but more lightweight
|
||||
|
||||
if you want to contribute write tests like this:
|
||||
|
||||
### FileStructure:
|
||||
|
||||
In /problems/ create a folder named after the problem.
|
||||
|
||||
In this folder create ```manifest.json, test.py, description.md```
|
||||
|
||||
**Manifest.JSON needs to exsist and _needs_ to look like this:**
|
||||
```json
|
||||
{
|
||||
"title": "Title of the Problem",
|
||||
"description": "Write a very short description here",
|
||||
"description_md": "problems/problempath/description.md",
|
||||
"difficulty": "easy || medium || hard",
|
||||
"test_code": "problems/problempath/test.py"
|
||||
}
|
||||
```
|
||||
I do know it might be a bit tedious but this is required and its the easiest way.
|
||||
|
||||
#### After you've decided on how you would name / write your Test write it like this:
|
||||
|
||||
- It is important to note that you _CAN_ write the Code the User is expected to write firstly. **BUT** after writing the UnitTest and it passing, comment out the written code.
|
||||
|
||||
It is supposed to look something like this (/sortlist/):
|
||||
|
||||
```python
|
||||
"""
|
||||
@TESTSAMPLE.PY / NAME THIS "test.py" in your actual project
|
||||
"""
|
||||
import unittest
|
||||
|
||||
#<!-- The Function the User needs to write -->
|
||||
# This is importantly commented out. The UnitTest tests this if uncommented.
|
||||
# This is only here for reference
|
||||
#
|
||||
# def revstring(x):
|
||||
# return x[::-1]
|
||||
" )) First Point from the List "
|
||||
# def sortlist(lst = [4,3,2,1]) -> list:
|
||||
# return sorted(lst)
|
||||
|
||||
#<!-- This Test, test if the function works -->
|
||||
")) This is a 'easy' Test, if you want you can write more defined ones."
|
||||
class TestSolution(unittest.TestCase):
|
||||
def test_simple(self):
|
||||
# !! This needs to be dynamic ; if the user enters some shit then it is supposed to work too
|
||||
x="";
|
||||
self.assertEqual(revstring(x), x[::-1])
|
||||
def test_sort(self):
|
||||
self.x = []
|
||||
self.assertEqual(sortlist(self.x), sorted(self.x)) # pyright: ignore[reportUndefinedVariable] <- This is only here so that pyright doesnt complain ; NOT NECCESARY!
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
```
|
||||
#### Writing the description:
|
||||
|
||||
**Please** by _God_ write simple and easy to understand terms. If you write like Einstein noone is going to understand you.
|
||||
|
||||
- Syntax:
|
||||
- Normal Markdown.
|
||||
- Start with "##" instead of "#" ; "##" looks better
|
||||
- Use CrossLinks ( something like [W3](https://www.w3schools.com/), or the [PyDocs](https://docs.python.org/3/))
|
||||
- Good Formatting is always appreciated
|
||||
|
||||
@@ -73,6 +73,9 @@ header p {
|
||||
.problems-list .problem-item {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.problem-item:last-child {
|
||||
border-bottom: none;
|
||||
@@ -82,6 +85,28 @@ header p {
|
||||
color: #0077ff;
|
||||
font-weight: 600;
|
||||
}
|
||||
/* Difficulty badge */
|
||||
.difficulty {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 0.25em 0.6em;
|
||||
border-radius: 10px;
|
||||
font-size: 0.85em;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.difficulty[data-difficulty="easy"] {
|
||||
background-color: #4CAF50; /* Green */
|
||||
}
|
||||
.difficulty[data-difficulty="medium"] {
|
||||
background-color: #FFC107; /* Amber */
|
||||
color: #333;
|
||||
}
|
||||
.difficulty[data-difficulty="hard"] {
|
||||
background-color: #F44336; /* Red */
|
||||
}
|
||||
/* Leaderboard */
|
||||
.leaderboard-head {
|
||||
display: flex;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
<header>
|
||||
<h1>Quick Problem Platform</h1>
|
||||
</header>
|
||||
|
||||
<div class="content" id="contentContainer">
|
||||
<!-- Problems -->
|
||||
<section class="card problems-list">
|
||||
@@ -28,9 +27,10 @@
|
||||
</div>
|
||||
<h2 style="margin-bottom:6px;font-size:1.1rem">Problems</h2>
|
||||
<div id="problemsContainer">
|
||||
{% for folder, description, test_code in problems %}
|
||||
{% for folder, description, test_code, difficulty in problems %}
|
||||
<div class="problem-item" data-name="{{ folder.replace('_',' ').title() }}" data-desc="{{ description }}">
|
||||
<a href="/problem/{{ folder }}">{{ folder.replace('_',' ').title() }}</a>
|
||||
<span class="difficulty" data-difficulty="{{ difficulty|lower }}">{{ difficulty }}</span>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="problem-item">No problems yet.</div>
|
||||
|
||||
Reference in New Issue
Block a user