Autor Tema: C dibujar circunferencia y media luna asteriscos consola lenguajeC #algoritmia  (Leído 734 veces)

jorge1g

  • Sin experiencia
  • *
  • APR2.COM
  • Mensajes: 5
    • Ver Perfil
Hola a todos:

Estoy empezando a programar en lenguaje C y me han puesto una práctica que consiste en dibujar una media luna con asteriscos introduciendo desde el teclado el valor del radio. Por ejemplo, con un radio de 5, debería quedar algo así:

     * *
  *    *
 *    *


*    *


 *    *
  *    *
     * *

Para hacer el primer semicírculo, he usado la ecuación que calcula los puntos que pertenecen a una circunferencia:

(x-a)*(x-a)+(y-b)*(y-b)=r*r

siendo (a,b) las coordenadas del centro de la circunferencia y r el radio. El programa que he hecho para dibujar la primera semicircunferencia es este:

Código: [Seleccionar]
#include <stdio.h>
    int main(){
        int n, i, j;
        printf("Introduzca el tamaño de la luna: ");
        scanf("%d", &n);
        for(j = 0; j <= 2*n; j++){
            for(i = 0; i <= n; i++){
                if (((i-n)*(i-n))+((j-n)*(j-n)) == n*n)
                        printf("*");
                    else printf(" ");}
        printf("\n");
    }
    }

Con este programa se dibuja esto:

     *
  *
 *


*


 *
  *
     *


Pero no se me ocurre como dibujar la otra semicircunferencia para completar la media luna.

¿Alguien me puede ayudar? Muchas gracias.
« Última modificación: 06 de Noviembre 2020, 10:15 por Mario R. Rancel »

Mario R. Rancel

  • Administrador
  • Experto
  • ********
  • APR2.COM
  • Mensajes: 1950
    • Ver Perfil
Hola, un problema interesante de algoritmia para entretenerse un rato y que que puede solucionarse de múltiples maneras, algunas más matemáticas y otras más intuitivas. Y nada sencillo como ejercicio para iniciarse en programación. Tener en cuenta que una circunferencia sólo tiene una forma, pero una media luna puede dibujarse de muchas maneras. Voy a indicar cómo lo he planteado yo. En primer lugar he empezado estudiando el problema y me he dibujado una media circunferencia de radio r. Para ello he optado por situar el centro de la circunferencia en el origen de los ejes de coordenadas, es decir, en el punto (0, 0), pues eso en principio simplifica un poco la ecuación de la circunferencia. Podría haber pensado en dibujar la luna con forma de C o con forma de D. Yo he optado por dibujarla con forma de C, por lo que me he centrado en "el lado izquierdo" de la circunferencia.

Con esto nos podemos hacer un esquema con unos ejes de coordenadas donde nuestra circunferencia pasa por los puntos (0, r) (-r, 0) y (0, -r)


Con esta representación las coordenadas x van desde -r hasta 0, las coordenadas y van desde r hasta -r, y podemos usar la ecuación de la circunferencia x^2 + y^2 = r^2  Si sqr(a) es la raíz de a podemos escribir x = sqr (r^2-y^2)

Para ver un caso concreto he tomado una circunferencia de radio 3.

Podemos ir sacando puntos de la circunferencia tomando valores de y y obteniendo valores de x. Así tendríamos:

y=3; x = sqr (3^2-3^2) = sqr (9-9) = sqr(0) = 0 obtenemos (0, 3)
y=2; x = sqr (3^2-2^2) = sqr (9-4) = sqr(5) = -2.23 tomando el valor negativo a conveniencia por interesarnos la parte izquierda de la gráfica
y=1; x = sqr (3^2-1^2) = sqr (9-1) = sqr( 8 ) = -2.82 tomando el valor negativo a conveniencia
y=0; x = sqr (3^2-0) = sqr (9) = -3 tomando el valor negativo a conveniencia
y=-1; x = sqr( 8 ) = -2.82 tomando el valor negativo a conveniencia
y=-2; x = sqr(5) = -2.23 tomando el valor negativo a conveniencia
y=-3; x = sqr(0) = 0 obtenemos (0, -3)

La cuestión ahora es cómo representar esto con asteriscos en la consola. La diferencia entre la consola y unos ejes de coordenadas es que en la consola no podemos trabajar con posiciones de caracteres en supuestas coordenadas reales. La consola sólo nos permite definir si un carácter está en posición uno, dos tres, cuatro etc. pero claro, siempre un número entero.

La consola podríamos verla como una matriz de celdas donde el centro de cada celda se corresponde con un par de coordenadas enteras de los ejes cartesianos.


