Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.


Mensajes - Kabuto

Páginas: 1 ... 32 33 34 35 36 [37] 38 39 40 41 42 ... 50
721
Comunidad / Re:Soy nuevo
« en: 16 de Abril 2020, 10:59 »
Bienvenido.

Se nota que en cuarentena la gente busca nuevos hobbies y entretenimientos, pues estos días ha llegado bastante gente nueva.

En la web tienes varios cursos a tu disposición para iniciarte en programación o diseño web, o en ambos..

Sácales provecho ahora que tienes tiempo.

Un saludo.

722
Aprender a programar desde cero / Re:Sistema de "regreso"
« en: 15 de Abril 2020, 23:33 »
Ambas formas, while() y do..while(), te van a servir.

Sí, do..while() te garantiza que al menos una vez se va a ejecutar el bucle, porque la condición se evalúa al final, después de ejecutar el bloque de código que contiene.
En cambio, el while() evalúa al principio y podría ocurrir que no se ejecute ni una sola vez.

Para un programa donde, sí o sí, queremos mostrar un menú de opciones al comienzo, sí parece más adecuado usar el do..while()

Para un programa distinto, donde queremos que el bloque de código se ejecute solo si se cumple cierta condición, mejor el while() sin duda.

Pero vamos, que un while(), si justo antes del bucle inicializas la variable que vas a usar como condición con valor true, también tienes garantizada al menos una ejecución del bucle.

Así que elegir uno u otro va a depender de cada caso, de si alguno te va a suponer ahorrar aunque sea una línea de código, o de simple gusto personal del programador.


Yo a veces elijo while() por encima del do..while() simplemente porque quiero que, quién vaya a leer mi código, lo primero que vea sea cuál es la condición (o condiciones) que se han de cumplir para que el bucle se repita.
Porque así facilito que quién lea mi código entienda mejor lo que se está haciendo.

Esto me ocurre a menudo. Si es un código para mí, lo escribo de cierta forma, donde prima la concisión y el ahorro de código.

Si es algo que tengo pensado compartir o es para alguien que ha pedido ayuda en un foro como este, entonces lo escribo de otra forma, donde prima la legibilidad y que sea fácil de entender.

Al compilador de Java le da igual una forma u otra    ;D

723
Aprender a programar desde cero / Re:Sistema de "regreso"
« en: 15 de Abril 2020, 11:13 »
Hola.
Sí, esa sería la lógica a seguir:

Usar una variable boolean con valor true para mantener "vivo" el bucle hasta que el usuario elija la opción de salir. Entonces será cuando esa variable cambie a valor false y el bucle finalizará

724
Comunidad / Re:Hola desde Mallorca
« en: 15 de Abril 2020, 00:09 »
Bienvenido.

Hay mucha gente que aprende HTML y/o programación por puro y simple pasatiempo.

Y es maravilloso. La programación no tiene porque ser simplemente una salida laboral, es un excelente entretenimiento además de que potencia la creatividad y ejercita la mente mogollón.

Seguro que lo disfrutas.
Un saludo.

725
Por cierto.
Estaba pensando que para el proceso de búsqueda, se podría reducir mucho código si las estaciones estuvieran en una matriz, y no en arrays separados.

Pero claro, no todas las líneas tienen la misma cantidad de estaciones, y por lo tanto no se puede construir una matriz.

Sin embargo, se puede construir algo parecido a una matriz donde no importe si cada línea tiene una cantidad distinta de estaciones.

No se si has trabajado con colecciones de datos dinámicas, como las clases Vector, ArrayList, etc...
Son colecciones de datos similares a los "arrays primitivos", pero no tienen un tamaño determinado, pueden crecer o decrecer según se añaden o eliminan elementos y además tiene todas las ventajas que da ser una clase orientada a objetos: métodos, herencias, etc...

La ideas es crear cada línea usando una de estas clases, por ejemplo Vector que para este caso nos sobra con lo que ofrece.

Una vez creadas las líneas, estos objetos Vector, se pueden a su vez agrupar en un array simple.
De este modo, tenemos algo muy parecido a una matriz.

Esto hace que luego en el método de busca de estaciones, ya no es necesario usar un bucle distinto para cada linea.
Basta con solo dos bucles anidados.

Abajo dejo un código de prueba donde verás que el método de buscar estaciones, queda reducido a muy pocas líneas.
Además, ya puestos a usar la clase Vector, en ese método de búsqueda lo que hago es devolver los nombres de las líneas coincidentes en un objeto Vector.
Así en un solo objeto tenemos los nombres de las líneas y también la cantidad, pues nos basta con consultar la longitud que tiene dicho Vector.

Aquí te dejo el código por si te resulta útil.

Código: [Seleccionar]
public class EstacionesMetro {

static Vector<String>[] estaciones; //Array de objetos Vector

public static void main(String[] args) {

initEstaciones();
Scanner teclado = new Scanner(System.in);

System.out.print("Estación a consultar: ");
String estacion = teclado.nextLine();
teclado.close();

//Recogemos en un Vector las líneas que contienen dicha estacion
Vector<String> lineas = lineas_por_estacion(estacion);

if (lineas.isEmpty())
System.out.println("No se han encontrado lineas para esas estación.");
else {
System.out.println("Hay " + lineas.size() + " líneas que contienen esa estación.");
System.out.print("Las líneas son: ");
for (String lin: lineas)
System.out.print("[ L" + lin + " ] ");
}

}

static Vector<String> lineas_por_estacion(String estacion) {

Vector<String> lineas = new Vector<String>();
for (int i = 0; i < estaciones.length; i++) {
for (int j = 0; j < estaciones[i].size(); j++) {

if (estaciones[i].get(j).equalsIgnoreCase(estacion)) {
lineas.add(Integer.toString(i + 1));
}
}
}

return lineas;

}

static void initEstaciones() {
Vector<String> l1 = new Vector<String>();
l1.add("Hospital de Bellvitge"); l1.add("Bellvitge"); l1.add("Av. Carrilet");
l1.add("Rambla Just Oliveras"); l1.add("Can Serra"); l1.add("Florida");
l1.add("Torrassa"); l1.add("Santa Eulalia"); l1.add("Mercat Nou");
l1.add("Plaça de Sants"); l1.add("Hostafrancs"); l1.add("Espanya");
l1.add("Rocafort"); l1.add("Urgell"); l1.add("Universitat");
l1.add("Catalunya"); l1.add("Urquinaona"); l1.add("Arc de Triomf");
l1.add("Marina"); l1.add("Glories"); l1.add("Clot");
l1.add("Navas"); l1.add("La Sagrera"); l1.add("Fabra i Puig");
l1.add("Sant Andreu"); l1.add("Torras i Bages"); l1.add("Trinitat Vella");
l1.add("Baro de Viver"); l1.add("Santa Coloma"); l1.add("Fondo");
Vector<String> l2 = new Vector<String>();
l2.add("Paral·lel"); l2.add("Sant Antoni"); l2.add("Universitat");
l2.add("Passeig de Gràcia"); l2.add("Tetuan"); l2.add("Monumental");
l2.add("Sagrada Familia"); l2.add("Encants"); l2.add("Clot");
l2.add("Bac de Roda"); l2.add("Sant Marti"); l2.add("La Pau");
l2.add("Verneda"); l2.add("Artigues Sant Adria"); l2.add("Sant Roc");
l2.add("Gorg"); l2.add("Pep Ventura"); l2.add("Badalona Pompeu Fabra");
Vector<String> l3 = new Vector<String>();
l3.add("Zona Universitaria"); l3.add("Palau Reial"); l3.add("Maria Cristina");
l3.add("Les Corts"); l3.add("Plaça del Centre"); l3.add("Sants Estacio");
l3.add("Tarragona"); l3.add("Espanya"); l3.add("Poble Sec");
l3.add("Paral·lel"); l3.add("Drassanes"); l3.add("Liceu");
l3.add("Catalunya"); l3.add("Passeig de Gracia"); l3.add("Diagonal");
l3.add("Fontana"); l3.add("Lesseps"); l3.add("Vallcarca");
l3.add("Penitents"); l3.add("Vall d'Hebron"); l3.add("Montbau");
l3.add("Mundet"); l3.add("Valldaura"); l3.add("Canyelles");
l3.add("Roquetes"); l3.add("Trinitat Nova");
Vector<String> l4 = new Vector<String>();
l4.add("La Pau"); l4.add("Besos"); l4.add("Besos Mar");
l4.add("El Maresme Forum"); l4.add("Selva de Mar"); l4.add("Poblenou");
l4.add("Llacuna"); l4.add("Bogatell"); l4.add("Ciutadella Vila Olimpica");
l4.add("Barceloneta"); l4.add("Jaume I"); l4.add("Urquinaona");
l4.add("Passeig de Gracia"); l4.add("Girona"); l4.add("Verdaguer");
l4.add("Joanic"); l4.add("Alfons X"); l4.add("Guinardo Hospital de Sant Pau");
l4.add("Maragall"); l4.add("Llucmajor"); l4.add("Via Julia");
l4.add("Trinitat Nova");
Vector<String> l5 = new Vector<String>();
l5.add("Cornella Centre"); l5.add("Gavarra"); l5.add("Sant Ildefons");
l5.add("Can Boixeres"); l5.add("Can Vidalet"); l5.add("Pubilla Cases");
l5.add("Collblanc"); l5.add("Badal"); l5.add("Plaça de Sants");
l5.add("Sants Estacio"); l5.add("Entença"); l5.add("Hospital Clinic");
l5.add("Diagonal"); l5.add("Verdaguer"); l5.add("Sagrada Familia");
l5.add("Sant Pau Dos de Maig"); l5.add("Camp de l'Arpa"); l5.add("La Sagrera");
l5.add("Congres"); l5.add("Maragall"); l5.add("Virrei Amat");
l5.add("Vilapicina"); l5.add("Horta"); l5.add("El Carmel");
l5.add("El Coll La Teixonera"); l5.add("Vall d'Hebron");

estaciones = new Vector[5];
estaciones[0] =  l1; //Linea 1 está en posicion 0
estaciones[1] =  l2; //Linea 2 en posicion 1, etc...
estaciones[2] =  l3;
estaciones[3] =  l4;
estaciones[4] =  l5;
}

}

