cours_ada/semestre3/Kaprekar/main.adb
2021-08-22 13:24:45 +02:00

204 lines
5.4 KiB
Ada

with ada.Text_IO, Ada.Integer_Text_IO;
with ada.Calendar;
use ada.Text_IO;
procedure Main is
-- Type & package
subtype chiffre is Natural range 0..9;
type nbr is array (Integer range <>) of Integer;
package date renames ada.Calendar;
-- Variables globales
FND : constant Integer := 100; -- FIND
WST : constant Integer := FND - 1; -- WRITE START
data_dect : nbr(1..FND);
-- Ce tableau contient des nombres pour de la detection de boucle
-- Le rang WST et FND sont des rangs de services
-- Procédure de detection de boucle, utilise la base de données data_dect
procedure detect_loop (int : in Integer) is
debut_ecriture : Integer := data_dect(WST);
begin
for i in data_dect'First..(WST - 1) loop
if int = data_dect(i) then
data_dect(FND) := 1;
end if;
end loop;
data_dect(debut_ecriture) := int;
data_dect(WST) := data_dect(WST) + 1;
if data_dect(WST) >= WST then
raise Storage_Error;
end if;
end detect_loop;
-- Tri par ordre croissant un tableau d'integer
procedure tri (tab : in out nbr) is
buffer : nbr(tab'Range);
valeur : Integer := 0;
pos : Integer := 0;
begin
for k in tab'Range loop
valeur := 0;
pos := tab'last;
for i in tab'range loop
if tab(i) >= valeur then
pos := i;
valeur := tab(i);
end if;
end loop;
tab(pos):=0;
buffer(k) := valeur;
end loop;
tab := buffer;
end tri;
-- Tri par ordre décroissant
procedure tri_inverse (tab : in out nbr) is
buffer : nbr(tab'Range);
begin
tri(tab);
for i in tab'range loop
buffer(i):=tab(tab'last-(i-1));
end loop;
tab:=buffer;
end tri_inverse;
-- Partie opérative de l'algo de Kaprekar (nombre en deux tableaux triés, affiche et retourne la différence des nombres
function operation (nombre : integer; dimension : Integer) return Integer is
ord_croiss : nbr(1..dimension);
ord_droiss : nbr(1..dimension);
nombre_croiss : Integer := 0;
nombre_droiss : Integer := 0;
nombre_stock : Integer := nombre;
begin
-- On met le nombre dans un tableau
for k in 1..dimension loop
ord_croiss(k) := (nombre_stock/10**(dimension-(k)));
nombre_stock := nombre_stock - ord_croiss(k)*10**(dimension-k);
end loop;
--tri
ord_droiss := ord_croiss;
tri(ord_croiss);
tri_inverse(ord_droiss);
for j in 1..dimension loop
nombre_droiss := nombre_droiss + ord_droiss(j) * (10**(dimension - (j)));
nombre_croiss := nombre_croiss + ord_croiss(j) * 10**(dimension -(j));
end loop;
Put_Line("N1 = " & Integer'Image(nombre_croiss) & " N2 = " & Integer'Image(nombre_droiss) & " N1 - N2 = " & Integer'Image(nombre_croiss - nombre_droiss));
return nombre_croiss - nombre_droiss;
end operation;
-- Permet de déterminer la taille d'un nombre
function nb_digits (nombre : Integer) return Integer is
dimension_nok : Boolean := true;
dimension : Integer := 0;
i : Integer := 0;
begin
while dimension_nok loop
if (nombre / 10**i) <= 0 then
dimension_nok := false;
dimension := i;
else
i := i + 1;
end if;
end loop;
if dimension = 0 then
dimension := 1;
end if;
return dimension;
end nb_digits;
-- Procédure de coordination des fonctions de l'algorithme et de la detection de boucle
procedure kaprekar (nombre : in out Integer) is
dimension_nok : Boolean := true;
dimension : Integer := 0;
i : Integer := 0;
temp : Integer := nombre;
begin
nombre := temp + 1;
while nombre /=temp loop
dimension := nb_digits(temp);
nombre := temp;
temp := operation(temp, dimension);
detect_loop(temp);
if data_dect(FND) = 1 then
Put_Line("Boucle dans l'algorithme");
nombre := temp;
end if;
delay 0.2;
Put_Line("--------------");
end loop;
end kaprekar;
-- Procédure de test de la fonction tri
-- cf ../../Test_tri pour d'autres algorithmes de tri
procedure test_tri is
test_tri1 : nbr(1..10) := (5,4,8,3,9,1,6,7,2,0);
test_tri2 : nbr(1..10) := (5,4,8,6,9,1,6,7,7,0);
begin
tri(test_tri2);
tri_inverse(test_tri1);
for i in test_tri1'First..test_tri1'Last loop
put(Integer'Image(test_tri1(i))& " ");
end loop;
Put_Line("");
for i in test_tri2'First..test_tri2'Last loop
put(Integer'Image(test_tri2(i))& " ");
end loop;
Put_Line("");
end test_tri;
nombre: Integer := 0;
begin
-- Detection de boucle:
data_dect(WST) := 1; --le premier rang écrit par défaut est le 1
data_dect(FND) := 0; --aucune boucle n'est trouvé au début
--Put_Line("Test du programme :");
--test_tri;
--
Put("Algorithme de Kaprekar. Saisir un nombre : ");
Ada.Integer_Text_IO.Get(nombre);
kaprekar(nombre);
Put_Line("ALGORITHME FINI");
-- Exceptions
exception
when Constraint_Error => Put_Line("Nombre donné non valide.");
when Storage_Error => Put_Line("DATA_BASE_TOO_SHORT, data_dect(WST):"&Integer'Image(data_dect(WST)));
when others => Put_line("Nombre non valide ou trop grand !");
end Main;