Con esta idea si colocamos un asterisco en la celda (-3,-3) equivaldría a colocar el asterisco con su centro en el punto (-3,-3)

Para nuestra circunferencia de radio 3 tenemos sólo tres puntos con todas las coordenadas enteras: el (0,3), el (-3,0) y el (0,-3) Pero ¿qué hacemos con el (2, -2.23) y el (1, -2.82) Pues no podemos representarlo en la consola. O al menos no podemos representarlo con exactitud. Como solución aproximada he optado por dibujar el asterisco en el entero más próximo a la coordenada deseada. Así pondré el asterisco en (2, -2) y en (1, -3) y así con cualesquiera valores. De ese modo lo que tenemos que resolver es en qué lugar de cada fila colocar el asterisco.

Para la consola voy a suponer que el rango de coordenadas viene dado en función del radio que el usuario elija para la circunferencia. Así, si el usuario elige radio 3 por ejemplo, la primera coordenada de acuerdo con el esquema planteado es (3, -3) ya que los límites de mi espacio de representación considero que vienen dados por el radio. Si el radio fuera 6 la primera posición sería (6, -6) y así sucesivamente.

Ya pasando a la codificación tendremos que pedir el radio al usuario, recorrer con un for exterior todas las filas de la matriz que se corresponden con las coordenadas y posibles y que en el caso de radio 3 serían 3, 2, 1, 0, -1, -2, -3 que equivale a un (for y=3; y>=-3; y--)

Dentro de una fila tengo que decidir en qué posición pongo el asterisco y esto lo he hecho con una variable stop1 = -round(sqrt(r*r-y*y)); El round me da el entero más próximo. El signo negativo lo tomo a conveniencia ya que la raíz de un número es +- algo y en mi representación me interesa el signo negativo.

Una vez obtenido el stop, recorro las columnas de la matriz de posiciones con un for(x = -(r); x <= 0; x++) parando en cero porque sólo nos interesa media circunferencia. En cada iteración se van colocando espacios hasta llegar a la posición del stop en la fila, y en ese momento insertamos el asterisco. En ese momento si solo quisiéramos dibujar la media circunferencia podríamos hacer un break.

Pero falta dibujar la curva que forma la media luna. Aquí podría hacerse de distintas maneras. Yo he pensado en una curva que pase por (0,r) y (0,-r) y por un punto intermedio entre (-3,0) y (0,0) aunque podría hacerse de otras maneras. La curva podría hacerse con una hipérbola. O con una circunferencia. Si la circunferencia es de igual radio tendríamos que desplazarla, pero además no pasaría por los puntos deseados.


Podríamos solucionarlo eliminando algunos puntos sobrantes o agrandando el diámetro de la circunferencia. Tomando una circunferencia de mayor radio sí podemos hacerla pasar por esos puntos, pero obtener la ecuación de una circunferencia que pasa por tres puntos no es trivial.

Como esto iba complicando todo y no se trata de un dibujo para la NASA, lo más sencillo me ha parecido plantear que la curva para y=0 pase por el punto medio entre el (0, -r) y el (0,0) que es el (0, -r/2). Y como colocando cada asterisco para la forma de la media luna a mitad de distancia podía generarse la forma, pues listo. Lo que tenemos que hacer entonces es definir dos posiciones para asteriscos: el de la media circunferencia stop1 y el que crea la forma de media luna stop2 que está a la mitad: stop2 = stop1/2; y dibujar asteriscos en ambas posiciones, y si no, un espacio en blanco con if (x == stop1 || x == stop2) {printf("*");} else printf(" ");}

El código, para cualquier radio, mucho más simple que toda esta explicación:

Código: [Seleccionar]
#include <stdlib.h>
#include<stdio.h>
#include <math.h>

// Dibujar una media luna con asteriscos lenguaje C
// Ecuación circunferencia x^2 + y^2 = r^2
// https://aprenderaprogramar.com/foros/index.php?topic=7781.0
    int main(){
        //stop1 indica la coordenada x donde debe insertarse el asterisco para una coordenada "y" determinada para el círculo exterior
        // stop2 idem para la curva interior de la luna
        int r, x, y, spc, stop1, stop2;
        printf("Introduzca el radio de la luna: ");
        scanf("%d", &r);

        for(y = r; y >= -r; y--){
                stop1 = -round(sqrt(r*r-y*y));
                stop2 = stop1/2;

            for(x = -(r); x <= 0; x++){
                if (x == stop1 || x == stop2) {printf("*");} else printf(" ");}

        printf("\n");
    }
    }

Saludos

 

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".