En pantalla tendríamos esto:
Citar
Estación a consultar: Diagonal
Hay 2 líneas que contienen esa estación.
Las líneas son: [ L3 ] [ L5 ]

Pregunta cualquier duda. Un saludo.

726
Hola.
Pero, parece que tu código sí conseguiría lo que quieres....
...de no ser por esto raro que haces tras los bucles de búsqueda:
Código: [Seleccionar]
contador = nLineas;
return nLineas;

La variable contador donde has estado contando la coincidencias, la machacas con nLineas, que no se lo que tiene porque es una variable que viene "de fuera" de este método.
Y luego lo que retornas es nLineas

Es decir, la variable que has usado para contar coincidencias, machacas su valor y de todos modos luego ni siquiera la retornas.

Parece que lo lógico sería retornar contador directamente, ya que es quién ha contado las coincidencias.

727
Hola.
Pues en realidad es lo más fácil.

Puedes haces crear un array con, por ejemplo, 10 objetos Rectangulo.

Para crearlo, puedes pedir por teclado la base y altura de cada uno.
Pero es tedioso y de todos modos parece que lo que interesa es mostrar su perímetro y área.

Así que otra opción es generar los valores para la base y altura al azar, usando la clase Random.

Una vez creados, recorres el array y muestras los datos de cada rectángulo generado.

Algo como esto: (pongo límite de base y altura hasta 30 porque es lo que has indicado en tu código)

Código: [Seleccionar]
public class PruebaRectangulo {

public static void main(String[] args) {
//Inicializamos array de rectangulos
Rectangulo[] listaRectangulos = new Rectangulo[10];

//Creamos rectangulos con base y altura al azar
Random rnd = new Random();
for (int i = 0; i < listaRectangulos.length; i++) {
int base = rnd.nextInt(29) + 1; //Genera valores al azar entre 1 y 30
int altura = rnd.nextInt(29) + 1;
listaRectangulos[i] = new Rectangulo(altura, base);
}

//Ya tenemos 10 rectangulos creados, mostramos su área y perímetro

for (int i = 0; i < listaRectangulos.length; i++) {
System.out.println("\n*** Rectángulo #" + (i + 1) + " ***");
System.out.println("Base: " + listaRectangulos[i].getBase());
System.out.println("Altura: " + listaRectangulos[i].getAltura());
System.out.println("Area: " + listaRectangulos[i].getArea());
System.out.println("Perimetro: " + listaRectangulos[i].getPerimetro());
}

}

}

En pantalla tendríamos este resultado:
Citar
*** Rectángulo #1 ***
Base: 22
Altura: 21
Area: 462
Perimetro: 86

*** Rectángulo #2 ***
Base: 28
Altura: 22
Area: 616
Perimetro: 100

*** Rectángulo #3 ***
Base: 24
Altura: 27
Area: 648
Perimetro: 102

*** Rectángulo #4 ***
Base: 22
Altura: 18
Area: 396
Perimetro: 80

*** Rectángulo #5 ***
Base: 25
Altura: 27
Area: 675
Perimetro: 104

*** Rectángulo #6 ***
Base: 3
Altura: 7
Area: 21
Perimetro: 20

*** Rectángulo #7 ***
Base: 2
Altura: 13
Area: 26
Perimetro: 30

*** Rectángulo #8 ***
Base: 8
Altura: 26
Area: 208
Perimetro: 68

*** Rectángulo #9 ***
Base: 9
Altura: 25
Area: 225
Perimetro: 68

*** Rectángulo #10 ***
Base: 24
Altura: 20
Area: 480
Perimetro: 88

728
Que lenguaje es, ¿MatLab?

Nunca lo he usado, así que no puedo ayudar demasiado.

Aparentemente la lógica es correcta. Si te está fallando, puede que sea un problema de sintaxis.
Prueba a encerrar las dos condiciones cada una dentro de su paréntesis propio.

Citar
if (mod(x,2) == 0) && (mod(x,3)== 0)

729
Comunidad / Re:COMO PUBLICAR UN TEMA EN UN FORO CONCRETO
« en: 11 de Abril 2020, 17:30 »
Hola. Básicamente solo hay 4 subforos disponibles.

1.- Aprender a Programar desde Cero
Este subforo se usa principalmente para consultas y respuestas sobres los cursos y ejercicios de aprendizaje que hay disponibles en la web
Pero también tienen cabida mensajes ajenos a estos cursos, pero principalmente enfocados a gente que se está iniciando y tiene dudas sobre por donde empezar su aprendizaje

2.- C, C++, C#, Java, Visual Basic, HTML, PHP, CSS, Javascript, Ajax, Joomla, MySql y más
Este está enfocado para preguntas, dudas, aportaciones.... sobre cualquier lenguaje de programación, pero digamos que ya en niveles más avanzados, no tanto para dudas sobre como iniciarse, si no como profundizar en conocimientos ya adquiridos.

3.- De todo un poco...
Este sería para temas aún más generalizados: dudas sobre sistemas operativos, ofimática, configuración de hardware, periféricos... e incluso temas no relacionados con informática o computación.

4.- Comunidad
Este es el subforo donde nos encontramos.
Un espacio para presentarse, preguntas sobre el foro, hacer sugerencias....


Esas son la 4 opciones que hay.
Si buscas un subforo dedicado a un único lenguaje: subforo de Java, subforo de PHP, subforo de C/C++... no los hay.
Se tratan todos juntos en un mismo subforo.

Puedes elegir entre uno de los dos primeros subforos.

731
Mira, una de las principales dificultades para aprender programación, por no decir la mayor de todas, es encontrarle el sentido a los enunciados de los ejercicios que a menudo resultan incongruentes.

La clase Date está pensada para modelar fechas (Date = Fecha)
Date sirve para representar un instante concreto del tiempo, por ejemplo, el 4 de Abril de 2020, a las 23:00 de la noche.

No sirve para representar magnitudes de tiempo: 2 horas, 120 minutos, 7200 segundos...
con las que luego hacer operaciones aritméticas.

Yo ignoraría la premisa de usar la clase Date y haría lo que dije al principio de mi anterior mensaje, usar un simple int que trabaje con minutos.

Sobre los parámetro de tiempo y distancia, como tú mismo te has dado cuenta, de nuevo es incongruente el enunciado.

