Programación en Ada/Tareas/Ejemplos
De Wikilibros, la colección de libros de texto de contenido libre.
Contenido |
[editar] Ejemplos completos de tareas
[editar] Semáforos
Una posible implementación del tipo abstracto semáforo es con tareas Ada. Pero este ejemplo no se ha de tomar muy en serio, puesto que es un típico caso de inversión de la abstracción, es decir, se hace uso de un mecanismo de alto nivel, las tareas, para implementar uno de bajo nivel, los semáforos. En Ada 95 la mejor manera de implementar un semáforo es un objeto protegido. Sin embargo a efectos didácticos es un buen ejemplo.
generic ValorInicial: Natural := 1; -- Parám. genérico con valor por defecto. package Semaforos is type TSemaforo is limited private; procedure Wait (Sem: in out TSemaforo); procedure Signal (Sem: in out TSemaforo); private task type TSemaforo is entry Wait; entry Signal; end TSemaforo; end Semaforos;
package body Semaforos is procedure Wait (Sem: in out TSemaforo) is begin Sem.Wait; -- Llamada a punto de entrada de la tarea. end Wait; procedure Signal (Sem: in out TSemaforo) is begin Sem.Signal; -- Llamada a punto de entrada de la tarea. end Signal; task body TSemaforo is S: Natural := ValorInicial; -- Es el contador del semáforo. begin loop select when S > 0 => accept Wait; S := S - 1; or accept Signal; S := S + 1; or terminate; end select; end loop; end TSemaforo; end Semaforos;
with Semaforos; procedure Prueba_Semaforos is package Paquete_Semaforos is new Semaforos; use Paquete_Semaforos; Semaforo: TSemaforo; begin -- Aquí se inicia la tarea de tipo TSemaforo (objeto Semaforo). -- ... Wait (Semaforo); -- ... Signal (Semaforo); -- ... end Prueba_Semaforos;
[editar] Simulación de trenes
Solución propuesta:
with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Float_Random; with Semaforos; procedure Simulador_Trenes is Num_Estaciones : constant := 5; Num_Trenes : constant := 3; type Num_Estación is range 1 .. Num_Estaciones; type Num_Tren is range 1 .. Num_Trenes; package Num_Estación_IO is new Ada.Text_IO.Integer_IO (Num_Estación); use Num_Estación_IO; package Num_Tren_IO is new Ada.Text_IO.Integer_IO (Num_Tren); use Num_Tren_IO; package Semaforos_Inicial_1 is new Semaforos (Valorinicial => 1); use Semaforos_Inicial_1; Semaforos_Estaciones : array (Num_Estación) of TSemaforo; task type Tren is entry Comenzar (Tu_Num : in Num_Tren); end Tren; Lista_Trenes : array (Num_Tren) of Tren; task body Tren is Mi_Num: Num_Tren; procedure Pon_Nombre is begin Put ("Tren nº"); Put (Mi_Num); Put (": "); end Pon_Nombre; Espera_En_Estación: constant Duration := 5.0; Duración_Mínima: constant Duration := 2.0; Factor_Duración: constant Duration := 10.0; Azar_Gen: Ada.Numerics.Float_Random.Generator; Actual, Siguiente: Num_Estación; begin Ada.Numerics.Float_Random.Reset (Azar_Gen); accept Comenzar (Tu_Num : in Num_Tren) do Mi_Num := Tu_Num; end Comenzar; Pon_Nombre; Put_Line ("Comienzo el trayecto"); Actual := 1; loop Pon_Nombre; Put ("En estación "); Put (Actual); New_Line; delay Espera_En_Estación; if Actual = Num_Estaciones then Siguiente := 1; else Siguiente := Actual + 1; end if; Wait (Semaforos_Estaciones (Siguiente)); Pon_Nombre; Put ("Trayecto hacia estación "); Put (Siguiente); New_Line; Signal (Semaforos_Estaciones (Actual)); delay Duration (Ada.Numerics.Float_Random.Random (Azar_Gen)) * Factor_Duración + Duración_Mínima; Actual := Siguiente; end loop; end Tren; begin for I in Lista_Trenes'Range loop Lista_Trenes (I).Comenzar (Tu_Num => I); end loop; end Simulador_Trenes;
[editar] Buffer circular
Otro ejemplo, una posible implementación de un buffer circular:
generic type TElemento is private; Tamaño: Positive := 32; package Buffer_servidor is type TBuffer is limited private; procedure EscribirBuf (B: in out TBuffer; E: TElemento); procedure LeerBuf (B: in out TBuffer; E: out TElemento); private task type TBuffer is entry Escribir (E: TElemento); entry Leer (E: out TElemento); end TBuffer; end Buffer_servidor;
package body Buffer_servidor is task body TBuffer is subtype TCardinalBuffer is Natural range 0 .. Tamaño; subtype TRangoBuffer is TCardinalBuffer range 0 .. Tamaño - 1; Buf: array (TRangoBuffer) of TElemento; Cima, Base: TRangoBuffer := 0; NumElementos: TCardinalBuffer := 0; begin loop select when NumElementos < Tamaño => accept Escribir (E: TElemento) do Buf(Cima) := E; end Escribir; Cima := TRangoBuffer(Integer(Cima + 1) mod Tamaño); NumElementos := NumElementos + 1; or when NumElementos > 0 => accept Leer (E: out TElemento) do E := Buf(Base); end Leer; Base := TRangoBuffer(Integer(Base + 1) mod Tamaño); NumElementos := NumElementos - 1; or terminate; end select; end loop; end TBuffer; procedure EscribirBuf (B: in out TBuffer; E: TElemento) is begin B.Escribir (E); end EscribirBuf; procedure LeerBuf (B: in out TBuffer; E: out TElemento) is begin B.Leer (E); end LeerBuf; end Buffer_servidor;
with Text_IO, Buffer_servidor; use Text_IO; procedure Buffer is Clave_Salida : constant String := "Salir"; type TMensaje is record NumOrden: Positive; Contenido: String (1..20); end record; package Cola_mensajes is new Buffer_servidor (TElemento => TMensaje); use Cola_mensajes; Cola: TBuffer; task Emisor; task Receptor; task body Emisor is M: TMensaje := (NumOrden => 1, Contenido => (others => ' ')); Último: Natural; begin loop Put ("[Emisor] Mensaje: "); Get_Line (M.Contenido, Último); M.Contenido (Último + 1 .. M.Contenido'Last) := (others => ' '); EscribirBuf (Cola, M); M.NumOrden := M.NumOrden + 1; exit when M.Contenido(Clave_Salida'range) = Clave_Salida; end loop; end Emisor; task body Receptor is package Ent_IO is new Text_IO.Integer_IO(Integer); use Ent_IO; M: TMensaje; begin loop LeerBuf (Cola, M); exit when M.Contenido(Clave_Salida'range) = Clave_Salida; Put ("[Receptor] Mensaje número "); Put (M.NumOrden); Put (": "); Put (M.Contenido); New_Line; end loop; end Receptor; begin null; end Buffer;
[editar] Problema del barbero durmiente
Esta es una solución al problema del barbero durmiente.
with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random; procedure Barberia is type Rango_Demora is range 1 .. 30; type Duracion_Afeitado is range 5 .. 10; type Nombre_Cliente is (Jose, Juan, Iñaki, Antonio, Camilo); package Demora_Al_Azar is new Ada.Numerics.Discrete_Random (Rango_Demora); package Afeitado_Al_Azar is new Ada.Numerics.Discrete_Random (Duracion_Afeitado); task Barbero is entry Afeitar (Cliente : in Nombre_Cliente); end Barbero; task type Cliente is entry Comenzar (Nombre : in Nombre_Cliente); end Cliente; Lista_Clientes : array (Nombre_Cliente) of Cliente; task body Barbero is Generador : Afeitado_Al_Azar.Generator; Espera_Máxima_Por_Cliente : constant Duration := 30.0; begin Afeitado_Al_Azar.Reset (Generador); Put_Line ("Barbero: Abro la barbería."); loop Put_Line ("Barbero: Miro si hay cliente."); select accept Afeitar (Cliente : in Nombre_Cliente) do Put_Line ("Barbero: Afeitando a " & Nombre_Cliente'Image (Cliente)); delay Duration (Afeitado_Al_Azar.Random (Generador)); Put_Line ("Barbero: Termino con " & Nombre_Cliente'Image (Cliente)); end Afeitar; or delay Espera_Máxima_Por_Cliente; Put_Line ("Barbero: Parece que ya no viene nadie," & " cierro la barbería."); exit; end select; end loop; end Barbero; task body Cliente is Generador : Demora_Al_Azar.Generator; Mi_Nombre : Nombre_Cliente; begin accept Comenzar (Nombre : in Nombre_Cliente) do Mi_Nombre := Nombre; end Comenzar; Demora_Al_Azar.Reset (Gen => Generador, Initiator => Nombre_Cliente'Pos (Mi_Nombre)); delay Duration (Demora_Al_Azar.Random (Generador)); Put_Line (Nombre_Cliente'Image (Mi_Nombre) & ": Entro en la barbería."); Barbero.Afeitar (Cliente => Mi_Nombre); Put_Line (Nombre_Cliente'Image (Mi_Nombre) & ": Estoy afeitado, me marcho."); end Cliente; begin for I in Lista_Clientes'Range loop Lista_Clientes (I).Comenzar (Nombre => I); end loop; end Barberia;
[editar] Problema de los filósofos cenando
Una solución con tareas y objetos protegidos del conocido problema de los filósofos cenando.
package Cubiertos is
type Cubierto is limited private;
procedure Coger(C: in out Cubierto);
procedure Soltar(C: in out Cubierto);
private
type Status is (LIBRE, OCUPADO);
protected type Cubierto(Estado_Cubierto: Status := LIBRE) is
entry Coger;
entry Soltar;
private
Estado: Status := Estado_Cubierto;
end Cubierto;
end Cubiertos;
package body Cubiertos is
procedure Coger (C: in out Cubierto) is
begin
C.Coger;
end Coger;
procedure Soltar (C: in out Cubierto) is
begin
C.Soltar;
end Soltar;
protected body Cubierto is
entry Coger when Estado = LIBRE is
begin
Estado := OCUPADO;
end Coger;
entry Soltar when Estado = OCUPADO is
begin
Estado := LIBRE;
end Soltar;
end Cubierto;
end Cubiertos;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Cubiertos; use Cubiertos;
procedure Problema_Filosofos is
type PCubierto is access Cubierto;
task type TFilosofo(Id: Character; Cubierto1: PCubierto; Cubierto2: PCubierto);
task body TFilosofo is
procedure Comer is
begin
Coger(Cubierto1.all);
Coger(Cubierto2.all);
for i in 1..10 loop
Put(Id & "c ");
delay 1.0;
end loop;
Soltar(Cubierto2.all);
Soltar(Cubierto1.all);
end Comer;
Procedure Pensar is
begin
for i in 1..10 loop
Put(Id & "p ");
delay 1.0;
end loop;
end Pensar;
begin
loop
Comer;
Pensar;
end loop;
end TFilosofo;
Num_Cubiertos: Positive;
begin
Put("Introduce el numero de cubiertos: "); Get(Num_Cubiertos); New_line;
declare
type PTFilosofo is access TFilosofo;
P: PTFilosofo;
C: Character := 'A';
Cuberteria: array (1..Num_Cubiertos) of PCubierto;
begin
for i in 1..Num_Cubiertos loop
Cuberteria(i) := new Cubierto;
end loop;
for i in 1..Num_Cubiertos-1 loop
P := new TFilosofo(C, Cuberteria(i), Cuberteria(i+1));
C := Character'Succ(C);
end loop;
P := new TFilosofo(C, Cuberteria(1), Cuberteria(Num_Cubiertos));
end;
end Problema_Filosofos;
Para evitar el bloqueo mutuo es totalmente imprescindible que al último filósofo se le asignen los cubiertos en ese orden. Sí se hiciese al contrario, el bloqueo no tardaría en aparecer (sobre todo si se eliminan las instrucciones delay):
P := new TFilosofo(C, Cuberteria(Num_Cubiertos), Cuberteria(1));
[editar] Chinos: una implementación concurrente en Ada
-- Chinos2: Otra implementación concurrente en Ada -- Tomás Javier Robles Prado -- tjavier@usuarios.retecal.es -- Uso: ./chinos <numero_jugadores> -- El juego consiste en jugar sucesivas partidas a los chinos. Si un -- jugador acierta, no paga y queda excluido de las siguientes -- rondas. El último que quede paga los vinos -- Copyright (C) 2003 T. Javier Robles Prado -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA with Ada.Text_IO; use Ada.Text_IO; with Ada.Numerics.Discrete_Random; with Ada.Command_Line; with Ada.Strings.Unbounded; with Ada.Exceptions; procedure Chinos is -- Número Máximo Jugadores que pueden participar (aforo máximo del bar) MAX : constant Natural := 20; -- Posibles mensajes que recibe un jugador tras una partida type Estados is (NO_SIGUES_JUGANDO, SIGUES_JUGANDO, HAS_PERDIDO); -- Subtipo que modela el número de jugadores posibles subtype NumMaxJugadores is Natural range 0..MAX; -- Modela la máxima apuesta que puede darse subtype MAX_APUESTA is Natural range 0..3*MAX; -- Nombres posibles para los jugadores. El 0 se utilizará para -- controlar el caso de que no haya ganador en una partida subtype TNombre is Integer range -1..MAX; -- Paquete para Numeros aleatorios: package Integer_Random is new Ada.Numerics.Discrete_Random(MAX_APUESTA); -- Apuesta de cada Jugador Subtype TApuesta is Integer range -1..3*MAX; -- Mano de cada jugador subtype TMano is Natural range 0..3; -- Ficha de cada jugador que guardara el arbitro type TFicha is record Nombre : TNombre; Apuesta : TApuesta := -1; Mano : TMano; SigueJugando : Boolean; end record; -- Array de Fichas type TTablon is array(1..MAX) of TFicha; -- Se define el tipo jugador task type Jugador; task Arbitro is -- El árbitro controla las partidas y sincroniza a los jugadores entry FijaNumeroJugadores (Num : in NumMaxJugadores); -- Recoge el argumento de la línea de comandos para saber -- cuántos jugadores van a participar entry AsignaNombre (Nombre: out TNombre; NumJug: out NumMaxJugadores); -- Asigna Nombres (de 1 a NumerosJugadores) a los jugadores que -- van a participar. A los que no, les asigna un -1 como -- indicación de que finalicen. entry SiguesJugando (Nombre: in TNombre; JugadorSigueJugando : out Estados; HuboGanador : out boolean); -- Mensaje que envía el árbitro a cada jugador tras una -- partida, comunicándole si ha ganado y deja de jugar, si -- sigue jugando o si ha perdido y tiene que pagar entry EnviaApuesta (Nombre: in TNombre ; Apuesta: in TApuesta); -- El árbitro recibe la apuesta de un jugador entry ConfirmaApuesta (Confirmada : out Boolean); -- Respuesta del árbitro sobre si la apuesta es válida (no la -- ha hecho otro antes) entry ReEnviaApuesta (Apuesta: in TApuesta); -- Si la apuesta no es válida se reenvia hasta que lo sea entry EnviaMano (Nombre: in TNombre ; Mano: in TMano); -- El jugador envía el número de manos que saca al árbitro end Arbitro; task body Arbitro is -- Funciones y Procedimientos function NumeroJugadores return NumMaxJugadores is -- Devuelve el número de jugadores begin return 5; end NumeroJugadores; function EsApuestaValida (Apuesta: in TApuesta; Tablon: in TTablon) return Boolean is -- Devuelve verdadero si la apuesta no ha sido realizada -- antes por algún otro jugador Valida : Boolean := True ; I : TNombre := 1; begin for I in 1..MAX loop if Tablon(I).SigueJugando then if Tablon(I).Apuesta = Apuesta then -- Ya está dicha, la apuesta NO es válida Valida := False ; end if; end if; end loop; return Valida; end EsApuestaValida; function ResultadoGanador (Tablon: in TTablon) return TApuesta is -- Devuelve el número de monedas que sacaron los jugadores Suma : TApuesta := 0 ; begin for I in 1..MAX loop if Tablon(I).SigueJugando then Suma := Suma + Tablon(I).Mano ; end if; end loop; return Suma; end ResultadoGanador; procedure ImprimeGanador (Tablon: in TTablon) is -- Imprimer el nombre del ganador I : TNombre := 1 ; Resultado : TApuesta ; Terminar : Boolean := False; begin Resultado := ResultadoGanador(Tablon); while not Terminar loop if Tablon(I).Apuesta = Resultado and Tablon(I).SigueJugando then Put_Line("Ha Ganado el Jugador " & I'Img); Terminar := True ; else if I = MAX then Put_Line("No ha habido Ganador"); Terminar := True; else I := I + 1; end if; end if; end loop; end ImprimeGanador; function JugadorEliminado (Tablon: in TTablon) return NumMaxJugadores is -- Devuelve el jugador que cuya apuesta sea la correcta Resultado : TApuesta; Ganador : NumMaxJugadores := 0; begin Resultado := ResultadoGanador(Tablon); for I in 1..MAX loop if Tablon(I).SigueJugando then if Resultado = Tablon(I).Apuesta then Ganador := I ; end if; end if; end loop; return Ganador; end JugadorEliminado; procedure ImprimeTablon(Tablon: in TTablon) is -- Imprime las apuestas y monedas de los jugadores begin for I in 1..MAX loop if Tablon(I).SigueJugando then Put_Line("Nombre =" & Tablon(I).Nombre'Img & " | Apuesta =" & Tablon(I).Apuesta'Img & " | Mano =" &Tablon(I).Mano'Img ); end if; end loop; Put_Line ("Resultado ganador: " & ResultadoGanador(Tablon)'Img); end ImprimeTablon; procedure SeparaPartidas (NumPar :in Natural) is -- Un simple separador para aumentar la claridad begin New_Line; Put_Line("******************************************"); Put_Line("Partida número " & NumPar'Img); Put_Line("******************************************"); end SeparaPartidas; -- Variables -- Número de jugadores de la partida N : NumMaxJugadores; Permitidos : NumMaxJugadores; -- Partida Actual PartidaActual : NumMaxJugadores; -- Tablón Tablon : TTablon; NombreActual : NumMaxJugadores; ApuestaValida : Boolean; Ganador : NumMaxJugadores; NumeroPartida : Natural; begin -- Averigua número de jugadores accept FijaNumeroJugadores (Num : in NumMaxJugadores) do N := Num; end FijaNumeroJugadores; -- Nombra solo a aquellos que vayan a jugar, a los que no, los -- nombra como -1 Permitidos := N; for I in 1..MAX loop accept AsignaNombre (Nombre: out TNombre ; NumJug: out NumMaxJugadores) do if Permitidos > 0 then Nombre := I; NumJug := N; Tablon(I).Nombre := I ; Tablon(I).SigueJugando := True; Permitidos := Permitidos - 1; else Nombre := -1; Tablon(I).Nombre := -1; Tablon(I).SigueJugando := False; end if; end AsignaNombre; end loop; NumeroPartida := 1; while N /= 1 loop -- Para separar las diferentes partidas SeparaPartidas(NumeroPartida); -- Recibe las apuestas de cada jugador for I in 1..N loop accept EnviaApuesta (Nombre: in TNombre; Apuesta: in TApuesta) do NombreActual := Nombre; ApuestaValida := EsApuestaValida(Apuesta,Tablon); if ApuestaValida then Tablon(Nombre).Apuesta := Apuesta ; end if; end EnviaApuesta; -- La Apuesta es Válida, se confirma y a otra cosa if ApuestaValida then accept ConfirmaApuesta(Confirmada: out Boolean) do Confirmada := True; end ConfirmaApuesta; else -- La apuesta no es válida. Se comunica esto al jugador para -- que envíe una nueva apuesta accept ConfirmaApuesta(Confirmada: out Boolean) do Confirmada := False; end ConfirmaApuesta; while not ApuestaValida loop -- Aceptará diferentes apuestas hasta q sea válida. accept ReEnviaApuesta (Apuesta: in TApuesta) do if EsApuestaValida(Apuesta,Tablon) then ApuestaValida := True; Tablon(NombreActual).Apuesta := Apuesta ; end if; end ReEnviaApuesta; accept ConfirmaApuesta(Confirmada: out Boolean) do Confirmada := ApuestaValida; end ConfirmaApuesta; end loop; end if; end loop; -- Recibe lo q saca cada jugador for I in 1..N loop accept EnviaMano(Nombre: in TNombre; Mano: in TMano) do Tablon(Nombre).Mano := Mano ; end EnviaMano; end loop; -- ImprimeResultados de la partida ImprimeTablon(Tablon); ImprimeGanador(Tablon); -- Envía a cada jugador su nuevo estado Ganador := JugadorEliminado (Tablon); if Ganador = 0 then -- Nadie acertó for I in 1..N loop accept SiguesJugando (Nombre: in TNombre; JugadorSigueJugando : out Estados; HuboGanador : out boolean) do JugadorSigueJugando := SIGUES_JUGANDO; Tablon(Nombre).SigueJugando := True; HuboGanador := false ; end SiguesJugando; end loop; else -- Hay ganador for I in 1..N loop accept SiguesJugando (Nombre: in TNombre; JugadorSigueJugando : out Estados; HuboGanador : out boolean) do HuboGanador := true; if Nombre = Ganador then JugadorSigueJugando := NO_SIGUES_JUGANDO; Tablon(Nombre).SigueJugando := False; else if N /= 2 then JugadorSigueJugando := SIGUES_JUGANDO; Tablon(Nombre).SigueJugando := True; else JugadorSigueJugando := HAS_PERDIDO; Tablon(Nombre).SigueJugando := False; end if; end if; end SiguesJugando; end loop; end if; NumeroPartida := NumeroPartida + 1; if Ganador /= 0 then N := N - 1; end if; end loop; end Arbitro; task body Jugador is MiNombre : TNombre; NumJug : NumMaxJugadores; Apuesta : TApuesta; ApuestaValidada : Boolean; Mano : Tmano; G : Integer_Random.Generator; YoSigo : Estados; Terminar : Boolean := False; HuboGanador : boolean; begin Arbitro.AsignaNombre(MiNombre, NumJug); -- Si MiNombre es -1, entonces termina su ejecución. Se sigue -- este método para ceñirnos a los jugadores que quiere el -- usuario if MiNombre /= -1 then -- Semillas aleatorias Integer_Random.Reset(G); while not Terminar loop -- Envia Apuesta for I in 1..MiNombre loop Apuesta := Integer_Random.Random(G) mod (NumJug * 3); end loop; Arbitro.EnviaApuesta(MiNombre, Apuesta); -- Proceso de confirmación de apuesta ApuestaValidada := False ; while not ApuestaValidada loop Arbitro.ConfirmaApuesta(ApuestaValidada); if not ApuestaValidada then -- Genera Nueva apuesta for I in 1..MiNombre loop Apuesta := Integer_Random.Random(G) mod (NumJug * 3) ; end loop; Arbitro.ReEnviaApuesta(Apuesta); end if; end loop; -- Envía Mano for I in 1..MiNombre loop Mano := Integer_Random.Random(G) mod 4; end loop; Arbitro.EnviaMano(MiNombre, Mano); -- Comprueba su estado, si sigue jugando, si ha perdido o -- si ha ganado y deja de jugar Arbitro.SiguesJugando(MiNombre, YoSigo, HuboGanador); if YoSigo = SIGUES_JUGANDO then Terminar := False; else if YoSigo = NO_SIGUES_JUGANDO then Terminar := True; else -- Ha perdido Put_Line("Jugador " & MiNombre'Img & ": He perdido, tengo que pagar :_("); end if; end if; if HuboGanador then NumJug := NumJug - 1; end if; end loop; end if; end Jugador; Jugadores : array (1..MAX) of Jugador; NumJug : Natural; begin if Ada.Command_Line.Argument_Count /= 1 then -- Número incorrecto de parámetros Put_Line("Uso: ./chinos <num_jugadores>"); NumJug := 1; else NumJug := Integer'Value(Ada.Command_Line.Argument(1)); if NumJug < 2 then -- Número mínimo de jugadores Put_Line("El número de jugadores ha de ser mayor que 1." & NumJug'Img & " no es mayor que 1"); Put_Line("Seleccione un valor mayor o igual que 2"); NumJug := 1; end if; if NumJug > MAX then -- Número máximo de jugadores Put_Line(NumJug'Img & " es mayor que " & MAX'Img); Put_Line("Seleccione un valor menor o igual que " & MAX'Img); NumJug := 1; end if; end if; Arbitro.FijaNumeroJugadores(NumJug); -- Por si nos intentan colar algún valor no válido exception when Constraint_Error => NumJug := 1; Arbitro.FijaNumeroJugadores(NumJug); Put_Line("El Valor Introducido no es correcto."); Put_Line("Uso: ./chinos <num_jugadores>"); end Chinos;