From 2e6d1d9457068c7f1adff22ddcae93f0d733c125 Mon Sep 17 00:00:00 2001 From: pepaskopec-blip Date: Fri, 11 Sep 2026 18:11:41 +0200 Subject: [PATCH] Add networks unit 10: ISO/OSI and TCP/IP models with quiz. Co-authored-by: Cursor --- i18n.c | 14 ++++ main.c | 2 + maturita.h | 5 +- net.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 195 insertions(+), 11 deletions(-) diff --git a/i18n.c b/i18n.c index bc2d2bf..15d2c84 100644 --- a/i18n.c +++ b/i18n.c @@ -247,6 +247,12 @@ const TrEntry tr_ui[] = { "4 slides about layers and protocols, then a quiz."}, {"net_ex9_title", "Kvíz: vrstevnaté modely a protokoly", "Quiz: layered models and protocols"}, + {"net_unit10", "Model ISO/OSI a TCP/IP", + "ISO/OSI and TCP/IP models"}, + {"net_unit10_sub", "3 snímky o ISO/OSI a TCP/IP a pak kvíz.", + "3 slides about ISO/OSI and TCP/IP, then a quiz."}, + {"net_ex10_title", "Kvíz: ISO/OSI a TCP/IP", + "Quiz: ISO/OSI and TCP/IP"}, {"net_slide_next", "Další", "Next"}, {"net_slide_prev", "Zpět", "Back"}, {"net_slide_start", "Přejít na cvičení", "Go to the exercise"}, @@ -397,6 +403,14 @@ const TrEntry tr_content[] = { "Each layer adds a header to the data"}, {"Rámec = linková, paket = síťová, segment = transportní", NULL, "Frame = link, packet = network, segment = transport"}, + {"ISO/OSI má 7 vrstev a je univerzální model", NULL, + "ISO/OSI has 7 layers and is a universal model"}, + {"V praxi je ISO/OSI pomalejší – spolehlivost řeší každá vrstva", NULL, + "In practice ISO/OSI is slower – each layer handles reliability"}, + {"TCP/IP zvítězil, protože vycházel ze skutečných potřeb", NULL, + "TCP/IP won because it came from real-world needs"}, + {"V TCP/IP řeší spolehlivost až vyšší vrstvy", NULL, + "In TCP/IP, reliability is handled by higher layers"}, {"čtrnáct", NULL, "fourteen"}, {"sedmnáct", NULL, "seventeen"}, {"dvacet", NULL, "twenty"}, diff --git a/main.c b/main.c index 8908572..3dbab3d 100644 --- a/main.c +++ b/main.c @@ -189,6 +189,8 @@ void activate(GtkApplication *app, gpointer user_data) { gtk_stack_add_named(main_stack, build_net_unit8_exercise_page(), "netex8"); gtk_stack_add_named(main_stack, build_net_unit9_page(), "netunit9"); gtk_stack_add_named(main_stack, build_net_unit9_exercise_page(), "netex9"); + gtk_stack_add_named(main_stack, build_net_unit10_page(), "netunit10"); + gtk_stack_add_named(main_stack, build_net_unit10_exercise_page(), "netex10"); for (int i = 0; i < NUM_UNLOCKED; i++) { UnitCtx *u = &units[i]; diff --git a/maturita.h b/maturita.h index 97d66ed..3999c0c 100644 --- a/maturita.h +++ b/maturita.h @@ -54,7 +54,8 @@ #define NET7_SLIDES 4 #define NET8_SLIDES 4 #define NET9_SLIDES 4 -#define NET_LESSONS 9 +#define NET10_SLIDES 3 +#define NET_LESSONS 10 typedef enum { THEME_CATPPUCCIN = 0, @@ -1021,6 +1022,7 @@ GtkWidget *build_net_unit6_page(void); GtkWidget *build_net_unit7_page(void); GtkWidget *build_net_unit8_page(void); GtkWidget *build_net_unit9_page(void); +GtkWidget *build_net_unit10_page(void); GtkWidget *net_qz_combo(void); void net_qz_set_prefix(GtkComboBoxText *c, int pfx); int net_qz_prefix(GtkComboBoxText *c); @@ -1040,6 +1042,7 @@ GtkWidget *build_net_unit6_exercise_page(void); GtkWidget *build_net_unit7_exercise_page(void); GtkWidget *build_net_unit8_exercise_page(void); GtkWidget *build_net_unit9_exercise_page(void); +GtkWidget *build_net_unit10_exercise_page(void); void activate(GtkApplication *app, gpointer user_data); int main(int argc, char **argv); diff --git a/net.c b/net.c index f788b40..ce73f90 100644 --- a/net.c +++ b/net.c @@ -4,15 +4,16 @@ NetLesson net_lessons[NET_LESSONS] = { - { .n_slides = NET_SLIDES, .unit_page = "netunit1", .ex_page = "netex" }, - { .n_slides = NET2_SLIDES, .unit_page = "netunit2", .ex_page = "netex2" }, - { .n_slides = NET3_SLIDES, .unit_page = "netunit3", .ex_page = "netex3" }, - { .n_slides = NET4_SLIDES, .unit_page = "netunit4", .ex_page = "netex4" }, - { .n_slides = NET5_SLIDES, .unit_page = "netunit5", .ex_page = "netex5" }, - { .n_slides = NET6_SLIDES, .unit_page = "netunit6", .ex_page = "netex6" }, - { .n_slides = NET7_SLIDES, .unit_page = "netunit7", .ex_page = "netex7" }, - { .n_slides = NET8_SLIDES, .unit_page = "netunit8", .ex_page = "netex8" }, - { .n_slides = NET9_SLIDES, .unit_page = "netunit9", .ex_page = "netex9" }, + { .n_slides = NET_SLIDES, .unit_page = "netunit1", .ex_page = "netex" }, + { .n_slides = NET2_SLIDES, .unit_page = "netunit2", .ex_page = "netex2" }, + { .n_slides = NET3_SLIDES, .unit_page = "netunit3", .ex_page = "netex3" }, + { .n_slides = NET4_SLIDES, .unit_page = "netunit4", .ex_page = "netex4" }, + { .n_slides = NET5_SLIDES, .unit_page = "netunit5", .ex_page = "netex5" }, + { .n_slides = NET6_SLIDES, .unit_page = "netunit6", .ex_page = "netex6" }, + { .n_slides = NET7_SLIDES, .unit_page = "netunit7", .ex_page = "netex7" }, + { .n_slides = NET8_SLIDES, .unit_page = "netunit8", .ex_page = "netex8" }, + { .n_slides = NET9_SLIDES, .unit_page = "netunit9", .ex_page = "netex9" }, + { .n_slides = NET10_SLIDES, .unit_page = "netunit10", .ex_page = "netex10" }, }; void net_paragraph(GtkWidget *box, const char *text) { @@ -440,7 +441,7 @@ void net_add_node(GtkFixed *fixed, int index) { char *text; static const char *unit_keys[NET_LESSONS] = { "net_unit1", "net_unit2", "net_unit3", "net_unit4", "net_unit5", - "net_unit6", "net_unit7", "net_unit8", "net_unit9" + "net_unit6", "net_unit7", "net_unit8", "net_unit9", "net_unit10" }; card = gtk_button_new(); @@ -1096,6 +1097,44 @@ GtkWidget *build_net_unit9_page(void) { return build_net_unit_page(&net_lessons[8], "net_unit9", slides, NET9_SLIDES); } +GtkWidget *build_net_unit10_page(void) { + static const NetSlide slides[NET10_SLIDES] = { + { + "1 / 3 • ISO/OSI", "Sedmivrstvý model", + NULL, + { + "ISO/OSI: 7vrstvý model.", + "Je univerzální – popisuje komunikaci obecně.", + "V praxi je ale pomalejší: každá vrstva řešila spolehlivost.", + NULL, + }, + }, + { + "2 / 3 • TCP/IP", "Praktická architektura", + NULL, + { + "TCP/IP: architektura, která zvítězila v praxi.", + "Vycházela ze skutečných potřeb sítí.", + "Spolehlivost řeší až vyšší vrstvy.", + NULL, + }, + }, + { + "3 / 3 • Srovnání", "Proč zvítězil TCP/IP", + "Tip: méně režie na nižších vrstvách = rychlejší provoz", + { + "ISO/OSI: teoretický, univerzální, těžší a pomalejší.", + "TCP/IP: praktický, jednodušší dělení odpovědností.", + "Proto se TCP/IP stal základem dnešního internetu.", + NULL, + }, + }, + }; + + return build_net_unit_page(&net_lessons[9], "net_unit10", slides, + NET10_SLIDES); +} + /* Solutions below are the canonical "largest subnet first, in order A–D" * allocation. Scenario 3 does not fit into a /24 as written, which is why * its "solution" explains that instead. */ @@ -2555,3 +2594,129 @@ GtkWidget *build_net_unit9_exercise_page(void) { return page; } + +/* ---- Unit 10: ISO/OSI and TCP/IP quiz -------------------------------- */ + +const ChoiceQ net10_qs[] = { + {"Model ISO/OSI má:", + {"4 vrstvy", "5 vrstev", "7 vrstev", "10 vrstev"}, 4, 2}, + {"ISO/OSI je především:", + {"Jen typ kabelu", "Univerzální referenční model", + "Jen tiskový server", "Jen FDM"}, 4, 1}, + {"Proč je ISO/OSI v praxi pomalejší?", + {"Nemá žádné vrstvy", "Každá vrstva řešila spolehlivost", + "Nepoužívá protokoly", "Nemá SAP"}, 4, 1}, + {"TCP/IP v praxi:", + {"Prohrál proti ISO/OSI", "Zvítězil jako praktická architektura", + "Je jen analogový signál", "Je jen half-duplex"}, 4, 1}, + {"TCP/IP vycházel z:", + {"Jen teoretických schémat bez praxe", "Skutečných potřeb sítí", + "Jen parity", "Jen trunkingu"}, 4, 1}, + {"V TCP/IP spolehlivost řeší:", + {"Vždy jen fyzická vrstva", "Až vyšší vrstvy", + "Jen metalické kabely", "Jen mainframe"}, 4, 1}, +}; + +const char *net10_hints[] = { + "ISO/OSI má 7 vrstev a je univerzální model", + "ISO/OSI má 7 vrstev a je univerzální model", + "V praxi je ISO/OSI pomalejší – spolehlivost řeší každá vrstva", + "TCP/IP zvítězil, protože vycházel ze skutečných potřeb", + "TCP/IP zvítězil, protože vycházel ze skutečných potřeb", + "V TCP/IP řeší spolehlivost až vyšší vrstvy", +}; + +GtkWidget *build_net_unit10_exercise_page(void) { + GtkWidget *page; + GtkWidget *scroll; + GtkWidget *body; + GtkWidget *check; + GtkWidget *btns; + NetMcqCtx *ctx = g_new0(NetMcqCtx, 1); + int n = (int)G_N_ELEMENTS(net10_qs); + int n_opts = net10_qs[0].n_options; + + page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_margin_start(page, 32); + gtk_widget_set_margin_end(page, 32); + gtk_widget_set_margin_top(page, 24); + gtk_widget_set_margin_bottom(page, 24); + + gtk_box_append(GTK_BOX(page), + top_bar("netunit10", "net_ex10_title", NULL)); + + scroll = gtk_scrolled_window_new(); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_vexpand(scroll, TRUE); + gtk_widget_set_margin_top(scroll, 12); + gtk_box_append(GTK_BOX(page), scroll); + + body = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); + gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), body); + + net_heading(body, "Kvíz k ISO/OSI a TCP/IP"); + net_paragraph(body, + "Vyberte u každé otázky jednu správnou odpověď " + "a stiskněte Zkontrolovat."); + + ctx->qs = net10_qs; + ctx->n = n; + ctx->n_opts = n_opts; + ctx->toggles = g_new0(GtkToggleButton *, n * n_opts); + ctx->hints = g_new0(GtkWidget *, n); + + for (int i = 0; i < n; i++) { + GtkWidget *prompt; + GtkWidget *row; + GtkToggleButton *first = NULL; + char *qtext; + + qtext = g_strdup_printf("%d.) %s", i + 1, net10_qs[i].prompt); + prompt = gtk_label_new(qtext); + g_free(qtext); + gtk_widget_set_halign(prompt, GTK_ALIGN_START); + gtk_label_set_wrap(GTK_LABEL(prompt), TRUE); + gtk_widget_add_css_class(prompt, "ex-prompt"); + gtk_widget_set_margin_top(prompt, 8); + gtk_box_append(GTK_BOX(body), prompt); + + row = gtk_flow_box_new(); + gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(row), GTK_SELECTION_NONE); + gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(row), n_opts); + gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(row), n_opts); + gtk_widget_set_halign(row, GTK_ALIGN_START); + gtk_box_append(GTK_BOX(body), row); + + for (int o = 0; o < n_opts; o++) { + GtkWidget *tb = + gtk_toggle_button_new_with_label(net10_qs[i].options[o]); + + gtk_widget_add_css_class(tb, "pill"); + gtk_toggle_button_set_group(GTK_TOGGLE_BUTTON(tb), first); + if (!first) + first = GTK_TOGGLE_BUTTON(tb); + gtk_flow_box_append(GTK_FLOW_BOX(row), tb); + ctx->toggles[i * n_opts + o] = GTK_TOGGLE_BUTTON(tb); + } + + ctx->hints[i] = meaning_add(body, net10_hints[i]); + } + + btns = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); + gtk_widget_set_margin_top(btns, 12); + gtk_box_append(GTK_BOX(body), btns); + + check = gtk_button_new(); + i18n_bind(check, "check", 1); + gtk_widget_add_css_class(check, "pill"); + gtk_widget_set_halign(check, GTK_ALIGN_START); + gtk_box_append(GTK_BOX(btns), check); + g_signal_connect(check, "clicked", G_CALLBACK(net_mcq_check), ctx); + + ctx->feedback = gtk_label_new(""); + gtk_widget_set_halign(ctx->feedback, GTK_ALIGN_START); + gtk_box_append(GTK_BOX(body), ctx->feedback); + + return page; +}