Si nos dicen que la distancia SIEMPRE va a ser de 800 km para TODOS los Transportes, a mi lo que me parecería lógico es crear un atributo con valor constante en la clase Transporte.
Y este es además uno de esos ejemplos donde se puede poner protected o incluso public, ya que al ser constante por muy visible que sea, no hay riesgo de que sea alterado.

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private Date tiempo;
private int capacidad;
protected final int DISTANCIA = 800; //Kilómetros

Pero bueno, si te dicen que luego se ha de pedir por parámetro, pues nada, no crearemos ese atributo y el valor de 800 lo pasaremos por parámetro.
Pero lo que si que hay que hacer, es declarar en el método abstracto que se ha de recibir una distancia por parámetro.
E insisto que tiempo ha de ser int, y sus get y set dejan de ser abstractos

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private int tiempo;
private int capacidad;

public abstract void VelocidadMedia(int distancia);

public int getTiempo() {
return tiempo;
}

public void setTiempo(int tiempo) {
this.tiempo = tiempo;
}

La clase Barco, en su constructor seteamos el tiempo de 7 horas llamando al método de la superclase.

Código: [Seleccionar]
public class Barco extends Transporte{

private int categoria;

public Barco(int categoria) {
super.setTiempo(420); //en minutos = 7 horas
this.categoria = categoria;

if(categoria==1) {
setPrecio(120);
}

Con esto ya establecido, ya solo hay que añadir código al método calcularDistancia() de la clase Barco.
Ahora que hemos decidido operar con valores int para la distancia y para el tiempo, no hay problemas para hacer cálculos.

Parece que se pide la velocidad media en nudos, creo que sería como pongo a continuación, pero si quieres intentar hacer el cálculo tú primero, pues no lo leas todavía  ;)

Un saludo.

Código: [Seleccionar]
@Override
public void VelocidadMedia(int distancia) {
int kmHora = distancia / (super.getTiempo() / 60); //Tiempo hay que convertir a horas
float nudos = kmHora * 0.54f;
System.out.println(String.format("Velocidad media en nudos: %.2f", nudos));
}

732
No estoy muy seguro de que quieres representar exactamente con el atributo tiempo.

Si quieres representar simplemente el número de horas que tarda en realizar su recorrido:
7 horas, 2 horas, etc...
Puedes usar simplemente un atributo int que trabaje con minutos y dividiendo por 60 puedes convertir a horas.
Haciendo mod de 60 obtienes el resto para mayor precisión.

Por ejemplo,
tiempo = 450;(minutos)

tiempo / 60 --> 450 / 60 = 7 (horas enteras)
tiempo mod 60 --> 450 % 60 = 30 (resto minutos)

450 minutos son 7 horas y 30 minutos.



Es distinto si quieres representar un tiempo concreto del día
Supongamos que queremos representar la hora a la que sale cada objeto Transporte
Uno sale a las 10:00 de la mañana, otro sale a las 15:30, otro sale  a las 20:45....

Y queremos preguntarle al programa que Transporte ha salido ya o cuál no ha salido todavía.

La clase Calendar está algo oxidada ya...
Y Date se considera obsoleta.

Es mejor usar otras clases más nuevas como LocalDate o LocalTime.
Puesto que en este ejemplo solo nos interesa el tiempo y no fechas, es mejor usar LocalTime.

Así la clase Transporte puede usar un atributo de este tipo.
Y el get y set para tiempo, dejan de ser abstractos y es la superclase Transporte quien tiene el código para gestionar.
Fíjate que para setear el tiempo, usamos dos int, uno representa la hora y la otra el minuto

Código: [Seleccionar]
import java.time.LocalTime;

public abstract class Transporte {

private float precio;
private LocalTime tiempo;
private int capacidad;

public abstract void VelocidadMedia();

public abstract void Salida();

public float getPrecio() {
return precio;
}

public int getCapacidad() {
return capacidad;
}

public abstract void setCapacidad(int capacidad);

public abstract void setPrecio(float precio);

public LocalTime getTiempo() {
return tiempo;
}

public void setTiempo(int hora, int minuto) {
tiempo = LocalTime.of(hora, minuto);
}
}

Podemos hacer ahora un código para probar como funciona ese atributo.
Este es un programita que hace una lista de tres Barcos en un array.

Hay un método que, según la hora actual (coge la hora del sistema), nos dice que barcos han zarpado ya, y si no lo han hecho, nos dice a que hora salen y cuanto tiempo falta para que zarpen:
Código: [Seleccionar]
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

public class Prueba {

private static Barco[] barcos; //Listado de barcos

public static void main(String[] args) {

//Creamos lista e indicamos sus horas de salida
barcos = new Barco[3];

barcos[0] = new Barco(1);
barcos[0].setTiempo(10, 0);//Sale a las 10:00
barcos[1] = new Barco(2);
barcos[1].setTiempo(15, 30);//Sale a las 15:30
barcos[2] = new Barco(3);
barcos[2].setTiempo(22, 45);//Sale a las 22:45

comprobarHorarios();
}

/**
* Recorre la lista de Barcos e indica que barcos han salido ya
* y los que no han salido, cuanto tiempo falta para que salgan
*/
public static void comprobarHorarios() {
//Recogemos la hora actual, a partir de la hora del sistema
LocalTime ahora = LocalTime.now();
System.out.println("Hora actual: " + ahora.getHour() + ":" + ahora.getMinute());

for (int i = 0; i < barcos.length; i++) {

if (barcos[i].getTiempo().isAfter(ahora)) { //Este barco aún no ha salido

System.out.println("\n\nHay un Barco disponible a las " + barcos[i].getTiempo().toString());
long minutosHastaSalir = ahora.until(barcos[i].getTiempo(), ChronoUnit.MINUTES);
int horas = (int) (minutosHastaSalir / 60);
int minutos = (int) (minutosHastaSalir % 60);
System.out.println("Faltan " + horas + " horas y " + minutos + " minutos para zarpar");
}
else { //Este barco ya ha salido
System.out.println("\n\nHay un barco que ya ha zarpado a las " + barcos[i].getTiempo().toString());
System.out.println("No estará disponible hasta mañana");
}
}
}

}

En pantalla nos sale un resultado como este:
Citar
Hora actual: 0:20


Hay un Barco disponible a las 10:00
Faltan 9 horas y 39 minutos para zarpar


Hay un Barco disponible a las 15:30
Faltan 15 horas y 9 minutos para zarpar


Hay un Barco disponible a las 22:45
Faltan 22 horas y 24 minutos para zarpar

Si engaño en el código para decir que "ahora" son las 15:25
Código: [Seleccionar]
//Recogemos la hora actual, a partir de la hora del sistema
LocalTime ahora = LocalTime.of(15, 25);

En pantalla tenemos
Citar
Hora actual: 15:25


Hay un barco que ya ha zarpado a las 10:00
No estará disponible hasta mañana


Hay un Barco disponible a las 15:30
Faltan 0 horas y 5 minutos para zarpar


Hay un Barco disponible a las 22:45
Faltan 7 horas y 20 minutos para zarpar


Esta podría ser una forma de hacerlo. Todo depende de qué quieres representar exactamente con el atributo tiempo que, repito, aún no me ha quedado claro.

Incluso se puede combinar. Un atributo para la hora de salida y otro atributo para indicar la duración del viaje.
De ese modo, solo con indicar la hora de salida, se puede hacer el cálculo de cuál sera la hora de llegada, puesto que hay otro atributo para indicar la duración.


En cualquier caso, ahora ya conoces la clase LocalTime, que es una maravilla. Oracle la introdujo junto con LocalDate cuando lanzó Java8, porque Calendar, Date y otras necesitaban modernizarse.

Un saludo.

733
Hola.
Tienes dos opciones.

Una es declarar los atributos de Transporte como protected
Esto es que estaríann a medio camino entre private y public.

En protected sigues impidiendo que cualquier clase pueda acceder a estos atributos directamente.
Sin embargo, permites que las clases hijas que hereden de Transporte, sí puedan acceder libremente a estos atributos.

Así, si pones precio como protected:

Código: [Seleccionar]
public abstract class Transporte {

protected float precio;
private Date tiempo;
private int capacidad;

Luego sus clases hijas como Barco, tienen acceso al atributo, usando la palabra reservada super para llamar a su clase padre:

Código: [Seleccionar]
@Override
public float getPrecio() {
return super.precio;
}

Esta es una opción.

La otra, consiste en conservar el atributo precio como private, pero lo que haremos será que la clase Transporte, su método getPrecio() NO será abstracto. Será como un getter normal y corriente.

Código: [Seleccionar]
public abstract class Transporte {

private float precio;
private Date tiempo;
private int capacidad;

public abstract void VelocidadMedia();

public abstract void Salida();

public float getPrecio() {
return precio;
}

De este modo, la clase Barco ya hereda directamente un método para devolver el precio.
No necesita que le hagas un getter para el precio, porque ya va a tener el que hereda de su superclase Transporte.

Sin embargo, puede que sí quieras que Barco tenga su propio getter para el precio según el ejercicio que esté realizando.

No parece ser el caso, pero vamos a suponer que tu quieres que las clases hijas de Transporte complementen el precio cada una a su manera.
Vamos a suponer que el atributo precio de Transporte es el precio básico. Pero que por ejemplo si es un Barco, a ese precio hay que añadirle un 15% por un impuesto exclusivo que tienen todos los Barcos.

En este caso, puede sobreescribir el método getPrecio que se hereda de Transporte y complementar el precio básico con dicho impuesto.
De nuevo, usamos la palabra super, pero para acceder al método heredado, no al atributo ya que no es visible al ser private.
Así la clase Barco tendría este método:
Código: [Seleccionar]
@Override
public float getPrecio() {
//Los barcos tienen un impuesto del 15%
return super.getPrecio() * 1.15f;
}
Si otra clase hija, tuviera un impuesto distinto, por ejemplo Helicoptero un impuesto del 30% si su potencia es de 150hp y 35% si es de 250hp, pues también sobreescribiría el método que hereda de la superclase para adecuarlo a sus necesidades.

Resumiendo, tienes en realidad tres opciones:
1- Superclase con atributos protected y métodos abstractos.
Las clases hijas estarán OBLIGADAS a sobreescribir los métodos abstractos que heredan, pero tendrán visibilidad para acceder libremente a los atributos de la superclase y operar con ellos.

2- Superclase con atributos private y métodos no abstractos que ya se encargan de operar con los atributos
Las clases hijas NO tienen visibilidad para acceder a los atributos de la superclase, pero en realidad no lo necesitan porque ya HEREDAN los métodos de la superclase que operan con sus atributos.

3- Superclase con atributos private y métodos no abstractos, que serán sobreescritos por las clases hija
Las clases hijas NO tienen acceso a los atributos de la superclase. HEREDAN los métodos de la superclase que ya operan con esos atributos, pero como la clase hija necesita COMPLEMENTAR con sus peculiaridades propias la operación a realizar con dichos atributos, van a SOBREESCRIBIR  los métodos heredados.



¿Cuál es la mejor de estas opciones?
Ninguna, depende de cada caso y de según prefiera cada programador.

No hay nada de malo en usar la instrucción protected, seguro que profesores te habrán insistido que los atributos han de ser siempre private y esto es cierto el 95% de las veces.
Sin embargo, habrá veces que te ahorres código o te facilite las cosas ampliar la visibilidad de un atributo con protected, o incluso con public, siempre que uno sepa bien lo que está haciendo.

Dicho esto, yo por lo general los mantengo como private y hago que la superclase ya tenga métodos operativos para estos atributos listos para ser heredados por sus hijas.
Y si estas necesitan sobreescribirlos para algo, pues que los sobreescriban.

Espero haberme explicado bien. Repregunta lo que sea.

Un saludo.

734
Comunidad / Re:Presentación
« en: 30 de Marzo 2020, 11:29 »
Bienvenido.

Aprender las bases de la programación es más sencillo de lo que parece. Y apasionante.

Eso sí, la clave es la paciencia, ya que puede pasar bastante tiempo hasta que se empiece hacer algo más interesante que mostrar sumas y restas en la consola del sistema.

Pero hay que ir paso a paso y el camino a recorrer vale la pena.

Échale un vistazo a los cursos disponibles

Ánimo y aquí esta el foro para lo que necesites.

735
Aprender a programar desde cero / Re:Error ejercicio CU00816B
« en: 26 de Marzo 2020, 14:32 »
Ojo a la etiqueta apertura php

Te sobra un >

Citar
   <?php>
      echo "Curso php para empezar a programar";
   ?>

Bórralo para que quede así:

Citar
   <?php
      echo "Curso php para empezar a programar";
   ?>

736
Muchas gracias ya estoy entendiendo. he creado 2 funciones mas para agregar al código.

una para validar el nombre y apellido del trabajador

el compila pero al ejecutar el programa y se escribe una secuencia de números igual las acepta.
Te falla porque has de cambiar las condiciones de la pregunta.

Para validar la cédula preguntábamos si había algún carácter FUERA del rango entre 48 y 57.
Es decir, si alguno era menor de 48 o era mayor de 57, entonces no es una cifra entre 0 y 9 y por lo tanto la rechazábamos.

Para validar el nombre, la pregunta es la opuesta. Ahora tenemos que preguntar si hay algún carácter DENTRO del rango 48 a 57.
Es decir, si algún carácter es mayor/igual a 48 y también menor/igual de 57, entonces sí es una cifra entre 0 y 9, y ha de ser rechazada.

La condición del if quedaría así:

Citar
      if (valorAscii >= 48) and (valorAscii <= 57) then
         validarNombre := false;



y la otra para validar que el salario sea en números y no letras

este me da los siguientes errores de codificacion:

GestionTrabajador.pas(183,15) Error: Type mismatch
GestionTrabajador.pas(187,29) Error: Illegal qualifier

quizás cambiando el valor ascii por otro que desconozca.
Aquí el error está en que el salario es un dato de tipo real, no es un string y no puedes trabajar con él de la misma manera.
Los tipos integer, real,... son auténticas magnitudes aritméticas, no son secuencias de caracteres que puedas recorrer con un bucle.

Por eso, por ejemplo con el valor 1 puedes hacer sumas, restas...
Porque es un valor numérico

integer valor := 1;
valor = valor + 5;


Pero en cambio no las puedes hacer con el valor '1', entre comillas simples, porque ahora es un valor alfanumérico, un string.
Parece un número, pero no lo es, es un carácter que representa un número.

Si intentamos esto:
string valor := '1';
valor = valor + 5;


...el compilador nos dirá que estamos locos.  :P

¿Cómo podemos entonces validar que para el salario nos metan un valor numérico?
Esto es importante en realidad, porque ahora mismo si en el salario metemos letras, el programa da un error de ejecución y se cierra bruscamente.

Lo que podemos hacer es leer el dato del salario como un string.
Comprobamos que solo contenga números, igual que hicimos con la cédula.
Y si la comprobación es correcta, entonces podemos parsear (transformar) ese string a un dato de tipo real.
Para hacer este parseo, podemos usar la función StrToFloat(), que lo que hace es recibir un string entre paréntesis y transformarlo a un valor numérico con coma flotante, es decir, a un valor de tipo real.
Para usar esta función, hay que importar otra unit llamada SysUtils. Yo, al igual que con la unit crt, he tenido que copiar manualmente el archivo sysutils.ppu del directorio de Free Pascal a mi carpeta de proyecto.

Así que, en el código del archivo GestionTrabajador.pas, llamamos a esta nueva librería

Código: [Seleccionar]
UNIT GestionTrabajador;

{
* En la interfaz declaramos estructuras, constantes, variables y
* nombres de procedimientos/funciones que seran visibles para otros
* programas}

INTERFACE

uses crt, sysutils; {Opcionalmente, podemos importar otras units}

type
 
