Add networks unit 10: ISO/OSI and TCP/IP models with quiz.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
pepaskopec-blip 2026-09-11 18:11:41 +02:00
commit 2e6d1d9457
4 changed files with 195 additions and 11 deletions

14
i18n.c
View file

@ -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"},

2
main.c
View file

@ -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];

View file

@ -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);

185
net.c
View file

@ -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;
}