from __future__ import annotations from pathlib import Path from xml.sax.saxutils import escape ROOT = Path(__file__).resolve().parents[2] RELATIVE = Path("contenus_pedagogiques/cycle_3/mathematiques/cm1/01_nombres_calcul_resolution/01B_fractions/exercices") TARGET_ROOTS = [ROOT / "backend" / RELATIVE, ROOT / "Programme" / RELATIVE] STYLE = """ .bg{fill:#f6f5ef} .panel{fill:#fff;stroke:#d9e7e1;stroke-width:3} .card{fill:#eef7f4;stroke:#c9dfd8;stroke-width:3} .white{fill:#fff;stroke:#c9dfd8;stroke-width:3} .title{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:48px;font-weight:800;fill:#074f4b} .h2{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:28px;font-weight:800;fill:#074f4b} .body{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:24px;fill:#1d3038} .small{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:20px;fill:#2d4148} .frac{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:36px;font-weight:800;fill:#074f4b} .op{font-family:"Trebuchet MS",Verdana,sans-serif;font-size:34px;font-weight:800;fill:#074f4b} .blank{stroke:#7fa79d;stroke-width:3;stroke-dasharray:10 10} .axis{stroke:#26383d;stroke-width:4;stroke-linecap:round} .tick{stroke:#26383d;stroke-width:3;stroke-linecap:round} .shade{fill:#5ab7a8} .empty{fill:#fff} """.strip() def text(x: int, y: int, value: str, klass: str = "body", anchor: str | None = None) -> str: anchor_attr = f' text-anchor="{anchor}"' if anchor else "" return f'{escape(value)}' def line(x1: int, y1: int, x2: int, y2: int, klass: str = "blank") -> str: return f'' def fraction(x: int, y: int, n: str | int, d: str | int, size: int = 52) -> str: n_text = str(n) d_text = str(d) width = max(58, int(max(len(n_text), len(d_text)) * size * 0.62) + 22) cx = width / 2 return ( f'' f'{escape(n_text)}' f'' f'{escape(d_text)}' "" ) def card(x: int, y: int, w: int, h: int, title: str, body: str, soft: bool = True) -> str: klass = "card" if soft else "white" return ( f'' f'' f'{text(32, 58, title, "h2")}' f'{body}' "" ) def sheet(title: str, cards: list[str]) -> str: return ( '\n' f' \n' ' \n' ' \n' f' {text(800, 112, title, "title", "middle")}\n' f' {"".join(cards)}\n' '\n' ) def band(x: int, y: int, parts: int, shaded: int, width: int = 250, height: int = 44) -> str: cell = width / parts rects = [] for index in range(parts): fill = "shade" if index < shaded else "empty" rects.append( f'' ) return "".join(rects) def number_line(x: int, y: int, parts: int, point: int | None = None, width: int = 320) -> str: items = [line(x, y, x + width, y, "axis")] for index in range(parts + 1): px = x + int(width * index / parts) items.append(line(px, y - 14, px, y + 14, "tick")) items.append(text(x, y + 48, "0", "small", "middle")) items.append(text(x + width, y + 48, "1", "small", "middle")) if point is not None: px = x + int(width * point / parts) items.append(f'') return "".join(items) def svg_01() -> str: c1 = "".join( fraction(58, y, n, d) + line(190, y + 8, 360, y + 8) for y, (n, d) in zip([125, 247, 369, 491], [(1, 2), (3, 4), (5, 8), (7, 10)]) ) c2 = "".join( fraction(58, y, n, d) + text(175, y - 22, "Numerateur :", "small") + line(320, y - 22, 385, y - 22) + text(175, y + 42, "Denominateur :", "small") + line(330, y + 42, 385, y + 42) for y, (n, d) in zip([145, 305, 465], [(2, 5), (4, 9), (6, 7)]) ) c3 = ( text(45, 140, "deux tiers", "body") + line(45, 180, 340, 180) + text(45, 260, "trois cinquiemes", "body") + line(45, 300, 340, 300) + text(45, 380, "neuf dixiemes", "body") + line(45, 420, 340, 420) + text(45, 510, "Ecris avec une barre horizontale.", "small") ) return sheet("Exercices - Lire et ecrire une fraction", [ card(110, 190, 430, 560, "1. Lis", c1), card(590, 190, 430, 560, "2. Haut et bas", c2, False), card(1070, 190, 420, 560, "3. Ecris", c3), ]) def svg_02() -> str: c1 = ( text(38, 120, "Quelle fraction est coloriee ?", "body") + band(45, 160, 3, 2) + line(330, 185, 430, 185) + band(45, 260, 5, 4) + line(330, 285, 430, 285) + band(45, 360, 10, 6) + line(330, 385, 430, 385) ) c2 = "".join( fraction(52, y, n, d) + text(160, y + 18, "Dessine une bande.", "small") + line(345, y + 18, 470, y + 18) for y, (n, d) in zip([145, 285, 425], [(1, 4), (3, 6), (5, 8)]) ) c3 = ( text(40, 130, "Verifie toujours :", "body") + text(55, 200, "1. une seule unite", "body") + text(55, 270, "2. des parts egales", "body") + text(55, 340, "3. les parts prises", "body") + text(55, 450, "Explique ton choix a l'oral.", "small") ) return sheet("Exercices - Representer une fraction partagee", [ card(95, 190, 460, 560, "1. Fraction coloriee", c1), card(590, 190, 500, 560, "2. Dessine", c2, False), card(1125, 190, 360, 560, "3. Verifie", c3), ]) def svg_03() -> str: c1 = number_line(55, 190, 4) + text(55, 115, "L'unite est partagee en 4.", "body") + line(55, 330, 350, 330) c2 = number_line(55, 210, 4, 3) + text(55, 115, "Avance de 3 petites parts.", "body") + fraction(360, 330, 3, 4) c3 = number_line(55, 210, 5, 2) + text(55, 115, "Lis le point orange.", "body") + line(55, 330, 350, 330) return sheet("Exercices - Fraction sur demi-droite", [ card(95, 190, 450, 500, "1. L'unite", c1), card(575, 190, 450, 500, "2. Placer", c2, False), card(1055, 190, 450, 500, "3. Lire", c3), ]) def svg_04() -> str: c1 = "".join(fraction(x, 170, n, d) for x, (n, d) in zip([45, 150, 255, 360, 465], [(2, 5), (5, 5), (7, 5), (9, 4), (3, 8)])) c1 += text(45, 330, "Entoure seulement celles qui sont > 1.", "small") c2 = ( fraction(45, 150, 5, 4) + text(145, 170, "=", "op") + fraction(205, 150, 4, 4) + text(305, 170, "+", "op") + line(365, 170, 500, 170) + fraction(45, 330, 7, 3) + text(145, 350, "=", "op") + fraction(205, 330, 6, 3) + text(305, 350, "+", "op") + line(365, 350, 500, 350) ) c3 = ( text(35, 135, "Numerateur", "small") + text(35, 180, "plus grand", "small") + text(35, 225, "que le bas :", "small") + text(35, 285, "souvent > 1.", "small") + text(35, 380, "Egal veut = 1.", "small") ) return sheet("Exercices - Fractions superieures a 1", [ card(80, 190, 560, 500, "1. Reconnaitre", c1), card(670, 190, 560, 500, "2. Decomposer", c2, False), card(1260, 190, 260, 500, "3. Attention", c3), ]) def svg_05() -> str: rows = [(2, 7, "<", 5, 7), (6, 8, ">", 3, 8), (4, 9, "=", 4, 9)] c1 = "".join( fraction(45, y, a, b) + text(155, y + 22, "...", "op") + fraction(235, y, c, d) for y, (a, b, _, c, d) in zip([135, 285, 435], rows) ) c2 = "".join( fraction(45, y, a, b) + text(155, y + 22, "ou", "op") + fraction(245, y, c, d) + line(360, y + 22, 500, y + 22) for y, (a, b, c, d) in zip([135, 285, 435], [(1, 2, 1, 4), (2, 3, 2, 5), (3, 6, 3, 10)]) ) c3 = ( text(45, 130, "Meme denominateur :", "body") + text(45, 190, "compare les numerateurs.", "small") + text(45, 290, "Meme numerateur :", "body") + text(45, 350, "les parts grandes", "small") + text(45, 390, "ont un bas plus petit.", "small") ) return sheet("Exercices - Comparer des fractions", [ card(80, 190, 520, 560, "1. Complete", c1), card(630, 190, 520, 560, "2. Choisis", c2, False), card(1180, 190, 330, 560, "3. Strategie", c3), ]) def svg_06() -> str: c1 = ( text(45, 125, "Avec des quarts :", "body") + text(45, 185, "1 =", "op") + line(120, 185, 220, 185) + text(235, 185, "et 2 =", "op") + line(340, 185, 440, 185) + text(45, 300, "Avec des tiers :", "body") + text(45, 360, "2 =", "op") + line(120, 360, 220, 360) + text(235, 360, "et 3 =", "op") + line(340, 360, 440, 360) ) c2 = ( text(45, 177, "... <", "op") + fraction(180, 155, 5, 4) + text(290, 177, "< ...", "op") + text(45, 327, "... <", "op") + fraction(180, 305, 8, 3) + text(290, 327, "< ...", "op") + text(45, 477, "... <", "op") + fraction(180, 455, 11, 5) + text(305, 477, "< ...", "op") ) c3 = number_line(45, 220, 4, 5, 320) + text(45, 120, "Repere l'entier juste avant", "body") + text(45, 345, "puis l'entier juste apres.", "small") return sheet("Exercices - Encadrer une fraction", [ card(90, 190, 470, 540, "1. Entiers", c1), card(595, 190, 410, 540, "2. Encadrer", c2, False), card(1040, 190, 470, 540, "3. Droite", c3), ]) def svg_07() -> str: c1 = "".join( fraction(45, y, a, b) + text(145, y + 22, "+", "op") + fraction(205, y, c, d) + text(310, y + 22, "=", "op") + line(370, y + 22, 510, y + 22) for y, (a, b, c, d) in zip([125, 275, 425], [(1, 5, 2, 5), (2, 7, 3, 7), (4, 10, 5, 10)]) ) c2 = "".join( fraction(45, y, a, b) + text(145, y + 22, "-", "op") + fraction(205, y, c, d) + text(310, y + 22, "=", "op") + line(370, y + 22, 510, y + 22) for y, (a, b, c, d) in zip([125, 275, 425], [(6, 8, 2, 8), (7, 9, 3, 9), (10, 12, 4, 12)]) ) c3 = ( text(35, 130, "On garde", "small") + text(35, 175, "le denominateur.", "small") + text(35, 260, "On calcule", "small") + text(35, 305, "les numerateurs.", "small") + line(45, 380, 330, 380) ) return sheet("Exercices - Additionner et soustraire", [ card(75, 190, 560, 560, "1. Additionner", c1), card(665, 190, 560, 560, "2. Soustraire", c2, False), card(1255, 190, 270, 560, "3. Regle", c3), ]) def svg_08() -> str: c1 = "".join( fraction(45, y, n, d) + text(145, y + 22, f"de {q} =", "op") + line(285, y + 22, 440, y + 22) for y, (n, d, q) in zip([135, 285, 435], [(1, 2, 18), (1, 3, 24), (1, 5, 40)]) ) c2 = "".join( fraction(45, y, n, d) + text(145, y + 22, f"de {q} =", "op") + line(285, y + 22, 440, y + 22) for y, (n, d, q) in zip([135, 285, 435], [(3, 4, 20), (2, 5, 30), (3, 6, 42)]) ) c3 = ( text(45, 130, "1. Je partage par le bas.", "body") + text(45, 210, "2. Je prends le haut.", "body") + text(45, 310, "Exemple :", "body") + fraction(45, 390, 3, 4) + text(145, 412, "de 20", "op") ) return sheet("Exercices - Fraction d'une quantite", [ card(80, 190, 490, 560, "1. Une part", c1), card(610, 190, 490, 560, "2. Plusieurs parts", c2, False), card(1140, 190, 370, 560, "3. Methode", c3), ]) SVG_BY_DIR = { "01_lire_ecrire_fraction_simple": svg_01, "02_representer_fraction_partage": svg_02, "03_fraction_sur_demi_droite_graduee": svg_03, "04_fraction_superieure_a_un": svg_04, "05_comparer_fractions_simples": svg_05, "06_encadrer_fraction_entre_entiers": svg_06, "07_additionner_soustraire_fractions_simples": svg_07, "08_fraction_d_une_quantite": svg_08, } def main() -> None: for root in TARGET_ROOTS: for folder, builder in SVG_BY_DIR.items(): target = root / folder / "exercices.svg" target.parent.mkdir(parents=True, exist_ok=True) target.write_text(builder(), encoding="utf-8") print(f"updated {target}") if __name__ == "__main__": main()