    tipoPersona = record

Creamos una nueva función para validar que salario solo tenga números. Es prácticamente la misma que escribimos para la cédula.
Observa que a esta función le decimos que el salario lo va a recibir como dato de tipo string, no como real.

Código: [Seleccionar]
function validarSalario(salario:string):boolean;

var
valorAscii: integer;

i: integer;

begin

validarSalario := true;{Si se encuentra un caracter que no es numero, pasara a ser false}

for i:= 1 to length(salario) do

begin

valorAscii := ord(salario[i]);

if (valorAscii < 48) or (valorAscii > 57) then
validarSalario := false;

end;

if not validarSalario then

begin

writeln('El salario no puede contener letras o simbolos');

writeln('Intente de nuevo...');

writeln();

end;

end;

Y ahora, para pedir el dato del salario, usamos un bucle como siempre que se repita hasta que su función que valida el salario sea true.
La diferencia es que dentro del bucle pedimos el salario en un string.
Y cuando el bucle ha terminado exitosamente, podemos estar bastante seguros de que el salario introducido es un dato valido y entonces lo parseamos a float para ahora ya sí guardarlo en el atributo salario que es de tipo real.

Código: [Seleccionar]
repeat

Write('Introduzca Salario: ');

ReadLn(st_salario); {Leemos salario en un string para aceptar cualquier entrada y validar despues}

until validarSalario(st_salario);

tra[cantidad].salario := StrToFloat(st_salario);

Para poder leer el salario en un string, previamente hay que declarar una nueva variable en el apartado var

Citar
var
 
