diff --git a/README.md b/README.md index e66f57e..6daf3b1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,118 @@ # cowsay -cowsay project for school +Projet INF203 autour de `cowsay`. +Cette même README est aussi publiée sur le site : , Les graphisme pour la charte seront mieux +il y a aussi le depot sur -# Preliminaries +## Contenu du dépôt -cowsay options : +- `start.sh` : lance un tour guidé de la plupart des programmes du projet. +- `ProjetCowsay.pdf` : document de projet au format PDF. +- `TODO.md` : checklist de suivi du travail demandé. +- `src/bash_scripts/` : scripts Bash. +- `src/C/` : programmes C principaux. +- `src/C/newcows/` : variantes C supplémentaires et script de compilation rapide. -- -e/--eyes -- -T -- +## Dépendances +Pour exécuter tout le projet, il faut au minimum : + +- `bash` +- `cowsay` +- `bc` pour `smart_cow.sh` +- un compilateur C : `cc`, `clang` ou `gcc` + +## Lancement rapide + +Depuis la racine du dépôt : + +```bash +bash start.sh +``` + +Le script de démonstration compile les programmes C dans un dossier temporaire puis exécute les différents exemples les uns après les autres. + +## Résumé des scripts Bash + +| Programme | Rôle | Exemple | +| --- | --- | --- | +| `cow_kindergarten.sh` | Fait parler la vache de `1` à `10`, avec une pause d'une seconde entre chaque valeur, puis termine avec une langue sortie. | `bash src/bash_scripts/cow_kindergarten.sh` | +| `cow_primaryschool.sh` | Fait parler la vache de `1` à `n`. | `bash src/bash_scripts/cow_primaryschool.sh 5` | +| `cow_highschool.sh` | Affiche les carrés parfaits de `1^2` à `n^2`. | `bash src/bash_scripts/cow_highschool.sh 5` | +| `cow_college.sh` | Affiche les `n` premiers termes de la suite de Fibonacci avec mémoïsation. | `bash src/bash_scripts/cow_college.sh 7` | +| `cow_university.sh` | Affiche les nombres premiers jusqu'à `n` avec un crible d'Ératosthène. | `bash src/bash_scripts/cow_university.sh 30` | +| `smart_cow.sh` | Évalue une expression arithmétique simple et essaie d'afficher le résultat dans les yeux de la vache. | `bash src/bash_scripts/smart_cow.sh '4+13'` | +| `crazy_cow.sh` | Génère une suite "look-and-say" de manière interactive, puis affiche toutes les étapes dans `cowsay`. | `bash src/bash_scripts/crazy_cow.sh` | + +## Résumé des programmes C + +| Programme | Rôle | Exemple | +| --- | --- | --- | +| `src/C/newcow.c` | Affiche une vache ASCII sans bulle, avec option `-e` ou `--eyes` pour changer les yeux. | `cc src/C/newcow.c -o /tmp/newcow && /tmp/newcow -e ^^` | +| `src/C/newcows/newcowT.c` | Variante de `newcow` qui gère la langue avec l'option `-T`. | `cc src/C/newcows/newcowT.c -o /tmp/newcowT && /tmp/newcowT -T U` | +| `src/C/newcows/newcowp.c` | Ajoute une bulle de texte simple au-dessus de la vache. | `cc src/C/newcows/newcowp.c -o /tmp/newcowp && /tmp/newcowp -p "Hello"` | +| `src/C/newcows/makefilealacon.sh` | Compile rapidement un fichier `.c` en un exécutable `.out` avec `clang`. | `bash src/C/newcows/makefilealacon.sh src/C/newcows/newcowT.c` | +| `src/C/newcow2.c` | Regroupe plusieurs animations terminales : clignement, langue, marche, rebond. | `cc src/C/newcow2.c -o /tmp/newcow2 && /tmp/newcow2 blink` | +| `src/C/reading_cow.c` | Lit un fichier caractère par caractère et montre la vache en train de "manger" le texte. | `cc src/C/reading_cow.c -o /tmp/reading_cow && /tmp/reading_cow --i 0.10 README.md` | +| `src/C/tamagoshi_cow.c` | Mini jeu en boucle avec gestion de `stock`, `fitness` et score de survie. | `cc src/C/tamagoshi_cow.c -o /tmp/tamagoshi_cow && /tmp/tamagoshi_cow` | + +## Tour d'ensemble du projet + +1. Bash simple avec comptage et pauses. +2. Bash plus algorithmique avec carrés, Fibonacci et nombres premiers. +3. Personnalisation de la vache en C. +4. Animations et interactions dans le terminal. +5. Programme de lecture de fichier. +6. Automate de jeu avec états pour le tamagotchi. + +## Partie automate + +- `liferocks` si `fitness` est entre `4` et `6` +- `lifesucks` si `fitness` est entre `1` et `3` ou entre `7` et `9` +- `byebyelife` si `fitness` vaut `0` ou `10` + +À chaque tour : + +- le joueur choisit `lunchfood` +- `fitness` est mise à jour avec un effet de digestion aléatoire +- `stock` est mis à jour avec une variation aléatoire de récolte +- si `fitness` atteint `0` ou `10`, la partie s'arrête + +```flow +st=>start: Début du jeu + +init=>operation: fitness = 5 ; stock = 5 ; score = 0 + +etat=>condition: fitness == 0 ou fitness == 10 ? +mort=>end: byebyelife Afficher score final + +checkRock=>condition: 4 ≤ fitness ≤ 6 ? +liferocks=>operation: liferocks;Afficher vache saine +lifesucks=>operation: lifesucks;Afficher vache malade + +affStock=>operation: Afficher stock + +choix=>operation: lunchfood choisi;0 ≤ lunchfood ≤ stock + +alea=>operation: digestion ∈ [-3,0];crop ∈ [-3,3] + +majFit=>operation: fitness = fitness + lunchfood + digestion +clampFit=>operation: fitness borné entre 0 et 10 + +majStock=>operation: stock = stock - lunchfood + crop +clampStock=>operation: stock borné entre 0 et 10 + +score=>operation: score += 1 + +st->init->etat +etat(yes)->mort +etat(no)->checkRock +checkRock(yes)->liferocks->affStock +checkRock(no)->lifesucks->affStock + +affStock->choix->alea->majFit->clampFit->majStock->clampStock->score->etat +``` + +## Remarques + +- Il faut utiliser start.sh pour avoir une demo du projet diff --git a/src/C/newcows/makefilealacon.sh b/src/C/newcows/makefilealacon.sh deleted file mode 100755 index e56ff05..0000000 --- a/src/C/newcows/makefilealacon.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -clang "$1" -o "${1%%.c}".out diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..23def38 --- /dev/null +++ b/start.sh @@ -0,0 +1,325 @@ +#!/usr/bin/env bash + +set -u +set -o pipefail + +ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd) +TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/cowsay-tour.XXXXXX") +trap 'rm -rf "$TMP_DIR"' EXIT + +AUTO_RUN=0 +COUNTDOWN=10 +STOP_TOUR=0 +COMPILER="" + +usage() { + cat <<'EOF' +Usage: + ./tour_programmes.sh + ./tour_programmes.sh --auto + +Options: + --auto starts immediately without waiting + -h, --help shows this help +EOF +} + +while (($# > 0)); do + case "$1" in + --auto) + AUTO_RUN=1 + ;; + -h | --help) + usage + exit 0 + ;; + *) + printf 'Unknown option: %s\n\n' "$1" >&2 + usage >&2 + exit 1 + ;; + esac + shift +done + +hr() { + printf '\n============================================================\n' +} + +show_intro() { + hr + printf 'Quick cowsay program tour\n' + if ((AUTO_RUN == 1)); then + printf 'Auto mode: demos start immediately.\n' + else + printf 'The first demo starts after %d seconds.\n' "$COUNTDOWN" + printf 'After each demo, the tour waits %d seconds before the next one.\n' "$COUNTDOWN" + printf 'Press Enter to continue faster, or type n then Enter to stop.\n' + fi +} + +need_commands() { + local missing=0 + local cmd + + for cmd in "$@"; do + if ! command -v "$cmd" >/dev/null 2>&1; then + printf 'Missing dependency: %s\n' "$cmd" >&2 + missing=1 + fi + done + + return "$missing" +} + +detect_compiler() { + if [[ -n "$COMPILER" ]]; then + return 0 + fi + + local candidate + for candidate in cc clang gcc; do + if command -v "$candidate" >/dev/null 2>&1; then + COMPILER="$candidate" + return 0 + fi + done + + printf 'No C compiler found.\n' >&2 + return 1 +} + +compile_c() { + local source="$1" + local output="$2" + + detect_compiler || return 1 + "$COMPILER" -std=c99 -Wall -Wextra -O2 -D_DEFAULT_SOURCE "$source" -o "$output" +} + +run_command() { + "$@" +} + +run_command_with_input() { + local input="$1" + shift + printf '%s' "$input" | "$@" +} + +announce_demo() { + local name="$1" + local description="$2" + + hr + printf '%s: %s\n' "$name" "$description" +} + +drain_stdin() { + if [[ ! -t 0 ]]; then + return 0 + fi + + while IFS= read -r -t 0; do + : + done +} + +timed_continue() { + local prompt="$1" + + if ((AUTO_RUN == 1)) || [[ ! -t 0 ]]; then + printf 'Starting...\n' + return 0 + fi + + drain_stdin + printf '%s' "$prompt" + + local answer="" + if IFS= read -r -t "$COUNTDOWN" answer; then + printf '\n' + case "${answer,,}" in + n) + STOP_TOUR=1 + return 1 + ;; + *) + return 0 + ;; + esac + fi + + printf '\n' + return 0 +} + +run_demo() { + local name="$1" + local function_name="$2" + + "$function_name" + local status=$? + + if ((status != 0)); then + printf '%s: failed (%d)\n' "$name" "$status" >&2 + fi +} + +demo_cow_kindergarten() { + need_commands cowsay || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/cow_kindergarten.sh" +} + +demo_cow_primaryschool() { + need_commands cowsay || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/cow_primaryschool.sh" 3 +} + +demo_cow_highschool() { + need_commands cowsay || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/cow_highschool.sh" 3 +} + +demo_cow_college() { + need_commands cowsay || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/cow_college.sh" 5 +} + +demo_cow_university() { + need_commands cowsay || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/cow_university.sh" 12 +} + +demo_smart_cow() { + need_commands cowsay bc || return 1 + run_command bash "$ROOT_DIR/src/bash_scripts/smart_cow.sh" '4+13' +} + +demo_crazy_cow() { + need_commands cowsay || return 1 + run_command_with_input $'5\n' bash "$ROOT_DIR/src/bash_scripts/crazy_cow.sh" +} + +demo_newcow() { + local bin="$TMP_DIR/newcow" + compile_c "$ROOT_DIR/src/C/newcow.c" "$bin" || return 1 + run_command "$bin" -e "^^" +} + +demo_newcowt() { + local bin="$TMP_DIR/newcowT" + compile_c "$ROOT_DIR/src/C/newcows/newcowT.c" "$bin" || return 1 + run_command "$bin" -T "U" +} + +demo_newcowp() { + local bin="$TMP_DIR/newcowp" + compile_c "$ROOT_DIR/src/C/newcows/newcowp.c" "$bin" || return 1 + run_command "$bin" -p "Hello" +} + +demo_newcow2() { + local bin="$TMP_DIR/newcow2" + compile_c "$ROOT_DIR/src/C/newcow2.c" "$bin" || return 1 + run_command "$bin" blink +} + +demo_reading_cow() { + local bin="$TMP_DIR/reading_cow" + local sample="$TMP_DIR/reading_demo.txt" + + compile_c "$ROOT_DIR/src/C/reading_cow.c" "$bin" || return 1 + printf 'Hello.\nI read.\n' >"$sample" + run_command "$bin" --i 0.10 "$sample" +} + +demo_tamagoshi_cow() { + local bin="$TMP_DIR/tamagoshi_cow" + + if ((AUTO_RUN == 1)) || [[ ! -t 0 ]]; then + printf 'Tamagoshi skipped in auto mode.\n' + return 0 + fi + + compile_c "$ROOT_DIR/src/C/tamagoshi_cow.c" "$bin" || return 1 + run_command "$bin" +} + +visit_programs() { + local -a names=( + 'cow_kindergarten.sh' + 'cow_primaryschool.sh' + 'cow_highschool.sh' + 'cow_college.sh' + 'cow_university.sh' + 'smart_cow.sh' + 'crazy_cow.sh' + 'newcow.c' + 'newcowT.c' + 'newcowp.c' + 'newcow2.c' + 'reading_cow.c' + 'tamagoshi_cow.c' + ) + local -a descriptions=( + 'Counts from 1 to 10.' + 'Counts up to n.' + 'Shows square numbers.' + 'Shows Fibonacci.' + 'Shows prime numbers.' + 'Calculates an expression.' + 'Generates a weird sequence.' + 'Basic cow.' + 'Cow with a tongue option.' + 'Cow with a speech bubble.' + 'Compiles a .c file into .out.' + 'Animates the cow.' + 'The cow reads a file.' + 'Small cow game.' + ) + local -a functions=( + 'demo_cow_kindergarten' + 'demo_cow_primaryschool' + 'demo_cow_highschool' + 'demo_cow_college' + 'demo_cow_university' + 'demo_smart_cow' + 'demo_crazy_cow' + 'demo_newcow' + 'demo_newcowt' + 'demo_newcowp' + 'demo_newcow2' + 'demo_reading_cow' + 'demo_tamagoshi_cow' + ) + + local total=${#names[@]} + local i + + for ((i = 0; i < total; i++)); do + announce_demo "${names[i]}" "${descriptions[i]}" + + if ((i == 0)); then + timed_continue "Press Enter to start, type n then Enter to stop, auto-start in ${COUNTDOWN} seconds... " || return + else + timed_continue "Press Enter to start the next program, type n then Enter to stop, or wait ${COUNTDOWN} seconds... " || return + fi + + run_demo "${names[i]}" "${functions[i]}" + ((STOP_TOUR == 1)) && return + done +} + +show_outro() { + hr + if ((STOP_TOUR == 1)); then + printf 'Tour stopped.\n' + else + printf 'End of tour.\n' + fi +} + +show_intro +visit_programs +show_outro