From 767678bb514bf624ba89d5266c4304e049daad9a Mon Sep 17 00:00:00 2001 From: a2nr Date: Sun, 18 Jan 2026 06:44:46 +0700 Subject: [PATCH] add code check uaing static analys with ---KEY_TEXT--- in content --- README.md | 51 ++++ app.py | 34 ++- example_content/data_types.md | 326 +++++++++++++++++++++++++ example_content/hello_world.md | 231 ++++++++++++++++++ example_content/home.md | 5 +- example_content/python_intro.md | 52 ---- example_content/variables.md | 218 +++++++++++++++++ example_content/variables_and_types.md | 121 --------- podman-compose.yml | 2 + templates/lesson.html | 171 ++++++++++++- 10 files changed, 1022 insertions(+), 189 deletions(-) create mode 100644 example_content/data_types.md create mode 100644 example_content/hello_world.md delete mode 100644 example_content/python_intro.md create mode 100644 example_content/variables.md delete mode 100644 example_content/variables_and_types.md diff --git a/README.md b/README.md index 2ad910c..7044804 100644 --- a/README.md +++ b/README.md @@ -804,3 +804,54 @@ class NewLanguageCompiler(BaseCompiler): - File extensions are automatically adjusted based on the selected language - The system maintains backward compatibility with existing C lessons - All language compilation follows the same security and timeout constraints + +## Static Code Analysis Feature + +The system includes a static code analysis feature that validates student code against required keywords before compilation. This prevents students from hardcoding outputs without using proper algorithms or variables. + +### How It Works + +1. Teachers define required keywords in lesson files using the `---KEY_TEXT---` and `---END_KEY_TEXT---` markers +2. When students submit code, the system checks if their code contains all required keywords +3. Students only receive success notifications and lesson completion credit if both: + - Their output matches the expected output (if specified) + - Their code contains all required keywords from the KEY_TEXT section + +### Adding Static Analysis to Lessons + +To add static analysis to a lesson, include the `---KEY_TEXT---` section in your lesson file: + +```markdown +---KEY_TEXT--- +int counter +counter = 5 +printf +---END_KEY_TEXT--- +``` + +This example would require students to use an integer variable named `counter`, initialize it to 5, and use the `printf` function in their code. + +### Advanced Pattern Matching + +The system supports both literal keyword matching and regex patterns: + +- For literal keywords, just list them (one per line) +- For regex patterns, enclose them in forward slashes: `/int\s+\w+\s*=\s*\d+/` + +Example with regex: +```markdown +---KEY_TEXT--- +int counter +/counter\s*=\s*\d+/ +printf +---END_KEY_TEXT--- +``` + +This would require an integer variable named counter, an assignment to a numeric value, and the printf function. + +### Behavior + +- If static analysis fails, the success message is hidden and progress is not tracked +- No explicit error messages are shown to students to maintain a clean user experience +- The code still gets compiled and executed normally, but success criteria are not met +- Both output correctness and keyword presence are required for lesson completion diff --git a/app.py b/app.py index 3fbb752..46d7dae 100644 --- a/app.py +++ b/app.py @@ -394,6 +394,7 @@ def render_markdown_content(file_path): initial_code = "" solution_code = "" expected_output = "" + key_text = "" # Look for expected output separator - format: [content] ---EXPECTED_OUTPUT--- [output] ---END_EXPECTED_OUTPUT--- [content] if '---EXPECTED_OUTPUT---' in lesson_content and '---END_EXPECTED_OUTPUT---' in lesson_content: @@ -407,6 +408,18 @@ def render_markdown_content(file_path): # Remove the expected output section from the lesson content lesson_content = lesson_content[:start_idx] + lesson_content[end_idx + len('---END_EXPECTED_OUTPUT---'):] + # Look for key text separator - format: [content] ---KEY_TEXT--- [keywords] ---END_KEY_TEXT--- [content] + if '---KEY_TEXT---' in lesson_content and '---END_KEY_TEXT---' in lesson_content: + start_idx = lesson_content.find('---KEY_TEXT---') + end_idx = lesson_content.find('---END_KEY_TEXT---') + + if start_idx != -1 and end_idx != -1 and end_idx > start_idx: + # Extract the key text between the separators + key_start = start_idx + len('---KEY_TEXT---') + key_text = lesson_content[key_start:end_idx].strip() + # Remove the key text section from the lesson content + lesson_content = lesson_content[:start_idx] + lesson_content[end_idx + len('---END_KEY_TEXT---'):] + # Look for lesson info separator - format: ---LESSON_INFO--- [info] ---END_LESSON_INFO--- [content] if '---LESSON_INFO---' in lesson_content and '---END_LESSON_INFO---' in lesson_content: start_idx = lesson_content.find('---LESSON_INFO---') + len('---LESSON_INFO---') @@ -458,7 +471,7 @@ def render_markdown_content(file_path): exercise_html = markdown.markdown(exercise_content, extensions=['fenced_code', 'codehilite', 'tables']) if exercise_content else "" lesson_info_html = markdown.markdown(lesson_info, extensions=['fenced_code', 'codehilite', 'tables']) if lesson_info else "" - return lesson_html, exercise_html, expected_output, lesson_info_html, initial_code, solution_code + return lesson_html, exercise_html, expected_output, lesson_info_html, initial_code, solution_code, key_text @app.route('/') def index(): @@ -524,7 +537,7 @@ def lesson(filename): if not os.path.exists(file_path): return "Lesson not found", 404 - lesson_html, exercise_html, expected_output, lesson_info, initial_code, solution_code = render_markdown_content(file_path) + lesson_html, exercise_html, expected_output, lesson_info, initial_code, solution_code, key_text = render_markdown_content(file_path) # If no initial code is provided, use a default template if not initial_code: @@ -585,6 +598,7 @@ int main() { lesson_info=lesson_info, initial_code=initial_code, solution_code=solution_code, + key_text=key_text, lesson_title=filename.replace('.md', '').replace('_', ' ').title(), token=token, progress=progress, @@ -599,6 +613,22 @@ int main() { language_display_name=language_display_name) +@app.route('/get-key-text/') +def get_key_text(filename): + """Get the key text for a specific lesson""" + file_path = os.path.join(CONTENT_DIR, filename) + if not os.path.exists(file_path): + return jsonify({'success': False, 'error': 'Lesson not found'}), 404 + + # Extract key text from the lesson file + _, _, _, _, _, _, key_text = render_markdown_content(file_path) + + return jsonify({ + 'success': True, + 'key_text': key_text + }) + + @app.route('/compile', methods=['POST']) def compile_code(): """Compile and run code submitted by the user in the selected programming language""" diff --git a/example_content/data_types.md b/example_content/data_types.md new file mode 100644 index 0000000..fe08c17 --- /dev/null +++ b/example_content/data_types.md @@ -0,0 +1,326 @@ +---LESSON_INFO--- +**Learning Objectives:** +- Memahami berbagai tipe data dalam bahasa C +- Mengenal tipe data karakter, angka bulat, dan angka desimal +- Belajar menggunakan operator sizeof() untuk mengetahui ukuran tipe data +- Memahami penggunaan tipe data dalam konteks nyata +- Mengenal tipe data extended (lebih lanjut) + +**Prerequisites:** +- Dasar-dasar pemrograman +- Pemahaman tentang program Halo Dunia +- Pemahaman tentang variabel + +---END_LESSON_INFO--- +# Tipe Data dalam C + +**Tipe data dalam bahasa C** menentukan jenis nilai yang bisa disimpan dalam variabel, serta ukuran dan rentang nilai yang bisa ditampung. Setiap variabel dalam C harus memiliki tipe data yang dideklarasikan. + +## Mengapa Tipe Data Penting? + +**Tipe data** penting karena: +- Menentukan **jumlah memori** yang dialokasikan untuk variabel +- Menentukan **jenis nilai** yang bisa disimpan (angka, karakter, dll.) +- Menentukan **operasi** yang bisa dilakukan pada variabel tersebut + +## Tipe Data Karakter + +**Tipe data `char`** digunakan untuk menyimpan **satu karakter**. Karakter harus ditempatkan di dalam tanda petik tunggal `' '`. + +```c +char myGrade = 'A'; +char letter = 'x'; +char symbol = '@'; +``` + +**Format specifier** untuk `char` adalah `%c`: +```c +char myGrade = 'A'; +printf("My grade is: %c\n", myGrade); // Output: My grade is: A +``` + +## Tipe Data Angka Bulat + +**Tipe data `int`** digunakan untuk menyimpan **bilangan bulat** (angka tanpa desimal). + +```c +int myNum = 5; // Bilangan positif +int myNegativeNum = -5; // Bilangan negatif +int zero = 0; // Nol +``` + +**Format specifier** untuk `int` adalah `%d` atau `%i`: +```c +int myNum = 5; +printf("My number is: %d\n", myNum); // Output: My number is: 5 +``` + +### Tipe Data Integer Lainnya + +C juga menyediakan tipe data integer lainnya: +- `short` - versi pendek dari int (biasanya 2 byte) +- `long` - versi panjang dari int (biasanya 8 byte) +- `unsigned int` - versi int tanpa tanda (hanya nilai positif dan nol) + +## Tipe Data Desimal + +**Tipe data `float`** digunakan untuk menyimpan **bilangan desimal** dengan presisi tunggal. + +```c +float myFloat = 9.99; +float scientific = 3e5; // 300000 +float negative = -3.99; +``` + +**Format specifier** untuk `float` adalah `%f`: +```c +float myFloat = 9.99; +printf("My float is: %f\n", myFloat); // Output: My float is: 9.990000 +``` + +**Tipe data `double`** digunakan untuk menyimpan **bilangan desimal** dengan presisi ganda (lebih akurat dari float). + +```c +double myDouble = 19.99; +double precise = 3.141592653589793; +``` + +**Format specifier** untuk `double` adalah `%lf`: +```c +double myDouble = 19.99; +printf("My double is: %lf\n", myDouble); // Output: My double is: 19.990000 +``` + +## Mengetahui Ukuran Tipe Data + +Anda bisa menggunakan **operator `sizeof()`** untuk mengetahui ukuran tipe data dalam byte: + +```c +#include + +int main() { + printf("Size of char: %zu byte(s)\n", sizeof(char)); + printf("Size of int: %zu byte(s)\n", sizeof(int)); + printf("Size of float: %zu byte(s)\n", sizeof(float)); + printf("Size of double: %zu byte(s)\n", sizeof(double)); + + return 0; +} +``` + +**Output (dapat bervariasi tergantung sistem):** +``` +Size of char: 1 byte(s) +Size of int: 4 byte(s) +Size of float: 4 byte(s) +Size of double: 8 byte(s) +``` + +## Tipe Data Extended + +C juga menyediakan tipe data extended untuk kebutuhan spesifik: + +### Tipe Data Unsigned +- `unsigned char` - karakter tanpa tanda (0 hingga 255) +- `unsigned int` - integer tanpa tanda (0 hingga 4,294,967,295) +- `unsigned short` - short integer tanpa tanda +- `unsigned long` - long integer tanpa tanda + +### Tipe Data Signed +- `signed char` - karakter dengan tanda (-128 hingga 127) +- `signed int` - integer dengan tanda (sama seperti int biasa) + +## Contoh Nyata Penggunaan Tipe Data + +Berikut adalah contoh penggunaan berbagai tipe data dalam situasi nyata: + +```c +#include + +int main() { + // Tipe data karakter + char initial = 'J'; + + // Tipe data angka bulat + int age = 25; + unsigned int population = 1000000; + + // Tipe data desimal + float temperature = 36.6; + double preciseValue = 3.141592653589793238; + + // Menampilkan informasi + printf("Initial: %c\n", initial); + printf("Age: %d years old\n", age); + printf("Population: %u people\n", population); + printf("Temperature: %.1f°C\n", temperature); + printf("Pi: %.10lf\n", preciseValue); + + // Menampilkan ukuran tipe data + printf("\nSize of age variable: %zu bytes\n", sizeof(age)); + printf("Size of temperature variable: %zu bytes\n", sizeof(temperature)); + + return 0; +} +``` + +**Output:** +``` +Initial: J +Age: 25 years old +Population: 1000000 people +Temperature: 36.6°C +Pi: 3.1415926535 + +Size of age variable: 4 bytes +Size of temperature variable: 4 bytes +``` + +## Konstanta dalam C + +**Konstanta** dalam bahasa C adalah nilai tetap yang tidak dapat diubah selama eksekusi program. Konstanta juga dikenal sebagai **literal** karena nilainya langsung ditulis dalam kode program. + +### Jenis-Jenis Konstanta + +Ada beberapa jenis konstanta dalam bahasa C: + +#### 1. Konstanta Integer +Nilai bilangan bulat yang tidak memiliki bagian desimal: +```c +const int MAX_STUDENTS = 100; +int count = 50; +``` + +#### 2. Konstanta Floating-Point +Nilai bilangan desimal: +```c +const double PI = 3.14159; +float tax_rate = 0.08; +``` + +#### 3. Konstanta Karakter +Satu karakter yang diapit oleh tanda petik tunggal: +```c +const char NEWLINE = '\n'; +char grade = 'A'; +``` + +#### 4. Konstanta String +Rangkaian karakter yang diapit oleh tanda petik ganda: +```c +const char *GREETING = "Hello, World!"; +char message[] = "Welcome to C programming"; +``` + +### Keyword `const` + +Anda bisa membuat variabel menjadi konstan dengan menggunakan **keyword `const`**. Setelah dideklarasikan sebagai konstan, nilai variabel tersebut tidak bisa diubah: + +```c +const int AGE = 25; +// AGE = 30; // Ini akan menyebabkan error karena AGE adalah konstan +``` + +### Preprocessor `#define` + +Alternatif lain untuk membuat konstanta adalah dengan menggunakan **preprocessor directive `#define`**: + +```c +#define PI 3.14159 +#define MAX_SIZE 100 +#define NAME "John Doe" + +int main() { + double area = PI * 5 * 5; // Menghitung luas lingkaran dengan jari-jari 5 + printf("Area of circle: %.2f\n", area); + return 0; +} +``` + +**Tips:** +- Gunakan tipe data yang **tepat** untuk kebutuhan Anda +- Perhatikan **rentang nilai** yang bisa ditampung oleh masing-masing tipe data +- Gunakan `unsigned` jika Anda yakin nilai tidak akan negatif +- Gunakan `double` jika Anda membutuhkan presisi tinggi + +**Referensi:** +- [https://www.w3schools.com/c/c_data_types.php](https://www.w3schools.com/c/c_data_types.php) +- [https://www.w3schools.com/c/c_data_types_characters.php](https://www.w3schools.com/c/c_data_types_characters.php) +- [https://www.w3schools.com/c/c_data_types_numbers.php](https://www.w3schools.com/c/data_types_numbers.php) +- [https://www.w3schools.com/c/c_data_types_dec.php](https://www.w3schools.com/c/c_data_types_dec.php) +- [https://www.w3schools.com/c/c_data_types_sizeof.php](https://www.w3schools.com/c/c_data_types_sizeof.php) +- [https://www.w3schools.com/c/c_data_types_reallife.php](https://www.w3schools.com/c/c_data_types_reallife.php) +- [https://www.w3schools.com/c/c_data_types_extended.php](https://www.w3schools.com/c/c_data_types_extended.php) +- [Hello, World!](lesson/hello_world.md) +- [Variables in C](lesson/variables.md) + +---EXERCISE--- + +# Latihan: Menggunakan Tipe Data + +Dalam latihan ini, Anda akan membuat program sederhana yang menggunakan berbagai tipe data untuk menyimpan informasi buku dan menampilkannya. + +**Requirements:** +- Buat variabel `title` untuk menyimpan judul buku (gunakan tipe data char array) +- Buat variabel `pages` untuk menyimpan jumlah halaman (gunakan tipe data int) +- Buat variabel `price` untuk menyimpan harga buku (gunakan tipe data float) +- Buat variabel `rating` untuk menyimpan rating buku (gunakan tipe data double) +- Tampilkan informasi buku menggunakan printf dengan format specifier yang sesuai +- Tampilkan ukuran dari variabel pages menggunakan sizeof() + +**Expected Output:** +``` +Book Title: The Art of Programming +Pages: 450 +Price: $49.99 +Rating: 4.75 +Size of pages variable: 4 byte(s) +``` + +Try writing your solution in the code editor below! + +---EXPECTED_OUTPUT--- +Book Title: The Art of Programming +Pages: 450 +Price: $49.99 +Rating: 4.75 +Size of pages variable: 4 byte(s) +---END_EXPECTED_OUTPUT--- + +---INITIAL_CODE--- +#include + +int main() { + // Deklarasi variabel di sini + + // Tampilkan informasi buku di sini + printf("Book Title: \n"); + printf("Pages: \n"); + printf("Price: $\n"); + printf("Rating: \n"); + printf("Size of pages variable: byte(s)\n"); + + return 0; +} +---END_INITIAL_CODE--- + +---SOLUTION_CODE--- +#include + +int main() { + // Deklarasi variabel + char title[] = "The Art of Programming"; + int pages = 450; + float price = 49.99; + double rating = 4.75; + + // Tampilkan informasi buku + printf("Book Title: %s\n", title); + printf("Pages: %d\n", pages); + printf("Price: $%.2f\n", price); + printf("Rating: %.2lf\n", rating); + printf("Size of pages variable: %zu byte(s)\n", sizeof(pages)); + + return 0; +} +---END_SOLUTION_CODE--- \ No newline at end of file diff --git a/example_content/hello_world.md b/example_content/hello_world.md new file mode 100644 index 0000000..df861f6 --- /dev/null +++ b/example_content/hello_world.md @@ -0,0 +1,231 @@ +---LESSON_INFO--- +**Learning Objectives:** +- Memahami struktur dasar program C +- Mengenal fungsi main() sebagai titik awal eksekusi program +- Belajar menggunakan perintah printf untuk menampilkan output +- Memahami konsep header file dan direktif include + +**Prerequisites:** +- Tidak ada persyaratan khusus +- Cocok untuk pemula dalam pemrograman C + +---END_LESSON_INFO--- +# Program Pertama C: Halo, Dunia! + +**Bahasa pemrograman C** adalah bahasa pemrograman umum yang berhubungan erat dengan cara mesin bekerja. **Memahami cara kerja memori komputer** adalah aspek penting dari bahasa pemrograman C. Meskipun C bisa dianggap sebagai "sulit dipelajari", sebenarnya C adalah bahasa yang sangat sederhana, dengan kemampuan yang sangat kuat. + +C adalah **bahasa yang sangat umum**, dan merupakan bahasa dari banyak aplikasi seperti Windows, interpreter Python, Git, dan banyak lagi. + +**C adalah bahasa yang dikompilasi** - yang berarti bahwa untuk menjalankannya, **kompiler** (misalnya, GCC atau Visual Studio) harus mengambil kode yang kita tulis, memprosesnya, lalu membuat file yang dapat dieksekusi. File ini kemudian dapat dijalankan, dan akan melakukan apa yang kita maksudkan agar program tersebut lakukan. + +## Program pertama kita +Setiap program C menggunakan **pustaka**, yang memberikan kemampuan untuk mengeksekusi fungsi-fungsi yang diperlukan. Sebagai contoh, fungsi paling dasar yang disebut `printf`, yang mencetak ke layar, didefinisikan dalam **file header `stdio.h`**. + +Untuk menambahkan kemampuan menjalankan perintah `printf` ke program kita, kita harus menambahkan **direktif include** berikut ke baris pertama kode kita: + +```c +#include +``` + +Bagian kedua dari kode adalah kode aktual yang akan kita tulis. **Kode pertama yang akan dijalankan selalu berada di fungsi `main`**. + +```c +int main() { + ... kode kita ada di sini +} +``` + +**Kata kunci `int`** menunjukkan bahwa fungsi `main` akan mengembalikan bilangan bulat - angka sederhana. Angka yang akan dikembalikan oleh fungsi menunjukkan apakah program yang kita tulis berjalan dengan benar. Jika kita ingin mengatakan bahwa kode kita berjalan dengan sukses, kita akan mengembalikan angka 0. Angka lebih besar dari 0 akan berarti bahwa program yang kita tulis gagal. Untuk tutorial ini, kita akan mengembalikan 0 untuk menunjukkan bahwa program kita berhasil: + +```c +return 0; +``` + +**Perhatikan bahwa setiap pernyataan dalam C harus diakhiri dengan titik koma**, sehingga kompiler tahu bahwa pernyataan baru telah dimulai. + +Terakhir tetapi tidak kalah pentingnya, kita perlu memanggil fungsi `printf` untuk mencetak kalimat kita. + +## Sintaks Dasar dalam C + +**Sintaks dalam bahasa C** merujuk pada aturan dan struktur yang menentukan bagaimana program ditulis. Berikut adalah beberapa konsep penting dalam sintaks C: + +### Struktur Program C +**Program C memiliki struktur tertentu** yang harus diikuti: +- **Header files** (menggunakan `#include`) +- **Fungsi `main()` sebagai titik awal eksekusi** +- **Deklarasi variabel** (jika ada) +- **Pernyataan-pernyataan program** +- **Pengembalian nilai dari fungsi `main()`** + +### Case Sensitivity +**Bahasa C bersifat *case-sensitive***, artinya huruf besar dan kecil dibedakan. Misalnya, `variable`, `Variable`, dan `VARIABLE` adalah tiga nama yang berbeda. + +### Titik Koma (;) +**Setiap pernyataan dalam C harus diakhiri dengan titik koma**. Ini memberi tahu kompiler bahwa pernyataan tersebut telah selesai. + +### Blok Kode +**Blok kode dalam C didefinisikan dengan kurung kurawal `{` dan `}`**. Semua kode yang berada di antara kurung kurawal ini dianggap sebagai satu unit. + +## Pernyataan dalam C + +**Pernyataan dalam bahasa C adalah instruksi** yang memberi tahu komputer untuk melakukan tindakan tertentu. Ada beberapa jenis pernyataan dalam C: + +### Pernyataan Ekspresi +Pernyataan yang terdiri dari ekspresi dan diakhiri dengan titik koma: +```c +x = 5; +y = x + 3; +hasil = a * b + c; +``` + +### Pernyataan Kompoun (Blok) +Sejumlah pernyataan yang dikelompokkan bersama dalam kurung kurawal: +```c +{ + int a = 10; + int b = 20; + int sum = a + b; +} +``` + +## Output dalam C + +**Output dalam bahasa C biasanya dilakukan menggunakan fungsi `printf()`** dari pustaka `stdio.h`. Fungsi ini memungkinkan kita untuk menampilkan teks dan nilai variabel ke layar. + +### Format Specifier +**Fungsi `printf()` menggunakan format specifier** untuk menentukan tipe data yang akan dicetak: +- **`%d` atau `%i` untuk bilangan bulat (integer)** +- **`%f` untuk bilangan desimal (float/double)** +- **`%c` untuk karakter** +- **`%s` untuk string** + +Contoh: +```c +int usia = 25; +float tinggi = 175.5; +char inisial = 'J'; +printf("Usia saya %d tahun\n", usia); +printf("Tinggi saya %.1f cm\n", tinggi); +printf("Inisial saya %c\n", inisial); +``` + +## Baris Baru dalam C + +**Untuk membuat baris baru dalam output C, kita menggunakan karakter escape `\n`**. Karakter ini memberi tahu kompiler untuk pindah ke baris berikutnya. + +Contoh: +```c +printf("Baris pertama\nBaris kedua\nBaris ketiga"); +``` + +Output: +``` +Baris pertama +Baris kedua +Baris ketiga +``` + +**Selain `\n`, ada beberapa karakter escape lain dalam C**: +- **`\t` untuk tab** +- **`\\` untuk backslash** +- **`\"` untuk tanda kutip ganda** + +## Komentar dalam C + +**Komentar adalah teks yang ditulis dalam kode program tetapi tidak akan dieksekusi**. Komentar digunakan untuk menjelaskan kode dan membuatnya lebih mudah dipahami. + +### Komentar Satu Baris +**Komentar satu baris dimulai dengan `//`**: +```c +// Ini adalah komentar satu baris +int x = 5; // komentar setelah pernyataan +``` + +### Komentar Lebih dari Satu Baris +**Komentar yang lebih dari satu baris dimulai dengan `/*` dan diakhiri dengan `*/`**: +```c +/* +Ini adalah komentar +yang mencakup lebih dari +satu baris +*/ +int y = 10; +``` + +**Komentar sangat penting untuk dokumentasi kode** dan membantu programmer lain (atau diri sendiri di masa depan) memahami maksud dari kode yang ditulis. + +--- + +## Tabel Fungsi Dasar dalam stdio.h + +| Fungsi | Deskripsi | Contoh | +|--------|-----------|--------| +| printf() | Mencetak output ke layar | `printf("Halo Dunia\\n");` | +| scanf() | Membaca input dari pengguna | `scanf("%d", &angka);` | +| getchar() | Membaca satu karakter | `char c = getchar();` | +| putchar() | Mencetak satu karakter | `putchar('A');` | + +**Referensi:** +- [https://www.w3schools.com/c/c_syntax.php](https://www.w3schools.com/c/c_syntax.php) +- [https://www.w3schools.com/c/c_statements.php](https://www.w3schools.com/c/c_statements.php) +- [https://www.w3schools.com/c/c_output.php](https://www.w3schools.com/c/c_output.php) +- [https://www.w3schools.com/c/c_newline.php](https://www.w3schools.com/c/c_newline.php) +- [https://www.w3schools.com/c/c_comments.php](https://www.w3schools.com/c/c_comments.php) +- [Variables in C](lesson/variables.md) +- [Data Types in C](lesson/data_types.md) + +---EXERCISE--- + +# Latihan: Program Halo, Dunia! dan Penggunaan Dasar C + +Latih pemahamanmu tentang sintaks dasar C dengan menyelesaikan program berikut. Tambahkan komentar, gunakan format specifier, dan karakter escape sesuai permintaan. + +**Requirements:** +- Ganti teks "Goodbye, World!" menjadi "Hello, World!" +- Tambahkan komentar satu baris sebelum fungsi main() menjelaskan tujuan program +- Tambahkan komentar lebih dari satu baris di dalam fungsi main() untuk menjelaskan apa yang dilakukan oleh printf +- Gunakan format specifier untuk mencetak usia kamu (sebagai integer) setelah "Hello, World!" +- Tambahkan karakter escape untuk membuat baris baru sebelum mencetak usia +- Pastikan program berjalan tanpa error + +**Expected Output:** +``` +Hello, World! +Saya berusia 20 tahun +``` + +Try writing your solution in the code editor below! + +---EXPECTED_OUTPUT--- +Hello, World! +Saya berusia 20 tahun +---END_EXPECTED_OUTPUT--- + +---KEY_TEXT--- +Hello, +\n +---END_KEY_TEXT--- + +---INITIAL_CODE--- +#include + +int main() { + printf("Goodbye, World!"); + return 0; +} +---END_INITIAL_CODE--- + + +---SOLUTION_CODE--- +#include + +// Program ini mencetak pesan sambutan dan usia +int main() { + /* + * Fungsi printf digunakan untuk mencetak output ke layar + * Dalam contoh ini, kita mencetak Hello, World! dan usia + */ + printf("Hello, World!\nSaya berusia 20 tahun"); + return 0; +} +---END_SOLUTION_CODE--- diff --git a/example_content/home.md b/example_content/home.md index fa17a7d..66440db 100644 --- a/example_content/home.md +++ b/example_content/home.md @@ -28,6 +28,7 @@ Happy coding! ---Available_Lessons--- -1. [Introduction to C Programming](lesson/introduction_to_c.md) -2. [Variables and Data Types in C](lesson/variables_and_data_types.md) +1. [Hello World](lesson/hello_world.md) +2. [variables](lesson/variable.md) +3. [data type](lesson/data_type.md) diff --git a/example_content/python_intro.md b/example_content/python_intro.md deleted file mode 100644 index 4d47f4f..0000000 --- a/example_content/python_intro.md +++ /dev/null @@ -1,52 +0,0 @@ -# Python Introduction Lesson - -This lesson introduces the basics of Python programming. - -## Variables and Data Types - -Python is a high-level programming language known for its simplicity and readability. - -```python -# This is a comment in Python -name = "John" # String variable -age = 25 # Integer variable -height = 5.9 # Float variable -is_student = True # Boolean variable - -print(f"Name: {name}, Age: {age}, Height: {height}, Student: {is_student}") -``` - -## Basic Operations - -You can perform basic arithmetic operations in Python: - -```python -a = 10 -b = 5 - -addition = a + b -subtraction = a - b -multiplication = a * b -division = a / b - -print(f"Addition: {addition}") -print(f"Subtraction: {subtraction}") -print(f"Multiplication: {multiplication}") -print(f"Division: {division}") -``` - ----EXERCISE--- - -Write a Python program that prints "Hello, Python!" to the console. - ----INITIAL_CODE--- -print("Write your Python code here") ----END_INITIAL_CODE--- - ----EXPECTED_OUTPUT--- -Hello, Python! ----END_EXPECTED_OUTPUT--- - ----SOLUTION_CODE--- -print("Hello, Python!") ----END_SOLUTION_CODE--- diff --git a/example_content/variables.md b/example_content/variables.md new file mode 100644 index 0000000..5fa8d28 --- /dev/null +++ b/example_content/variables.md @@ -0,0 +1,218 @@ +---LESSON_INFO--- +**Learning Objectives:** +- Memahami konsep variabel dalam bahasa C +- Belajar mendeklarasikan dan menginisialisasi variabel +- Mengenal aturan penamaan variabel dalam C +- Memahami cara mengubah nilai variabel +- Mengenal format specifier untuk berbagai tipe data +- Belajar mendeklarasikan beberapa variabel sekaligus +- Memahami penggunaan variabel dalam konteks nyata + +**Prerequisites:** +- Dasar-dasar pemrograman +- Pemahaman tentang program Halo Dunia + +---END_LESSON_INFO--- +# Variabel dalam C + +**Variabel dalam bahasa C** adalah bagian memori bernama yang digunakan untuk menyimpan data dan mengaksesnya kapan saja diperlukan. Variabel memungkinkan kita menggunakan memori tanpa harus mengingat alamat memori yang tepat. + +## Apa itu Variabel? + +**Variabel** dalam bahasa C adalah **wadah (kontainer)** untuk menyimpan nilai data. Seperti halnya kotak yang bisa kita beri label dan isi dengan nilai tertentu. Setiap variabel memiliki **nama** (identifier) dan **nilai**. + +## Deklarasi dan Inisialisasi Variabel + +Untuk membuat variabel dalam C, kita harus menentukan **tipe data** dan **nama** yang akan disimpan. Setiap variabel harus dideklarasikan sebelum digunakan. + +### Deklarasi Variabel +**Deklarasi variabel** adalah proses membuat variabel dengan menentukan tipe data dan nama: + +```c +int myNum; +``` + +### Inisialisasi Variabel +**Inisialisasi variabel** adalah proses memberikan nilai awal ke variabel: + +```c +int myNum = 15; +``` + +Contoh lengkap deklarasi dan inisialisasi: +```c +// Deklarasi dan inisialisasi sekaligus +int age = 20; +float price = 19.99; +char grade = 'A'; + +// Deklarasi terlebih dahulu, kemudian inisialisasi +int score; +score = 100; +``` + +## Format Specifier untuk Variabel + +**Format specifier** digunakan dalam fungsi `printf()` untuk menentukan tipe data yang akan dicetak: + +- `%d` atau `%i` untuk bilangan bulat (integer) +- `%f` untuk bilangan desimal (float/double) +- `%c` untuk karakter +- `%s` untuk string + +Contoh: +```c +int myNum = 5; +float myFloatNum = 5.99; +char myLetter = 'D'; + +printf("Number: %d\n", myNum); +printf("Float: %f\n", myFloatNum); +printf("Letter: %c\n", myLetter); +``` + +## Mengubah Nilai Variabel + +Setelah variabel dideklarasikan, kita bisa **mengubah nilainya** kapan saja dengan menggunakan operator penugasan (`=`): + +```c +int myNum = 15; +printf("Original value: %d\n", myNum); // Output: 15 + +myNum = 20; +printf("New value: %d\n", myNum); // Output: 20 +``` + +**Catatan penting:** Anda tidak bisa mengganti tipe data dari variabel yang sudah dideklarasikan. Jika sebuah variabel dideklarasikan sebagai `int`, Anda hanya bisa menyimpan bilangan bulat di dalamnya. + +## Deklarasi Beberapa Variabel + +Anda bisa **mendeklarasikan beberapa variabel sekaligus** dengan tipe data yang sama menggunakan koma: + +```c +int x, y, z; +x = y = z = 50; +``` + +Atau deklarasi dan inisialisasi sekaligus: +```c +int x = 10, y = 20, z = 30; +``` + +## Aturan Penamaan Variabel + +**Aturan untuk memberi nama variabel dalam C:** +1. Nama variabel hanya boleh mengandung **huruf**, **angka**, dan **garis bawah** +2. Harus **dimulai dengan huruf atau garis bawah**, tidak bisa dimulai dengan angka +3. **Tidak diperbolehkan spasi** dalam nama variabel +4. Nama **tidak boleh merupakan kata kunci** atau reserved word +5. Nama harus **unik dalam program** +6. Bahasa C bersifat **case-sensitive** (huruf besar dan kecil berbeda) + +Contoh nama variabel yang **valid**: `myVar`, `_count`, `totalAmount`, `student_id` +Contoh nama variabel yang **tidak valid**: `2count`, `first name`, `int` + +## Contoh Nyata Penggunaan Variabel + +Berikut adalah contoh penggunaan variabel dalam situasi nyata: + +```c +#include + +int main() { + // Informasi pelanggan + char firstName[] = "John"; + char lastName[] = "Doe"; + int age = 30; + float salary = 2500.50; + + // Menampilkan informasi + printf("Name: %s %s\n", firstName, lastName); + printf("Age: %d years old\n", age); + printf("Salary: $%.2f\n", salary); + + return 0; +} +``` + +**Output:** +``` +Name: John Doe +Age: 30 years old +Salary: $2500.50 +``` + +**Tips:** +- Gunakan nama variabel yang **deskriptif** agar kode lebih mudah dipahami +- Gunakan **camelCase** atau **snake_case** untuk nama variabel yang terdiri dari beberapa kata +- Hindari nama variabel yang terlalu singkat kecuali untuk variabel loop (seperti `i`, `j`, `k`) + +**Referensi:** +- [https://www.w3schools.com/c/c_variables.php](https://www.w3schools.com/c/c_variables.php) +- [https://www.w3schools.com/c/c_variables_format.php](https://www.w3schools.com/c/c_variables_format.php) +- [https://www.w3schools.com/c/c_variables_change.php](https://www.w3schools.com/c/c_variables_change.php) +- [https://www.w3schools.com/c/c_variables_multiple.php](https://www.w3schools.com/c/c_variables_multiple.php) +- [https://www.w3schools.com/c/c_variables_names.php](https://www.w3schools.com/c/c_variables_names.php) +- [https://www.w3schools.com/c/c_variables_reallife.php](https://www.w3schools.com/c/c_variables_reallife.php) +- [Hello, World!](lesson/hello_world.md) +- [Data Types in C](lesson/data_types.md) + +---EXERCISE--- + +# Latihan: Menggunakan Variabel + +Dalam latihan ini, Anda akan membuat program sederhana yang menggunakan beberapa variabel untuk menyimpan informasi produk dan menampilkannya. + +**Requirements:** +- Buat variabel `productName` untuk menyimpan nama produk (gunakan tipe data char array) +- Buat variabel `quantity` untuk menyimpan jumlah produk (gunakan tipe data int) +- Buat variabel `price` untuk menyimpan harga produk (gunakan tipe data float) +- Tampilkan informasi produk menggunakan printf dengan format specifier yang sesuai + +**Expected Output:** +``` +Product: Laptop +Quantity: 5 +Price: $1200.00 +``` + +Try writing your solution in the code editor below! + +---EXPECTED_OUTPUT--- +Product: Laptop +Quantity: 5 +Price: $1200.00 +---END_EXPECTED_OUTPUT--- + +---INITIAL_CODE--- +#include + +int main() { + // Deklarasi variabel di sini + + // Tampilkan informasi produk di sini + printf("Product: \n"); + printf("Quantity: \n"); + printf("Price: $\n"); + + return 0; +} +---END_INITIAL_CODE--- + +---SOLUTION_CODE--- +#include + +int main() { + // Deklarasi variabel + char productName[] = "Laptop"; + int quantity = 5; + float price = 1200.00; + + // Tampilkan informasi produk + printf("Product: %s\n", productName); + printf("Quantity: %d\n", quantity); + printf("Price: $%.2f\n", price); + + return 0; +} +---END_SOLUTION_CODE--- \ No newline at end of file diff --git a/example_content/variables_and_types.md b/example_content/variables_and_types.md deleted file mode 100644 index a27c33f..0000000 --- a/example_content/variables_and_types.md +++ /dev/null @@ -1,121 +0,0 @@ ----LESSON_INFO--- -**Learning Objectives:** -- Memahami berbagai tipe data dalam bahasa C -- Belajar mendeklarasikan dan menginisialisasi variabel -- Mengenal batas-batas masing-masing tipe data -- Memahami perbedaan antara tipe data signed dan unsigned - -**Prerequisites:** -- Dasar-dasar pemrograman -- Pemahaman tentang program Halo Dunia - ----END_LESSON_INFO--- -# Tipe Data dan Variabel dalam C - -C memiliki beberapa jenis variabel, tetapi ada beberapa tipe dasar: - -* Bilangan Bulat - bilangan bulat yang bisa positif atau negatif. Didefinisikan menggunakan `char`, `int`, `short`, `long` atau `long long`. -* Bilangan Bulat Tak Bertanda - bilangan bulat yang hanya bisa positif. Didefinisikan menggunakan `unsigned char`, `unsigned int`, `unsigned short`, `unsigned long` atau `unsigned long long`. -* Bilangan Pecahan - bilangan real (bilangan dengan pecahan). Didefinisikan menggunakan `float` dan `double`. -* Struktur - akan dijelaskan nanti, di bagian Struktur. - -## Tipe Data dalam C - -Jenis-jenis variabel yang berbeda menentukan batas-batasnya. Sebuah `char` bisa dari -128 hingga 127, sedangkan sebuah `long` bisa dari -2,147,483,648 hingga 2,147,483,647 (`long` dan tipe data numerik lainnya mungkin memiliki rentang lain di komputer yang berbeda, misalnya - dari –9,223,372,036,854,775,808 hingga 9,223,372,036,854,775,807 di komputer 64-bit). - -Perhatikan bahwa C _tidak_ memiliki tipe boolean. Biasanya, itu didefinisikan menggunakan notasi berikut: - -```c -#define BOOL char -#define FALSE 0 -#define TRUE 1 -``` - -C menggunakan array karakter untuk mendefinisikan string, dan akan dijelaskan di bagian String. - -## Mendefinisikan variabel -Untuk angka, kita biasanya akan menggunakan tipe `int`. Di kebanyakan komputer saat ini, itu adalah bilangan 32-bit, yang berarti angkanya bisa dari -2,147,483,648 hingga 2,147,483,647. - -Untuk mendefinisikan variabel `foo` dan `bar`, kita perlu menggunakan sintaks berikut: - -```c -int foo; -int bar = 1; -``` - -Variabel `foo` bisa digunakan, tetapi karena kita tidak menginisialisasinya, kita tidak tahu apa yang ada di dalamnya. Variabel `bar` berisi angka 1. - -Sekarang, kita bisa melakukan beberapa operasi matematika. Dengan mengasumsikan `a`, `b`, `c`, `d`, dan `e` adalah variabel, kita bisa menggunakan operator penjumlahan, pengurangan dan perkalian dalam notasi berikut, dan memberikan nilai baru ke `a`: - -```c -int a = 0, b = 1, c = 2, d = 3, e = 4; -a = b - c + d * e; -printf("%d", a); /* akan mencetak 1-2+3*4 = 11 */ -``` - ---- - -## Tabel Tipe Data dalam C - -| Tipe | Ukuran (bit) | Rentang Nilai | Contoh | -|------|--------------|---------------|--------| -| char | 8 | -128 hingga 127 | `char grade = 'A';` | -| int | 32 | -2,147,483,648 hingga 2,147,483,647 | `int age = 25;` | -| short | 16 | -32,768 hingga 32,767 | `short year = 2023;` | -| long | 64 | -9,223,372,036,854,775,808 hingga 9,223,372,036,854,775,807 | `long population = 1000000L;` | -| float | 32 | ~7 digit desimal | `float price = 19.99f;` | -| double | 64 | ~15 digit desimal | `double pi = 3.14159;` | -| unsigned char | 8 | 0 hingga 255 | `unsigned char count = 100;` | - ----EXERCISE--- - -# Latihan: Menjumlahkan Variabel - -Di latihan berikutnya, Anda perlu membuat program yang mencetak jumlah dari angka `a`, `b`, dan `c`. - -**Requirements:** -- Hitung jumlah dari variabel a, b, dan c -- Simpan hasilnya dalam variabel sum -- Pastikan tipe data yang digunakan sesuai - -**Expected Output:** -``` -The sum of a, b, and c is 12.750000. -``` - -Try writing your solution in the code editor below! - ----EXPECTED_OUTPUT--- -The sum of a, b, and c is 12.750000. ----END_EXPECTED_OUTPUT--- - ----INITIAL_CODE--- -#include - -int main() { - int a = 3; - float b = 4.5; - double c = 5.25; - float sum; - - /* Kode Anda di sini */ - - printf("The sum of a, b, and c is %f.", sum); - return 0; -} ----END_INITIAL_CODE--- - ----SOLUTION_CODE--- -#include - -int main() { - int a = 3; - float b = 4.5; - double c = 5.25; - float sum; - - sum = a + b + c; - printf("The sum of a, b, and c is %f.", sum); - return 0; -} ----END_SOLUTION_CODE--- \ No newline at end of file diff --git a/podman-compose.yml b/podman-compose.yml index 7d602f4..7f30b0a 100644 --- a/podman-compose.yml +++ b/podman-compose.yml @@ -4,6 +4,8 @@ services: elemes: build: . container_name: elemes + ports: + 5000:5000 volumes: - ../content:/app/content - ./static:/app/static diff --git a/templates/lesson.html b/templates/lesson.html index 4cf4120..0f5435c 100644 --- a/templates/lesson.html +++ b/templates/lesson.html @@ -232,6 +232,7 @@ const initialCode = {{ initial_code | tojson }}; const solutionCode = {{ solution_code | tojson }}; const expectedOutput = {{ expected_output | tojson }}; + const keyText = {{ key_text | tojson }}; // Get DOM elements const runButton = document.getElementById('run-code'); @@ -563,6 +564,51 @@ return; } + // Perform static analysis first + let staticAnalysisPassed = true; + let staticAnalysisMessage = ''; + + if (keyText && keyText !== "None" && keyText !== "") { + // Parse the key text to get required keywords + const requiredKeywords = keyText.split('\n').filter(keyword => keyword.trim() !== ''); + + // Perform static analysis + staticAnalysisPassed = true; + staticAnalysisMessage = ''; + + for (const keyword of requiredKeywords) { + if (keyword.trim() !== '') { + // Check if the keyword contains regex patterns (enclosed in slashes) + const trimmedKeyword = keyword.trim(); + + if (trimmedKeyword.startsWith('/') && trimmedKeyword.endsWith('/')) { + // This is a regex pattern + try { + const regexPattern = trimmedKeyword.slice(1, -1); // Remove the leading and trailing slashes + const regex = new RegExp(regexPattern, 'g'); + + if (!regex.test(code)) { + staticAnalysisPassed = false; + staticAnalysisMessage += `Missing pattern: "${trimmedKeyword}"\n`; + } + } catch (e) { + // If regex is malformed, treat as literal string + if (!code.includes(trimmedKeyword)) { + staticAnalysisPassed = false; + staticAnalysisMessage += `Missing required keyword: "${trimmedKeyword}"\n`; + } + } + } else { + // Simple check: see if the literal keyword exists in the code + if (!code.includes(trimmedKeyword)) { + staticAnalysisPassed = false; + staticAnalysisMessage += `Missing required keyword: "${trimmedKeyword}"\n`; + } + } + } + } + } + // Show loading state runButton.innerHTML = ' Running...'; runButton.disabled = true; @@ -591,10 +637,12 @@ outputContent.textContent = data.output || 'Program executed successfully with no output.'; outputContent.className = 'output-success'; - // Check if output matches expected output (if available) + // Check if output matches expected output (if available) AND static analysis passed if (expectedOutput && expectedOutput !== "None" && expectedOutput !== "") { const actualOutput = data.output || ''; - if (actualOutput.trim() === expectedOutput.trim()) { + + // Both output match and static analysis pass are required for success + if (actualOutput.trim() === expectedOutput.trim() && staticAnalysisPassed) { // Show success message card if element exists const successElement = document.getElementById('success-message'); if (successElement) { @@ -691,27 +739,126 @@ }); } } else { - // Hide success message if output doesn't match + // Hide success message if output doesn't match OR static analysis failed const successElement = document.getElementById('success-message'); if (successElement) { successElement.classList.add('d-none'); } - // Hide solution button if output doesn't match + // Hide solution button if output doesn't match OR static analysis failed if (solutionButton) { solutionButton.classList.add('d-none'); } } } else { - // Hide success message if no expected output - const successElement = document.getElementById('success-message'); - if (successElement) { - successElement.classList.add('d-none'); - } + // For lessons without expected output, check only static analysis + if (staticAnalysisPassed) { + // Show success message card if element exists + const successElement = document.getElementById('success-message'); + if (successElement) { + // Remove d-none to show the element + successElement.classList.remove('d-none'); - // Hide solution button if no expected output - if (solutionButton) { - solutionButton.classList.add('d-none'); + // Hide the success message after 10 seconds + setTimeout(function() { + successElement.classList.add('d-none'); + }, 10000); + } + + // Show solution button if solution code exists + if (solutionButton && solutionCode && solutionCode !== "None" && solutionCode !== "") { + solutionButton.classList.remove('d-none'); + } + + // Track progress if student is logged in + const savedToken = localStorage.getItem('student_token'); + if (savedToken) { + // Extract lesson name from the URL + const pathParts = window.location.pathname.split('/'); + let lessonFilename = pathParts[pathParts.length - 1]; + + // Handle the case where the URL might include query parameters + if (lessonFilename.includes('?')) { + lessonFilename = lessonFilename.split('?')[0]; + } + + // Extract just the lesson name without .md extension + const lessonName = lessonFilename.replace('.md', ''); + + // Send progress to server + fetch('/track-progress', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + token: savedToken, + lesson_name: lessonName, + status: 'completed' + }) + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + console.log('Progress tracked successfully for lesson:', lessonName); + // Update the UI to reflect the new status + document.querySelectorAll('.lesson-card').forEach(card => { + const link = card.querySelector('a'); + if (link && link.href.includes(lessonFilename)) { + const statusBadge = card.querySelector('.badge'); + if (statusBadge) { + statusBadge.className = 'badge bg-success float-end'; + statusBadge.title = 'Completed'; + statusBadge.innerHTML = ' Completed'; + } + const btn = card.querySelector('.btn-primary'); + if (btn) { + btn.textContent = btn.textContent.replace('Start Learning', 'Review'); + } + } + }); + + // Update the current lesson status in the sidebar + const statusElement = document.querySelector('.card-body p strong + p span'); + if (statusElement) { + statusElement.className = 'badge bg-success'; + statusElement.innerHTML = ' Completed'; + } + + // Update the lesson in the "All Lessons" sidebar + document.querySelectorAll('.list-group-item').forEach(item => { + if (item.href && item.href.includes(lessonFilename)) { + let badge = item.querySelector('.badge'); + if (!badge) { + badge = document.createElement('span'); + badge.className = 'badge bg-success float-end'; + badge.innerHTML = ''; + item.appendChild(badge); + } else { + badge.className = 'badge bg-success float-end'; + badge.innerHTML = ''; + } + } + }); + } else { + console.error('Failed to track progress:', data.message); + } + }) + .catch(error => { + console.error('Error tracking progress:', error); + }); + } + } else { + // Hide success message if static analysis failed + const successElement = document.getElementById('success-message'); + if (successElement) { + successElement.classList.add('d-none'); + } + + // Hide solution button if static analysis failed + if (solutionButton) { + solutionButton.classList.add('d-none'); + } } } } else {