   tra: array[1..capacidad] of tipoPersona;
   
   trabajadorMenor: tipoPersona;
 
    cantidad: integer;
 
    opcion: integer;
 
    i, j: integer;
 
    textoBuscar: string;
   
    st_salario: string;
 
    encontrado: boolean;
 
   bono: real;
 
   seBorro:boolean;
 
   acumMedia :real;
 
   contMedia: integer;


Bien, si ahora compilamos nuestros archivos .pas, veremos que al pedir salario, se acepta cualquier tipo de entrada sin que se de ningún error de ejecución, pero el dato ha introducido ha de pasar por la validación y se volverá a pedir el salario hasta que solo contenga números.

En principio, así ha quedado bastante bien, pero hemos pasado un detalle por alto.
Nuestra validación solo acepta números, pero también debería aceptar la coma decimal, pues un salario podría ser: 2500,49
Y esto nuestro programa no lo acepta.

Tenemos que retocar nuestra función para validar el salario y añadir una segunda condición.
Si encontramos un carácter que no es un número, antes de asignar valor false a la función, debemos comprobar si se trata del carácter --> ','
Si el carácter es distinto de la coma, entonces si asignamos valor false

Código: [Seleccionar]
function validarSalario(salario:string):boolean;

var
valorAscii: integer;

i: integer;

begin

validarSalario := true;{Si se encuentra un caracter que no es numero, pasara a ser false}

for i:= 1 to length(salario) do

begin

valorAscii := ord(salario[i]);

if (valorAscii < 48) or (valorAscii > 57) then

if salario[i] <> ',' then {Si aceptamos coma decimal}

validarSalario := false;

end;

if not validarSalario then

begin

writeln('El salario no puede contener letras o simbolos');

writeln('Intente de nuevo...');

writeln();

end;

end;

En principio solo se acepta la coma decimal, no el punto decimal, aunque verás que cuando se muestra el dato en pantalla al hacer un listado, si sale con el punto y no la coma.
Aunque esto puede variar según el sistema operativo y su configuración regional.

ademas me gustaria saber si de la misma maneras en que se hace en geany

Citar
No. No tienes que unir los archivos.
El programa ahora tendrá dos archivos separados: prom.pas y GestionTrabajadores.pas

Cuando compilas el de los trabajadores, como es una UNIT, se genera un archivo .ppu

Luego, cuando compiles el programa principal, se genera el archivo .exe, o sea, el archivo ejecutable, que ya contiene convertido en código máquina, tanto el programa como la UNIT.

se puede hacer usando el programa free pascal ya que al enviarle el código a la profesora debo enviarle los 2 el .exe y el .pas

muchas gracias.

No me queda clara tu pregunta.
En principio da igual si usas geany, free pascal, lazarus, delphi, visual studio o el mismísimo bloc de notas.

Tu proyecto va a tener dos archivos .pas. Uno para la unit y otro para el programa.

Cuando compilas la unit, se genera un archivo .ppu. Este .ppu sería el que tu podrías distribuir a otros programadores para poder utilizar tu gestor de trabajadores, sin tener que entregar el código fuente original.

Y luego al compilar el programa, se genera un archivo .exe. Este ejecutable es el que podrías distribuir al usuario final para que ejecute el programa, sin necesidad de tener los archivos de código fuente, ni el de las units, ni nada.

Así que tu profesora, solo necesitará los dos archivos .pas para poder ver el código fuente que has creado.
Y el .exe para poder probarlo.

Si crees que va a ser un problema entregárselo con el código separado en dos archivos .pas, se puede hacer todo en un solo archivo .pas.
Ya no hay que crear una UNIT, ni hay secciones INTERFACE, IMPLEMENTATION ni nada de eso.

En el programa principal, antes del cuerpo del programa, volvemos a poner las declaraciones de type, var, constants y además los procedimientos y funciones que hemos escrito.

Te adjunto para descargar un archivo .pas de como quedaría todo junto, para que elijas como prefieres tenerlo

737
No. No tienes que unir los archivos.
El programa ahora tendrá dos archivos separados: prom.pas y GestionTrabajadores.pas

Cuando compilas el de los trabajadores, como es una UNIT, se genera un archivo .ppu

Luego, cuando compiles el programa principal, se genera el archivo .exe, o sea, el archivo ejecutable, que ya contiene convertido en código máquina, tanto el programa como la UNIT.

Repito, no se unen. Son dos archivos separados uno del otro. Fíjate lo que marco en rojo, se trabaja con ellos como documentos separados, pero como están en la misma carpeta forman parte del mismo proyecto.




Esto es lo habitual en programación, que un programa esté compuesto por multitud de archivos de código separados.
Habrá uno que será el programa principal, el que ponga todo en marcha y que además, suele ser el que menos código tiene.
En este proyecto, prom.pas es el programa principal y GestionTrabajador.pas es la librería o unidad que pone en uso.

738
Lo ideal en un programa como este (bueno, y en prácticamente todos) es, efectivamente, modular el código en distintos procedimientos y funciones.

Si tenemos un menú de 10 opciones, cada opción debería realizarse mediante un procedimiento.

No hay que hacer un cambio demasiado drástico. Básicamente sería declarar los distintos procedimientos y copiar-pegar el código que tenemos en cada case del switch en su correspondiente procedimiento.

Ahora bien, todo esto podemos hacerlo en el mismo archivo .pas, pero nos puede quedar un archivo enorme, con una gran cantidad de texto, y esto hace que sea muy difícil entender a simple vista cuál es la lógica del programa, donde debemos buscar para modificar o añadir una funcionalidad nueva, etc...

Lo ideal es, no solo separar el código en procedimientos y funciones, si no también separarlo en distintos archivos si es posible.

En este caso podemos crear una UNIT, una unidad/librería, que podemos llamar GestionTrabajador y va a ser quien tenga el grueso del código. Tendrá las variables, funciones, procedimientos, estructuras... que están enfocadas a la creación y gestión de trabajadores.

Para ello creamos un nuevo archivo .pas, pero en lugar de crear un programa (program) creamos una unidad (unit).

La unit tiene dos secciones principalmente: interfaz e implementación.

En la interfaz ponemos las variables que se usarán: integers, strings, el type tipoPersona...

Y también se ponen las cabeceras de los procedimientos y funciones que tendrá la unidad. Solo la cabecera, no el código, que se escribirá después.

Todo lo que pongamos en la interfaz será público, es decir, los programas que hagan uso de esta unit, podrán ver y acceder a esos procedimientos, variables, etc...

A continuación viene la implementación
Es aquí donde se escribe el código de cada procedimiento y función.
Todo lo que aquí se escribe será privado, es decir, los programas que hagan uso de esta unit, no podrán acceder a las variables, constantes,... que pudiéramos declarar aquí.

Si no están en la interfaz, no son visibles fuera de la unit

Aquí te pongo el código de nuestra unidad.  Fíjate que en realidad básicamente es un copia-pega del código que habíamos escrito, solo que ahora estará modulado en distintos procedimientos.
Además he añadido un par de cosas. Ya he encontrado una forma de usar la unit crt y poder hacer clrscr, luego te lo explico.
Además añado instrucciones "repeat until keypressed" al final de cada proceso, para que el usuario decida cuando quiere volver al menú principal pulsando una tecla.

Fíjate que después de compilar, automáticamente se generará un archivo .ppu a partir de nuestra unit.

Código: [Seleccionar]
UNIT GestionTrabajador;

{
* En la interfaz declaramos estructuras, constantes, variables y
* nombres de procedimientos/funciones que seran visibles para otros
* programas}

INTERFACE

uses crt; {Opcionalmente, podemos importar otras units}

type
 
