feat(sandbox): add carre program
This commit is contained in:
parent
ccd3dfef7b
commit
dea9bd52ee
177
PLAN.md
Normal file
177
PLAN.md
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
# Programme `carre` Plan
|
||||||
|
|
||||||
|
## Objectif
|
||||||
|
|
||||||
|
Ajouter un nouveau programme ComputerCraft nommé `carre` qui dessine des carres dans le terminal.
|
||||||
|
|
||||||
|
Le programme doit etre utile pour un test simple, mais assez amusant pour explorer plusieurs rendus: carre fixe, carre plein, carre aleatoire, et repetition de carres.
|
||||||
|
|
||||||
|
Le code doit aussi pouvoir servir d'exemple pedagogique pour debutants Lua. L'implementation pourra donc contenir quelques commentaires en francais, courts et utiles, pour expliquer les etapes importantes sans noyer le programme.
|
||||||
|
|
||||||
|
## Emplacement
|
||||||
|
|
||||||
|
- Programme: `programs/carre.lua`
|
||||||
|
- Tests: `tests/programs/carre_test.lua` ou `tests/carre_test.lua`, selon les conventions existantes au moment de l'implementation
|
||||||
|
- Package: nouveau package separe `trapos-sandbox`, afin de tester `ccpm` sans inclure `carre` directement dans `trapos`
|
||||||
|
|
||||||
|
## Interface Proposee
|
||||||
|
|
||||||
|
Commande de base:
|
||||||
|
|
||||||
|
```text
|
||||||
|
carre [options]
|
||||||
|
```
|
||||||
|
|
||||||
|
Options:
|
||||||
|
|
||||||
|
- `-size <n>`: taille du carre, par defaut `8`
|
||||||
|
- `-x <n>`: colonne de depart, par defaut centree si possible
|
||||||
|
- `-y <n>`: ligne de depart, par defaut centree si possible
|
||||||
|
- `-char <c>`: caractere utilise pour dessiner, par defaut `#`
|
||||||
|
- `-fill`: dessine un carre plein au lieu d'un contour
|
||||||
|
- `-random`: choisit une taille, une position et un caractere aleatoires simples compatibles avec le terminal
|
||||||
|
- `-count <n>`: dessine plusieurs carres, utile avec `-random`, par defaut `1`
|
||||||
|
- `-delay <s>`: pause entre deux carres quand `-count` est superieur a `1`, par defaut `0`
|
||||||
|
- `-clear`: efface l'ecran avant de dessiner
|
||||||
|
- `-help` / `--help`: affiche l'aide
|
||||||
|
- `-version` / `--version`: affiche la version du package via `/apis/libversion`
|
||||||
|
|
||||||
|
Exemples:
|
||||||
|
|
||||||
|
```text
|
||||||
|
carre
|
||||||
|
carre -size 12 -char * -clear
|
||||||
|
carre -size 6 -fill -x 4 -y 3
|
||||||
|
carre -random
|
||||||
|
carre -random -count 5 -delay 0.2 -clear
|
||||||
|
```
|
||||||
|
|
||||||
|
## Comportement Attendu
|
||||||
|
|
||||||
|
- Le programme dessine dans le terminal courant avec `term.setCursorPos()` et `write()`.
|
||||||
|
- Si `-clear` est donne, il appelle `term.clear()` avant le dessin.
|
||||||
|
- Sans `-x` ou `-y`, le carre est centre dans la zone disponible quand la taille du terminal le permet.
|
||||||
|
- Les coordonnees et tailles sont bornees pour eviter les erreurs ou les dessins hors ecran.
|
||||||
|
- `-size 1` dessine un seul caractere.
|
||||||
|
- `-size 2` dessine un carre minimal valide.
|
||||||
|
- Si `-fill` est absent, seul le contour est dessine.
|
||||||
|
- Si `-fill` est present, toute la surface est remplie.
|
||||||
|
- Si `-random` est present, les options explicites doivent rester prioritaires quand c'est raisonnable: par exemple `carre -random -char @` garde `@` mais randomise taille/position.
|
||||||
|
- Si `-count` est superieur a `1`, chaque carre est dessine successivement sur le meme ecran par defaut. Avec `-clear`, l'ecran est efface avant chaque carre pour produire une petite animation.
|
||||||
|
- Les couleurs ne sont pas prioritaires pour la premiere version: l'objectif est de garder un programme lisible pour debutants.
|
||||||
|
|
||||||
|
## Regles De Validation Des Arguments
|
||||||
|
|
||||||
|
- `-size` doit etre un entier positif.
|
||||||
|
- `-x` et `-y` doivent etre des entiers positifs.
|
||||||
|
- `-count` doit etre un entier positif.
|
||||||
|
- `-delay` doit etre un nombre positif ou nul.
|
||||||
|
- `-char` prend le premier caractere non vide fourni.
|
||||||
|
- Option inconnue: afficher une erreur courte puis suggerer `carre -help`.
|
||||||
|
- Argument invalide: afficher une erreur courte puis quitter sans stack trace.
|
||||||
|
|
||||||
|
## Idee D'Implementation
|
||||||
|
|
||||||
|
Structure minimale dans `programs/carre.lua`:
|
||||||
|
|
||||||
|
1. Charger `/apis/libversion` pour `--version`.
|
||||||
|
2. Definir `printUsage()`.
|
||||||
|
3. Parser `...` avec une boucle simple sur `args`.
|
||||||
|
4. Recuperer `term.getSize()`.
|
||||||
|
5. Calculer une configuration finale de dessin.
|
||||||
|
6. Dessiner avec une fonction locale `drawSquare(x, y, size, char, fill)`.
|
||||||
|
7. Repeter selon `count`, avec `sleep(delay)` si necessaire.
|
||||||
|
|
||||||
|
Commentaires a privilegier dans le code:
|
||||||
|
|
||||||
|
- Expliquer pourquoi on lit `...` pour recuperer les arguments du programme.
|
||||||
|
- Expliquer le calcul de centrage.
|
||||||
|
- Expliquer la difference entre contour et remplissage.
|
||||||
|
- Expliquer que le mode aleatoire borne les valeurs pour rester visible dans le terminal.
|
||||||
|
|
||||||
|
Commentaires a eviter:
|
||||||
|
|
||||||
|
- Commentaires qui repetent exactement le code, par exemple `-- ajoute 1 a x`.
|
||||||
|
- Gros blocs de theorie Lua qui rendraient le programme moins lisible.
|
||||||
|
|
||||||
|
Pseudo-rendu contour:
|
||||||
|
|
||||||
|
```text
|
||||||
|
########
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
# #
|
||||||
|
########
|
||||||
|
```
|
||||||
|
|
||||||
|
Pseudo-rendu plein:
|
||||||
|
|
||||||
|
```text
|
||||||
|
########
|
||||||
|
########
|
||||||
|
########
|
||||||
|
########
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tests Proposes
|
||||||
|
|
||||||
|
Ajouter des tests CraftOS-PC avec `/apis/libtest.lua` pour les parties deterministes:
|
||||||
|
|
||||||
|
- Parse des options de base.
|
||||||
|
- Rejet des valeurs invalides.
|
||||||
|
- Calcul de centrage avec une taille de terminal simulee.
|
||||||
|
- Calcul de bornage quand le carre depasse la zone disponible.
|
||||||
|
- Rendu contour dans une surface terminal simulee.
|
||||||
|
- Rendu plein dans une surface terminal simulee.
|
||||||
|
- Mode random teste avec une source aleatoire injectable ou avec des invariants seulement: taille positive, position visible, pas d'erreur.
|
||||||
|
|
||||||
|
Pour rendre le programme testable sans gros refactor, l'implementation peut garder les fonctions pures dans le fichier et n'executer `main(...)` qu'a la fin. Si les conventions du depot preferent tester seulement les programmes via execution CraftOS-PC, adapter les tests en consequence.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Apres implementation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
just check
|
||||||
|
just trapos --headless --exec 'shell.run("/programs/carre", "-size", "5", "-clear"); os.shutdown()'
|
||||||
|
just trapos --headless --exec 'shell.run("/programs/carre", "-random", "-count", "3", "-delay", "0"); os.shutdown()'
|
||||||
|
```
|
||||||
|
|
||||||
|
Si des tests sont ajoutes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
just trapos --headless --exec 'shell.run("/programs/runtest", "/tests/carre_test.lua"); os.shutdown()'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Packaging
|
||||||
|
|
||||||
|
- Creer le nouveau package `packages/trapos-sandbox/ccpm.json`.
|
||||||
|
- Ne pas ajouter `carre` au package principal `trapos`.
|
||||||
|
- Ajouter `programs/carre.lua` dans les fichiers du package `trapos-sandbox`.
|
||||||
|
- Bumper la version du package `trapos-sandbox` quand le comportement change.
|
||||||
|
- Reporter la meme version dans `packages/index.json`.
|
||||||
|
- Verifier que `carre --version` retourne bien la version attendue.
|
||||||
|
|
||||||
|
## Decisions Validees
|
||||||
|
|
||||||
|
- `carre` doit etre dans un nouveau package separe, pas dans `trapos`, pour faciliter les tests de `ccpm`.
|
||||||
|
- Le package s'appelle `trapos-sandbox`.
|
||||||
|
- Le programme s'appelle `carre.lua`, sans accent.
|
||||||
|
- Les commentaires en francais sont souhaites pour rendre le code utile a des debutants.
|
||||||
|
- Les couleurs sont repoussees: le programme doit rester simple et pedagogique pour la premiere version.
|
||||||
|
|
||||||
|
## Questions Restantes
|
||||||
|
|
||||||
|
- `carre -random -count N` doit-il garder tous les carres visibles par defaut, ou faut-il finalement effacer entre chaque dessin meme sans `-clear`?
|
||||||
|
|
||||||
|
## Hors Scope Pour La Premiere Version
|
||||||
|
|
||||||
|
- Dessin de rectangles non carres.
|
||||||
|
- Animation avancee avec rebonds.
|
||||||
|
- Interface interactive au clavier.
|
||||||
|
- Sauvegarde du dessin dans un fichier.
|
||||||
|
- Support multi-caracteres pour les bordures.
|
||||||
|
- Couleurs de texte ou de fond.
|
||||||
171
apis/libcarre.lua
Normal file
171
apis/libcarre.lua
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
local DEFAULT_SIZE = 8;
|
||||||
|
local DEFAULT_CHAR = '#';
|
||||||
|
local RANDOM_CHARS = { '#', '*', '+', 'x', '@', '=' };
|
||||||
|
|
||||||
|
local function firstChar(value)
|
||||||
|
value = tostring(value or '');
|
||||||
|
if value == '' then return nil; end
|
||||||
|
return string.sub(value, 1, 1);
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parsePositiveInteger(value, name)
|
||||||
|
local number = tonumber(value);
|
||||||
|
if not number or number < 1 or number ~= math.floor(number) then
|
||||||
|
return nil, name .. ' doit etre un entier positif';
|
||||||
|
end
|
||||||
|
return number;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parseNonNegativeNumber(value, name)
|
||||||
|
local number = tonumber(value);
|
||||||
|
if not number or number < 0 then
|
||||||
|
return nil, name .. ' doit etre un nombre positif ou nul';
|
||||||
|
end
|
||||||
|
return number;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clamp(value, minValue, maxValue)
|
||||||
|
if value < minValue then return minValue; end
|
||||||
|
if value > maxValue then return maxValue; end
|
||||||
|
return value;
|
||||||
|
end
|
||||||
|
|
||||||
|
local function createCarre(opts)
|
||||||
|
opts = opts or {};
|
||||||
|
local random = opts.random or math.random;
|
||||||
|
|
||||||
|
local api = {};
|
||||||
|
|
||||||
|
function api.parseArgs(args)
|
||||||
|
args = args or {};
|
||||||
|
local config = {
|
||||||
|
size = DEFAULT_SIZE,
|
||||||
|
char = DEFAULT_CHAR,
|
||||||
|
fill = false,
|
||||||
|
random = false,
|
||||||
|
count = 1,
|
||||||
|
delay = 0,
|
||||||
|
clear = false,
|
||||||
|
explicit = {},
|
||||||
|
};
|
||||||
|
|
||||||
|
local i = 1;
|
||||||
|
while i <= (args.n or #args) do
|
||||||
|
local arg = args[i];
|
||||||
|
|
||||||
|
if arg == '-size' then
|
||||||
|
local value, err = parsePositiveInteger(args[i + 1], '-size');
|
||||||
|
if not value then return nil, err; end
|
||||||
|
config.size = value;
|
||||||
|
config.explicit.size = true;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-x' then
|
||||||
|
local value, err = parsePositiveInteger(args[i + 1], '-x');
|
||||||
|
if not value then return nil, err; end
|
||||||
|
config.x = value;
|
||||||
|
config.explicit.x = true;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-y' then
|
||||||
|
local value, err = parsePositiveInteger(args[i + 1], '-y');
|
||||||
|
if not value then return nil, err; end
|
||||||
|
config.y = value;
|
||||||
|
config.explicit.y = true;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-char' then
|
||||||
|
local value = firstChar(args[i + 1]);
|
||||||
|
if not value then return nil, '-char doit recevoir un caractere'; end
|
||||||
|
config.char = value;
|
||||||
|
config.explicit.char = true;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-fill' then
|
||||||
|
config.fill = true;
|
||||||
|
elseif arg == '-random' then
|
||||||
|
config.random = true;
|
||||||
|
elseif arg == '-count' then
|
||||||
|
local value, err = parsePositiveInteger(args[i + 1], '-count');
|
||||||
|
if not value then return nil, err; end
|
||||||
|
config.count = value;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-delay' then
|
||||||
|
local value, err = parseNonNegativeNumber(args[i + 1], '-delay');
|
||||||
|
if not value then return nil, err; end
|
||||||
|
config.delay = value;
|
||||||
|
i = i + 1;
|
||||||
|
elseif arg == '-clear' then
|
||||||
|
config.clear = true;
|
||||||
|
else
|
||||||
|
return nil, 'option inconnue: ' .. tostring(arg);
|
||||||
|
end
|
||||||
|
|
||||||
|
i = i + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
return config;
|
||||||
|
end
|
||||||
|
|
||||||
|
function api.computeSquare(config, width, height)
|
||||||
|
width = math.max(1, tonumber(width) or 1);
|
||||||
|
height = math.max(1, tonumber(height) or 1);
|
||||||
|
config = config or {};
|
||||||
|
|
||||||
|
local explicit = config.explicit or {};
|
||||||
|
local maxSize = math.max(1, math.min(width, height));
|
||||||
|
local size = config.size or DEFAULT_SIZE;
|
||||||
|
local char = config.char or DEFAULT_CHAR;
|
||||||
|
|
||||||
|
if config.random then
|
||||||
|
if not explicit.size then
|
||||||
|
size = random(1, maxSize);
|
||||||
|
end
|
||||||
|
if not explicit.char then
|
||||||
|
char = RANDOM_CHARS[random(1, #RANDOM_CHARS)];
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
size = clamp(size, 1, maxSize);
|
||||||
|
|
||||||
|
local maxX = math.max(1, width - size + 1);
|
||||||
|
local maxY = math.max(1, height - size + 1);
|
||||||
|
local x = config.x;
|
||||||
|
local y = config.y;
|
||||||
|
|
||||||
|
if config.random and not explicit.x then
|
||||||
|
x = random(1, maxX);
|
||||||
|
elseif not x then
|
||||||
|
x = math.floor((width - size) / 2) + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
if config.random and not explicit.y then
|
||||||
|
y = random(1, maxY);
|
||||||
|
elseif not y then
|
||||||
|
y = math.floor((height - size) / 2) + 1;
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
x = clamp(x, 1, maxX),
|
||||||
|
y = clamp(y, 1, maxY),
|
||||||
|
size = size,
|
||||||
|
char = firstChar(char) or DEFAULT_CHAR,
|
||||||
|
fill = config.fill == true,
|
||||||
|
};
|
||||||
|
end
|
||||||
|
|
||||||
|
function api.drawSquare(termLib, square)
|
||||||
|
for row = 1, square.size do
|
||||||
|
termLib.setCursorPos(square.x, square.y + row - 1);
|
||||||
|
|
||||||
|
for column = 1, square.size do
|
||||||
|
local isBorder = row == 1 or row == square.size or column == 1 or column == square.size;
|
||||||
|
if square.fill or isBorder then
|
||||||
|
termLib.write(square.char);
|
||||||
|
else
|
||||||
|
termLib.write(' ');
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return api;
|
||||||
|
end
|
||||||
|
|
||||||
|
return createCarre;
|
||||||
@ -6,6 +6,7 @@
|
|||||||
"trapos-net": "0.2.1",
|
"trapos-net": "0.2.1",
|
||||||
"trapos-ui": "0.2.2",
|
"trapos-ui": "0.2.2",
|
||||||
"trapos-ai": "0.5.1",
|
"trapos-ai": "0.5.1",
|
||||||
|
"trapos-sandbox": "0.1.0",
|
||||||
"trapos": "0.6.2"
|
"trapos": "0.6.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
11
packages/trapos-sandbox/ccpm.json
Normal file
11
packages/trapos-sandbox/ccpm.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "trapos-sandbox",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "TrapOS sandbox programs for ccpm experiments and Lua learning",
|
||||||
|
"dependencies": ["trapos-core"],
|
||||||
|
"files": [
|
||||||
|
"apis/libcarre.lua",
|
||||||
|
"programs/carre.lua"
|
||||||
|
],
|
||||||
|
"autostart": []
|
||||||
|
}
|
||||||
62
programs/carre.lua
Normal file
62
programs/carre.lua
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
local createCarre = require('/apis/libcarre');
|
||||||
|
local createVersion = require('/apis/libversion');
|
||||||
|
|
||||||
|
-- Les arguments du programme sont disponibles dans `...`.
|
||||||
|
-- `table.pack` permet de les garder dans une table facile a parcourir.
|
||||||
|
local args = table.pack(...);
|
||||||
|
|
||||||
|
local function printUsage()
|
||||||
|
print('carre usage:');
|
||||||
|
print();
|
||||||
|
print(' carre');
|
||||||
|
print(' carre -size <n> [-x <n>] [-y <n>] [-char <c>] [-fill] [-clear]');
|
||||||
|
print(' carre -random [-count <n>] [-delay <s>] [-clear]');
|
||||||
|
print(' carre --version');
|
||||||
|
print(' carre --help');
|
||||||
|
print();
|
||||||
|
print('exemples:');
|
||||||
|
print(' carre -size 10 -char * -clear');
|
||||||
|
print(' carre -size 6 -fill -x 4 -y 3');
|
||||||
|
print(' carre -random -count 5 -delay 0.2');
|
||||||
|
end
|
||||||
|
|
||||||
|
local command = args[1];
|
||||||
|
|
||||||
|
if command == '-help' or command == '--help' or command == 'help' then
|
||||||
|
printUsage();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
if command == '-version' or command == '--version' or command == 'version' then
|
||||||
|
print('v' .. createVersion().forSelf());
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local carre = createCarre();
|
||||||
|
local config, err = carre.parseArgs(args);
|
||||||
|
if not config then
|
||||||
|
print(err);
|
||||||
|
print('utilise: carre -help');
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local width, height = term.getSize();
|
||||||
|
|
||||||
|
for index = 1, config.count do
|
||||||
|
if config.clear then
|
||||||
|
term.clear();
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Le calcul choisit une position visible. Si rien n'est donne,
|
||||||
|
-- le carre est centre dans le terminal.
|
||||||
|
local square = carre.computeSquare(config, width, height);
|
||||||
|
|
||||||
|
-- Le mode contour ecrit seulement les bords. Le mode plein ecrit partout.
|
||||||
|
carre.drawSquare(term.current(), square);
|
||||||
|
|
||||||
|
if config.delay > 0 and index < config.count then
|
||||||
|
sleep(config.delay);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setCursorPos(1, height);
|
||||||
122
tests/carre.lua
Normal file
122
tests/carre.lua
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
local createLibTest = require('/apis/libtest');
|
||||||
|
local createCarre = require('/apis/libcarre');
|
||||||
|
|
||||||
|
local testlib = createLibTest({ ... });
|
||||||
|
|
||||||
|
local function packed(...)
|
||||||
|
return table.pack(...);
|
||||||
|
end
|
||||||
|
|
||||||
|
local function fakeTerm(width, height)
|
||||||
|
local buffer = {};
|
||||||
|
local cursorX = 1;
|
||||||
|
local cursorY = 1;
|
||||||
|
|
||||||
|
for y = 1, height do
|
||||||
|
buffer[y] = {};
|
||||||
|
for x = 1, width do
|
||||||
|
buffer[y][x] = '.';
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
setCursorPos = function(x, y)
|
||||||
|
cursorX = x;
|
||||||
|
cursorY = y;
|
||||||
|
end,
|
||||||
|
write = function(text)
|
||||||
|
text = tostring(text);
|
||||||
|
for i = 1, #text do
|
||||||
|
if buffer[cursorY] and buffer[cursorY][cursorX] then
|
||||||
|
buffer[cursorY][cursorX] = string.sub(text, i, i);
|
||||||
|
end
|
||||||
|
cursorX = cursorX + 1;
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
line = function(y)
|
||||||
|
return table.concat(buffer[y], '');
|
||||||
|
end,
|
||||||
|
};
|
||||||
|
end
|
||||||
|
|
||||||
|
testlib.test('parseArgs accepts basic drawing options', function()
|
||||||
|
local carre = createCarre();
|
||||||
|
local config = carre.parseArgs(packed('-size', '5', '-x', '2', '-y', '3', '-char', '@', '-fill', '-clear'));
|
||||||
|
|
||||||
|
testlib.assertEquals(config.size, 5);
|
||||||
|
testlib.assertEquals(config.x, 2);
|
||||||
|
testlib.assertEquals(config.y, 3);
|
||||||
|
testlib.assertEquals(config.char, '@');
|
||||||
|
testlib.assertEquals(config.fill, true);
|
||||||
|
testlib.assertEquals(config.clear, true);
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.test('parseArgs rejects invalid sizes', function()
|
||||||
|
local carre = createCarre();
|
||||||
|
local config, err = carre.parseArgs(packed('-size', '0'));
|
||||||
|
|
||||||
|
testlib.assertEquals(config, nil);
|
||||||
|
testlib.assertTrue(string.find(err, 'entier positif', 1, true));
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.test('computeSquare centers and clamps the square', function()
|
||||||
|
local carre = createCarre();
|
||||||
|
local square = carre.computeSquare({ size = 4, char = '#', fill = false }, 10, 6);
|
||||||
|
|
||||||
|
testlib.assertEquals(square.x, 4);
|
||||||
|
testlib.assertEquals(square.y, 2);
|
||||||
|
testlib.assertEquals(square.size, 4);
|
||||||
|
|
||||||
|
square = carre.computeSquare({ size = 20, x = 99, y = 99, char = '#' }, 7, 5);
|
||||||
|
testlib.assertEquals(square.x, 3);
|
||||||
|
testlib.assertEquals(square.y, 1);
|
||||||
|
testlib.assertEquals(square.size, 5);
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.test('computeSquare random keeps explicit character', function()
|
||||||
|
local values = { 3, 2, 4 };
|
||||||
|
local index = 0;
|
||||||
|
local carre = createCarre({
|
||||||
|
random = function(minValue, maxValue)
|
||||||
|
index = index + 1;
|
||||||
|
return math.max(minValue, math.min(maxValue, values[index]));
|
||||||
|
end,
|
||||||
|
});
|
||||||
|
|
||||||
|
local square = carre.computeSquare({
|
||||||
|
random = true,
|
||||||
|
char = '@',
|
||||||
|
explicit = { char = true },
|
||||||
|
}, 10, 8);
|
||||||
|
|
||||||
|
testlib.assertEquals(square.size, 3);
|
||||||
|
testlib.assertEquals(square.x, 2);
|
||||||
|
testlib.assertEquals(square.y, 4);
|
||||||
|
testlib.assertEquals(square.char, '@');
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.test('drawSquare renders an outline', function()
|
||||||
|
local carre = createCarre();
|
||||||
|
local termLib = fakeTerm(8, 6);
|
||||||
|
|
||||||
|
carre.drawSquare(termLib, { x = 2, y = 2, size = 4, char = '#', fill = false });
|
||||||
|
|
||||||
|
testlib.assertEquals(termLib.line(1), '........');
|
||||||
|
testlib.assertEquals(termLib.line(2), '.####...');
|
||||||
|
testlib.assertEquals(termLib.line(3), '.# #...');
|
||||||
|
testlib.assertEquals(termLib.line(4), '.# #...');
|
||||||
|
testlib.assertEquals(termLib.line(5), '.####...');
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.test('drawSquare renders a filled square', function()
|
||||||
|
local carre = createCarre();
|
||||||
|
local termLib = fakeTerm(6, 5);
|
||||||
|
|
||||||
|
carre.drawSquare(termLib, { x = 2, y = 2, size = 3, char = '*', fill = true });
|
||||||
|
|
||||||
|
testlib.assertEquals(termLib.line(2), '.***..');
|
||||||
|
testlib.assertEquals(termLib.line(3), '.***..');
|
||||||
|
testlib.assertEquals(termLib.line(4), '.***..');
|
||||||
|
end);
|
||||||
|
|
||||||
|
testlib.run();
|
||||||
Loading…
Reference in New Issue
Block a user