    tipoPersona = record
 
        nombre: string;
 
        salario: real;
 
sal_anual: real;
 
sal_mensual: real;
 
utilidades: real;

vacaciones: real;
 
bono: real;
 
cedula: string;
 
    end;
 
const
 
capacidad = 1000;

cesta = 200;
 
var
 
tra: array[1..capacidad] of tipoPersona;

trabajadorMenor: tipoPersona;
 
    cantidad: integer;
 
    opcion: integer;
 
    i, j: integer;
 
    textoBuscar: string;
 
    encontrado: boolean;
 
bono: real;
 
seBorro:boolean;
 
acumMedia :real;
 
contMedia: integer;


{Ahora procedimientos y funciones, solo su firma/cabecera. Su codigo se escribira despues}

function validarCedula(cedula:string):boolean;

procedure agregarTrabajador;

procedure mostrarTodos;

procedure buscarTrabajador;

procedure reporte1;

procedure reporte2;

procedure borrarTrabajador;

procedure promedioNominaMayor;

procedure promedioNominaMenor;

procedure promedioGeneral;

procedure listaTrabajadoresGananMasQueMayores;

 
{En la implementacion es donde se escribe el codigo de cada funcion y procedimiento}

IMPLEMENTATION

function validarCedula(cedula:string):boolean;

var
valorAscii: integer;

i: integer;

begin

validarCedula := true;{Si se encuentra un caracter que no es numero, pasara a ser false}

for i:= 1 to length(cedula) do

begin

valorAscii := ord(cedula[i]);

if (valorAscii < 48) or (valorAscii > 57) then
validarCedula := false;

end;

if not validarCedula then

begin

writeln('La cedula solo puede contener numeros');

writeln('Intente de nuevo...');

writeln();

end;

end;

procedure agregarTrabajador;

begin

if (cantidad < capacidad) then
 
begin

clrscr;
 
inc(cantidad);

WriteLn('Introduciendo al trabajador ', cantidad);

repeat

Write('Introduzca Cedula del trabajador: ');

ReadLn(tra[cantidad].cedula);

until validarCedula(tra[cantidad].cedula);{Hasta que la funcion devuelva true}

Write('Introduzca el nombre del trabajador: ');

ReadLn(tra[cantidad].nombre);

Write('Introduzca Salario: ');

ReadLn(tra[cantidad].salario);
   
with tra[cantidad] do begin
   
if salario > 1500 then begin

utilidades := salario * 2;{2 meses de utilidades}

vacaciones := salario;{1 mes de bono vacacional}

bono := salario * 0.1;{10% productividad, se paga mensual}

sal_mensual := salario + bono;

sal_anual := sal_mensual * 12 + utilidades + vacaciones;

end

else begin {salario es <= a 1500}

utilidades := salario * 4;{4 meses de utilidades}

vacaciones := salario;{1 mes de bono vacacional}

sal_mensual := salario  + cesta;{cesta ticket mensual}

sal_anual := sal_mensual * 12 + utilidades + vacaciones;

end;
   
end;

writeln('Trabajador registrado. Pulse una tecla para continuar');

repeat until keypressed;

end;

end;

procedure mostrarTodos;

begin

clrscr;

if cantidad = 0 then

WriteLn('No hay datos')

else

for i := 1 to cantidad do

WriteLn(i,' ',tra[i].cedula,' ',tra[i].nombre,' ',tra[i].salario:4:2);

WriteLn;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure buscarTrabajador;

begin

clrscr;

Write('Escriba cedula del trabajador ');

ReadLn( textoBuscar );

encontrado := false;

for i := 1 to cantidad do

if pos (textoBuscar, tra[i].cedula) > 0 then

begin

encontrado := true;

WriteLn( i,' - Cedula: ', tra[i].cedula,',Nombre: ', tra[i].nombre,', Salario: ', tra[i].salario:4:2);

end;

if not encontrado then

WriteLn('No se ha encontrado.');

WriteLn;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure reporte1;

begin

clrscr;

for i := 1 to cantidad do

begin

if tra[i].salario > 1500 then

begin

writeln('Nombre del trabajador: ', tra[i].nombre);

WriteLn('Salario: ', tra[i].salario:4:2);

WriteLn('Bono: ', tra[i].bono:4:2);

WriteLn('Total: ', tra[i].sal_mensual:4:2);

end;

end;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure reporte2;

begin

clrscr;

for i := 1 to cantidad do

begin

if tra[i].salario <= 1500 then

begin

writeln('Nombre del trabajador: ', tra[i].nombre);

WriteLn('Salario: ', tra[i].salario:4:2);

WriteLn('Cestaticket: ', cesta);

WriteLn('Total: ', tra[i].sal_mensual:4:2);

end;

end;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure borrarTrabajador;

begin

clrscr;

write('Nombre a buscar: ');

readln(textoBuscar);

seBorro := false;

for i := 1 to cantidad do begin

{ReadLn(tra[cantidad].nombre);}

if (textoBuscar = tra[i].nombre) then

begin

seBorro := true;
dec(cantidad);

with tra[i] do begin

nombre:='';

salario:=0;

sal_anual:=0.0;

sal_mensual:=0.0;

utilidades:=0;

vacaciones:=0;

bono:=0;

end;

end;

end;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure promedioNominaMayor;

begin

clrscr;

acumMedia:= 0; contMedia:= 0;

for i := 1 to cantidad do

if tra[i].salario > 1500 then

begin

acumMedia := acumMedia + tra[i].salario;

inc(contMedia);

end;

if (contMedia = 0) then

writeln('No hay trabajadores con salario mayor de 1500')

else

writeln('Promedio Nomina Mayor es: ', acumMedia/contMedia:4:2);

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure promedioNominaMenor;

begin

clrscr;

acumMedia:= 0; contMedia:= 0;

for i := 1 to cantidad do

if tra[i].salario <= 1500 then

begin

acumMedia := acumMedia + tra[i].salario;

inc(contMedia);

end;

if (contMedia = 0) then

writeln('No hay trabajadores con salario menor o igual a 1500')

else

writeln('Promedio Nomina Menor es: ', acumMedia/contMedia:4:2);

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure promedioGeneral;

begin

clrscr;

if (cantidad = 0) then

writeln('No hay trabajadores registrados')

else

begin

acumMedia:= 0;

contMedia:= 0;

for i := 1 to cantidad do

begin

acumMedia := acumMedia + tra[i].salario;

inc(contMedia);

end;

writeln('Promedio general es: ', acumMedia/contMedia:4:2);

end;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

procedure listaTrabajadoresGananMasQueMayores;

begin

clrscr;

writeln('Trabajadores Menores que ganan mas que Mayores:');

for i:= 1 to cantidad do {Bucle principal busca trabajadores menores}

if tra[i].salario <= 1500 then

begin

trabajadorMenor := tra[i];

for j:= 1 to cantidad do {Bucle anidado busca empleados mayores para comparar salario anual}

if (tra[j].salario > 1500) and (tra[j].sal_anual < trabajadorMenor.sal_anual) then
{trabajador menor gana mas que un trabajador mayor, mostramos sus datos}
begin

writeln();

write('El trabajador menor con Nombre: ', trabajadorMenor.nombre);

writeln(' y Salario Anual: ', trabajadorMenor.sal_anual:4:2);

write('Gana mas que el trabajador mayor con Nombre: ', tra[j].nombre);

writeln(' cuyo Salario Anual es: ', tra[j].sal_anual:4:2);

break; {Cerramos bucle anidado, no es necesario seguir buscando para este trabajador Menor}

end;

end;

writeln('Pulse una tecla para continuar');

repeat until keypressed;

end;

{
* La siguiente seccion es opcional.
* Podemos poner código que queremos que se ejecute
* al iniciarse el programa, como inicializar variables.}

begin

cantidad := 0;

end.




Puesto que todo el grueso del código está en esta nueva unit, en el programa principal podemos retirar todo ese código que hemos copiado.
Lo único que hay que añadir es indicarle que ha de usar nuestra unit con la instrucción:
USES GestionTrabajador;

Y ya con eso, en cada case del switch nos basta con llamar a los procedimientos correspondientes.

Ahora el código principal queda mucho más reducido y es más fácil de leer y entender lo que está pasando, aunque no estemos viendo el código completo.

Código: [Seleccionar]
program ACME;

uses GestionTrabajador, crt;

var

opcion: integer;
 
{Cuerpo del programa principal}
 
begin
 
    repeat

clrscr;

        WriteLn('***BIENVENIDO A ACME***');
 
        WriteLn;
 
        WriteLn('1- Agregar Trabajador');
 
        WriteLn('2- Todos los trabajadores');
 
        WriteLn('3- Buscar a un trabajador');
 
        WriteLn('4- Reporte 1');
 
        WriteLn('5- Reporte 2');
 
WriteLn('6- Eliminar trabajador');
 
WriteLn('7- Promedio Nomina Mayor');
 
WriteLn('8- Promedio Nomina Menor');
 
WriteLn('9- Promedio General');

writeln('10- Trabajadores de Nomina Menor que ganan mas que algunos de Nomina Mayor');
 
        WriteLn('0- Salir');
 
        Write('Escoja una opcion: ');
 
        ReadLn(opcion);
 
        WriteLn;
 
 
 
        case opcion of
 
1:
agregarTrabajador;
 
            2:
mostrarTodos;
 
            3:
buscarTrabajador;
 
            4:
reporte1;
 
            5:
reporte2;
 
            6:
borrarTrabajador;
 
            7: 
promedioNominaMayor;
 
            8: 
promedioNominaMenor;
 
            9: 
promedioGeneral;

10:

listaTrabajadoresGananMasQueMayores;
 
0: { salir}
 
begin
 
WriteLn;
 
WriteLn('Saliendo...');
 
WriteLn;
 
                end;
 
             else
 
                begin
 
WriteLn;
 
WriteLn('Opción incorrecta!');
 
WriteLn;
 
                end;
 
        end;  { Fin de "case" }
 
    until opcion = 0;
 
end.

El programa funciona igual, pero ahora tenemos el código separado en procedimientos y archivos.
Es más, esa unit que hemos escrito en reutilizable, esto significa que se pueden crear distintos programas que utilicen el type tipoPersona y sus procedimientos para gestionar trabajadores sin tener que volver a escribir este código. Basta con que llamen a esta unit para usarla.
Y si se hace algún cambio en como queremos gestionar los trabajadores, basta con modificar la unit. No sería necesario modificar todo esos posibles programas que hacen uso la unit.

Esta es la ventaja de separar el código en archivos.

Sobre como he hecho para usar la unit crt. Lo he arreglado un poco "a las bravas", he copiado los archivos crt.ppu y crt.o y los he pegado junto los archivos .pas de este proyecto.
Así la unit crt ya está visible y utilizable.
Estos archivos están en la carpeta de instalación de Free Pascal, en mi caso están en la ruta:
C:\FPC\3.0.4\units\x86_64-win64\rtl-console

No es la mejor manera de solucionarlo, en algún sitio se le ha de poder decir al editor Geany que busque units en esa ruta, para no tener que copiar y pegar los archivos a mano.
Pero no soy capaz de ver donde configurar eso.

Te adjunto un archivo .zip con todos los archivos de este proyecto, menos el .exe ejecutable.

739
Hola.
Al estar trabajando ahora en modo consola de texto, las posibilidades para controlar el formato de entrada son algo limitadas.

Y yo tampoco soy ningún experto en Pascal, de hecho, estoy aprendiendo de nuevo a medida que me vas preguntando cosas je je...

Una forma que se me ocurre para por ejemplo evitar que se ingrese una cédula con caracteres no admitidos (letras, símbolos, etc...) es crear una función booleana.
No se si ya has trabajado con procedimientos y funciones.

Una función es un pequeño código que se escribe a parte del programa principal que se va a dedicar a una tarea muy concreta.
Recibe un dato (o varios, según necesitemos), hace los cómputos que le pidamos y al final devuelve un valor: un integer, un real, un string,...

En nuestro caso nos puede interesar que devuelva un boolean, es decir, que devuelva true o false.
Lo que vamos a querer es que la función reciba la cédula que ha tecleado el usuario, que compruebe carácter a carácter si se trata de una cifra numérica o no.

Si solo encuentra números, el resultado a devolver será true, es decir, la cédula es correcta.
En cambio, si encuentra algún carácter que no es un número, entonces devolverá false. La cédula no es correcta.

Así, en nuestro programa principal podemos hacer que la petición de la cédula al usuario esté dentro de un bucle que se repita una y otra vez hasta que nuestra función devuelva valor true porque considere que la cédula es válida.

Esta podría ser la función que necesitamos:
Código: [Seleccionar]
{Declaramos una funcion para validar la cedula}
 
function validarCedula(cedula:string):boolean;

var
valorAscii: integer;

begin

validarCedula := true;{Si se encuentra un caracter que no es numero, pasara a ser false}

for i:= 1 to length(cedula) do

begin

valorAscii := ord(cedula[i]);

if (valorAscii < 48) or (valorAscii > 57) then
validarCedula := false;

end;

if not validarCedula then

begin

writeln('La cedula solo puede contener numeros');

writeln('Intente de nuevo...');

writeln();

end;

end;

Te explico un poco lo que significa cada línea:

function validarCedula(cedula:string):boolean;

Esta es la "firma" o declaración de nuestra función.
- Se va a llamar validarCedula.

- Entre paréntesis le indicamos que dato/s va a recibir cuando se la invoque dentro del programa principal.
En este caso le estamos diciendo que va a recibir un dato string y que dentro de la función se va a llamar cedula. Ojo, este nombre del dato no tiene porque coincidir con el nombre que tendrá en el programa principal, pueden ser nombres distintos. Aquí simplemente le estamos diciendo que nombre queremos que tenga ese dato string dentro
de la función.

- Al final de la firma le estamos diciendo que tipo de dato queremos devolver, en este caso un boolean(verdadero/falso).

var
   valorAscii: integer;


Dentro de la función, podemos hacer otra declaración de variables si lo necesitamos. Es opcional.
Declaramos un integer llamado valorAscii
¿Por qué ese nombre? Porque como veremos a continuación, esta función lo que va a hacer es obtener el código ASCII de cada carácter del string cedula y comprobar si pertenece a un carácter entre 0 y 9, que son los únicos que vamos a considerar aceptables.

Después, comienza el código de la función:

begin

   validarCedula := true;{Si se encuentra un caracter que no es numero, pasara a ser false}


Lo primero que hacemos es asignar el valor true a la función. En Pascal la función es al mismo tiempo una variable, por eso podemos asignarle un valor de este modo.
Así que en realidad, en Pascal, la función no retorna un valor, si no que lo adopta.
En otros lenguajes como C y derivados (C++, Java, C#...) esto no es así en absoluto, las funciones no adoptan valores, si no que los retornan.
Esto lo comento como curiosidad.

Volviendo a esa línea, ¿por qué comenzamos dándole valor true si aún el programa no ha comprobado ningún carácter?
Porque para simplificar el código, vamos a comenzar considerando que la cédula es correcta. Luego, si el código encuentra algún carácter no aceptable, cambiará el valor de la función a false.

for i:= 1 to length(cedula) do
   
   begin
   
      valorAscii := ord(cedula[ i ]);
   
      if (valorAscii < 48) or (valorAscii > 57) then
         validarCedula := false;
      
   end;


Comienza un bucle que va desde 1 hasta la longitud que tenga el string cédula. De este modo usaremos este indice para visitar cada uno de los caracteres que tiene el string, igual que si fuera un array. De hecho, un string es un array de caracteres.

Lo primero que hace es invocar a la función ord(), que pertenece a Pascal, que lo que hace es recibir un caracter del string cedula y devolvernos su valor ASCII, que lo recogemos en el integer que habíamos declarado previamente.

Luego preguntamos si este valor ASCII es inferior a 48 ó superior a 57. ¿Por qué?
Si le hechas un vistazo a la tabla ASCII verás que los caracteres del 0 al 9 están asignados a los códigos entre 48 y 57.

Entonces, si la función encuentra un carácter que está fuera de ese rango, significa que no es un número entre 0 y 9, por lo tanto la cédula contiene caracteres no válidos y es entonces cuando la función adopta valor false. Y mantendrá este valor aunque el bucle siga adelante y encuentre números válidos en los próximos caracteres.
Basta con que haya una sola letra o símbolo para que la cédula sea rechazada.

if not validarCedula then
   
   begin
   
      writeln('La cedula solo puede contener numeros');
      
      writeln('Intente de nuevo...');
      
      writeln();
      
   end;


Esta parte es simplemente para informar al usuario de que se ha equivocado con la cédula ingresada.
Estos mensajes solo aparecen cuando la función tiene valor false.

Preguntar if not validarCedula es exactamente lo mismo que pregunta if validarCedula = false


Y este será el análisis de nuestra función, ahora vamos a ver como usarla en el programa principal.

Código: [Seleccionar]
                begin
 
    inc(cantidad);
 
                    WriteLn('Introduciendo al trabajador ', cantidad);
                   
                    repeat
 
Write('Introduzca Cedula del trabajador: ');
 
ReadLn(tra[cantidad].cedula);

   until validarCedula(tra[cantidad].cedula);{Hasta que la funcion devuelva true}

  write('Introduzca el nombre del trabajador: ');

Como vemos, la petición de la cédula la hacemos dentro un bucle repeat ... until, que se va a repetir hasta que la función validarCedula() consiga tener valor true.

Esta es una forma de solucionar lo que pides, seguramente hay formas mejores, como usar expresiones regulares
Pero ahora mismo no tengo ni idea de como se usan en Pascal y además requieren cierto aprendizaje y quizás no es momento ahora de que te adentres en ellas.


Te adjunto para descargar el archivo .pas para descargar, por si tienes dudas de donde he declarado la función.

En principio la función la puedes declarar en cualquier sitio fuera del cuerpo principal.
Pero fíjate que en este caso, en la función utilizo la variable i para el bucle for que está en la declaración var principal.
Entonces, conviene que la función esté declarada después del var principal porque si no, no sabrá qué es la variable i al compilar.

Ahora que lo pienso, la verdad es que habría sido más correcto declarar dentro de la función, otro integer distinto para su bucle for.
Al usar la variable i que se ha declarado en el var principal ponemos en riesgo el buen funcionamiento del programa.
En este caso no pasa nada, pero imagina que dentro de un bucle for que está usando esa variable i como indice, invocamos a nuestra función que también va a usar esa misma variable como indice.
La función estaría alterando los valores de i y el bucle for no estaría completando correctamente sus iteraciones.

Así que mejor que la función use sus propias variables internas y no las declaradas para el programa principal para evitar estos problemas.

En fin, prueba estos cambios y pregunta si tienes dudas.
Un saludo.

740

1 me sugirio que no solo aparecieran los trabajadores menor ganan mas si no que aparecieran en pantalla cuales son los trabajadores mayores haciendo la comparacion. Por ejemplo si el trabajador menor 2 gana mas que el trabajador mayor 1 entonces deben aparecer los dos en pantalla

Añadir eso es sencillo, cuando el bucle encuentra el trabajador mayor que gana MENOS que el trabajador menor, en ese momento tenemos acceso a los datos de ambos. Así que basta con modificar un poco los writeln para mostrar en pantalla la info de dichos trabajadores.
Código: [Seleccionar]
10: {Trabajadores Menores que ganan mas que Mayores}

{clrscr;}

begin

writeln('Trabajadores Menores que ganan mas que Mayores:');

for i:= 1 to cantidad do {Bucle principal busca trabajadores menores}

if tra[i].salario <= 1500 then

begin

trabajadorMenor := tra[i];

for j:= 1 to cantidad do {Bucle anidado busca empleados mayores para comparar salario anual}

if (tra[j].salario > 1500) and (tra[j].sal_anual < trabajadorMenor.sal_anual) then
{trabajador menor gana mas que un trabajador mayor, mostramos sus datos}
begin

writeln();

write('El trabajador menor con Nombre: ', trabajadorMenor.nombre);

writeln(' y Salario Anual: ', trabajadorMenor.sal_anual:4:2);

write('Gana mas que el trabajador mayor con Nombre: ', tra[j].nombre);

writeln(' cuyo Salario Anual es: ', tra[j].sal_anual:4:2);

break; {Cerramos bucle anidado, no es necesario seguir buscando para este trabajador Menor}

end;

end;

end;

2. he agregado el valor cedula al codigo por sugerencia de la profesora pero este lo he puesto de forma string ya que no me compilaba como integer. Como podria hacer para que fuera solo integer y que no reconociera otra cosa si no numeros.
En Pascal, un integer es un valor de 16 bits con signo. Esto significa que solo puede almacenar valores numéricos entre el rango: -32768 hasta 32767

Ese rango se queda muy pequeño si queremos guardar números largos como los de una cédula o un teléfono.
De hecho, se queda muy pequeño para gran parte de operaciones matemáticas.
Si por ejemplo queremos contar las personas que viven en una ciudad de 50.000 habitantes, no nos va a servir

Para números más grandes podemos usar el tipo Longint, que es de 32 bit y amplía muchísimo más el rango numérico.

Ahora bien, para trabajar con datos como los hemos mencionado, cédulas o números de teléfono, puesto que en principio no vamos a realizar operaciones matemáticas con ellos, no es necesario guardarlos en un tipo de dato numérico.
Podemos usar un string, y de hecho, tiene más sentido hacerlo así. Cédulas, teléfonos, códigos postales..., aunque estén compuesto de cifras numéricas, realmente no son magnitudes aritméticas.
Son cadenas de caracteres y tiene sentido guardarlos en un string, y de hecho, puede que no sea más útil para según que cosas tratarlos como cadenas (string) y no como valor numérico (integers, etc..)

3. le he colocado al codigo el comando clrscr para hacer el programa mas amigable pero este no me deja compilarlo me gustaria saber porque ocurre este error.

Te puedo decir por qué ocurre, pero no como solucionarlo xD
Al menos yo no lo he conseguido solucionar.

clrscr y otros comandos para el manejo de la pantalla, no forman parte de la librería básica de Pascal.
Forman parte de otras librerías (units) que acompañan a este lenguaje, y para poder usar estos comandos, hay que decirle al programa que las importe.

clrscr forma parte de la unit llamada crt, así que hay que decirle al programa que queremos usarla y esto lo hacemos al principio de todo con la palabra reservada "uses" y a continuación el nombre de la unit/librería que queremos usar.
Citar
program ACME;

uses CRT;

type
 
    tipoPersona = record
 
        nombre: string;
 
        salario: real;

Con esto el compilador ya sabrá que es el comando clrscr;

Sin embargo, al menos en mi caso, ahora el compilador se queja de que no encuentra la unit CRT.

Y no he sabido solucionarlo. Nunca había utilizado el editor Geany, ni el compilador Free Pascal. Como dije al principio, hace 20 años que estudié algo de Pascal, en ordenadores y sistemas operativos que no tienen nada que ver con los actuales.

He empezado a usar Geany y a rememorar algo de Pascal, a raíz de tus mensajes, para intentar ayudarte.
Pero no he logrado hacer que el compilador encuentre la unit CRT, a pesar de que la tengo en el directorio donde instalé el compilador Free Pascal.

Quizás tu profesora que tendrá más experiencia con Geany, sepa decirte como solucionarlo. Si lo hace, ¡compártelo por aquí!  ;)

Un saludo.

Páginas: 1 ... 32 33 34 35 36 [37] 38 39 40 41 42 ... 50

Sobre la educación, sólo puedo decir que es el tema más importante en el que nosotros, como pueblo, debemos involucrarnos.

Abraham Lincoln (1808-1865) Presidente estadounidense.

aprenderaprogramar.com: Desde 2006 comprometidos con la didáctica y divulgación de la programación

Preguntas y respuestas

¿Cómo establecer o cambiar la imagen asociada (avatar) de usuario?
  1. Inicia sesión con tu nombre de usuario y contraseña.
  2. Pulsa en perfil --> perfil del foro
  3. Elige la imagen personalizada que quieras usar. Puedes escogerla de una galería de imágenes o subirla desde tu ordenador.
  4. En la parte final de la página pulsa el botón "cambiar perfil".