First commit 01/01/1993

This commit is contained in:
2021-09-08 21:41:03 +02:00
commit 63fd346c86
12 changed files with 1030 additions and 0 deletions

361
S.C Normal file
View File

@ -0,0 +1,361 @@
/*
Este programa forma parte del Curso de C
Copyright (C) 1991 Grupo Editorial Jackson
Todos los derechos reservados
*/
/* ESPIRAL: dibuja espirales poligonales aleatorias */
/* NOTA: tambi<62>n este fichero, como REBOTE.C, contiene dos programas
distintos, el primero escrito con las funciones gr<67>ficas de Turbo C
2.0 y el segundo con las de Quick C 2.0. La opci<63>n es autom<6F>tica
con una instrucci<63>n #ifdef.
Este sistema comienza a resultar demasiado inc<6E>modo: en la lecci<63>n
E5 se explica c<>mo crear una 'librer<65>a' de funciones gr<67>ficas
port<72>til, parecida a la librer<65>a Jconio, empleada para las funciones
de consola.
*/
/*========================= Versi<73>n para Turbo C 2.0 ======================*/
#ifdef __TURBOC__
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <conio.h>
#include <graphics.h>
/* constantes y variables globales */
#define PAUSA 3 /*3 segundos de pausa entre espirales*/
int maxcol; /*l<>mite de colores*/
int centroX; /*coordenadas del centro de la pantalla*/
int centroY;
double cuadra; /*factor de cuadratura*/
double pi; /*n<>mero pi*/
double grad; /*constante de conversi<73>n grados/radianes*/
/* prototipos de funciones: */
void Espiral(void);
/********************************************************************
* main
********************************************************************/
main()
{
int driver = DETECT; /*elige autom<6F>ticamente*/
int modo;
int dimx,dimy; /*dimensiones pantalla (n<>mero pixels)*/
time_t t;
initgraph(&driver,&modo,NULL); /*inicia gr<67>ficos <1>*/
if (driver < 0) { /*comprueba si ok*/
cputs("\r\n- No se pueden utilizar los"
" gr<67>ficos de este ordenador."); /*sale si no puede*/
exit(1);
}
maxcol = getmaxcolor(); /*color m<>s alto*/
dimx = getmaxx()+1; /*y l<>mites pantalla*/
dimy = getmaxy()+1;
centroX = dimx/2; /*calcula centro <2>*/
centroY = dimy/2;
cuadra = (dimx/(double)dimy)/(4.0/3.0); /*cuadratura <3>*/
pi = 4.0*atan(1.0); /*n<>mero pi <4>*/
grad = pi/180.0; /*constante convers. <5>*/
srand((unsigned int)time(NULL)); /*inicia random*/
while (kbhit()) getch(); /*vac<61>a buffer*/
while (! kbhit()) { /*sale con una tecla*/
Espiral(); /*dibuja una espiral*/
t = time(NULL)+PAUSA; /*espera o tecla <6>*/
while (! kbhit() && time(NULL) < t)
;
}
if (kbhit()) getch(); /*vac<61>a posibles teclas*/
closegraph(); /*vuelve al modo texto*/
}
/* Notas sobre main:
<1> El paso al modo gr<67>fico es id<69>ntico al de REBOTE.
<2> Dado que el n<>mero de pixels es par, no existe un centro exacto.
<3> El factor de cuadratura se utilizar<61> para corregir la dimensi<73>n
horizontal de forma que la figura aparezca con las mismas proporciones
tanto en vertical como en horizontal, independientemente de la forma
de los pixels en un determinado ordenador. Las operaciones con
(double) son necesarias para evitar que dimx/dimy sea una divisi<73>n
entera con p<>rdida del resto.
<4> Aprovechando el hecho de que 45<34> es <20>/4 y que la tangente de 45<34> es
1.0, se puede obtener el valor de pi sin tener que escribirlo.
<5> Es m<>s c<>modo disponer de una constante para convertir entre grados
sexagesimales (una vuelta = 360<36>) y radianes (una vuelta = 2<>).
<6> El tiempo de espera establecido (PAUSA segundos) se interrumpe si el
usuario pulsa una tecla para terminar el programa. Si se desea una
mayor precisi<73>n, se deber<65>a utilizar clock en lugar de time.
*/
/********************************************************************
* Espiral: dibuja una espiral poligonal aleatoria.
********************************************************************/
void Espiral(void) /*<1>*/
{
double r; /*radio*/
double ia; /*incremento <20>ngulo*/
double ir; /*incremento radio*/
double rlim; /*l<>mite radio*/
double s,c; /*seno y coseno actuales <2>*/
double ca; /*coseno anterior*/
double isin,icos; /*incremento seno y coseno*/
int x,y;
rlim = centroY*2.5; /*fija l<>mite*/
ia = (double)((rand()%3600)/10.0); /*extrae incrementos <3>*/
ir = 1.0+(double)((rand()%200)/100.0);
isin = sin(ia*grad);
icos = cos(ia*grad);
r = 0.0; /*parte del centro*/
s = sin(0.0); /*con <20>ngulo 0 grados*/
c = cos(0.0);
setcolor(1+rand()%maxcol); /*y color, no negro <4>*/
cleardevice(); /*borra pantalla*/
moveto(centroX,centroY); /*va al centro*/
while (r < rlim) {
ca = c; /*copia coseno*/
c = c*icos-s*isin; /*nuevo coseno <5>*/
s = s*icos+ca*isin; /*nuevo seno*/
x = centroX+(int)(floor(r*c*cuadra+0.5)); /*nuevas coordenadas <6>*/
y = centroY+(int)(floor(r*s+0.5));
lineto(x,y); /*traza l<>nea*/
r += ir; /*incrementa radio*/
}
}
/* Notas sobre Espiral:
<1> Una espiral poligonal se obtiene girando a velocidad constante
alrededor del centro y aumentando progresivamente el radio. A
intervalos regulares (en t<>rminos de <20>ngulo) se fija un punto y
se une con un segmento rectil<69>neo al punto anterior.
<2> La funci<63>n Espiral usa un truco para no tener que llamar a dos
funciones trigonom<6F>tricas relativamente lentas (seno y coseno) en
cada vuelta. Es posible calcular una sola vez, al principio, las dos
variables isin y icos, y utilizarlas con simples multiplicaciones
para calcular la posici<63>n sucesiva a lo largo de una circunferencia.
<3> La rotaci<63>n se obtiene aumentando en cada vuelta el <20>ngulo actual un
determinado valor (en realidad utilizamos el truco descrito en la nota
2). Ejecutando rand()%3600 se obtiene un valor entre 0 y 3599, y
dividi<64>ndolo por 10.0 se subdivide el <20>ngulo de giro en d<>cimas de
grado: el valor de ia resulta entonces comprendido entre 0.0 y 359.9
grados. El valor de ir (incremento radio) estar<61> comprendido, sin
embargo, entre 1.0 y 2.99.
<4> Extrae un color entre los disponibles, excluido el cero. En el caso
de un monitor monocromo, extrae siempre el blanco.
<5> Este es el atajo utilizado para evitar el c<>lculo en cada vuelta del
seno y el coseno del <20>ngulo actual. No profundizamos en la t<>cnica
trigonom<6F>trica empleada.
<6> La coordenada horizontal se multiplica por cuadra (el factor de
cuadratura) para asegurar unas proporciones 'cuadradas'. Utilizamos
el sistema habitual para aproximar un double al entero m<>s cercano:
a<>adir 0.5 y aproximar con floor al entero inferior. La utilizaci<63>n
de (int) no es estrictamente necesaria, pero muestra sin ninguna
duda que se ejecuta un truncamiento de la parte decimal pasando de
un double a un int (la parte decimal ya era cero, de todas formas,
por el efecto de floor).
*/
/*========================= Versi<73>n para Quick C 2.0 ======================*/
#else
#include <stdlib.h>
#include <stddef.h> /*para definir NULL*/
#include <time.h>
#include <math.h>
#include <conio.h>
#include <graph.h>
/* constantes y variables globales */
#define PAUSA 3 /*3 segundos de pausa entre espirales*/
int maxcol; /*l<>mite de colores*/
int centroX; /*coordenadas del centro de la pantalla*/
int centroY;
double cuadra; /*factor de cuadratura*/
double pi; /*n<>mero pi*/
double grad; /*constante de conversi<73>n grados/radianes*/
/* prototipos de funciones: */
void Espiral(void);
/********************************************************************
* main
********************************************************************/
main()
{
int modos[] = { /*lista de los modos en orden de preferencia*/
_VRES16COLOR, /*VGA 640 x 480*/
_ERESCOLOR, /*EGA color 640 x 350*/
_ERESNOCOLOR, /*EGA monocroma 640 x 350*/
_ORESCOLOR, /*Olivetti 640 x 400*/
_HERCMONO, /*Hercules 720 x 348*/
_HRESBW, /*CGA 640 x 400*/
_DEFAULTMODE /*indica fin de lista*/
};
struct videoconfig v; /*datos del modo de v<>deo actual*/
int dimx,dimy; /*dimensiones de la pantalla (n<>mero pixels)*/
time_t t;
int i;
i = 0; /*inicia gr<67>ficos <1>*/
while (modos[i] != _DEFAULTMODE
&& _setvideomode(modos[i]) == 0) {
i++;
}
if (modos[i] == _DEFAULTMODE) { /*comprueba si ok*/
cputs("\r\n- No se pueden utilizar los"
" gr<67>ficos de este ordenador."); /*sale si no puede*/
exit(1);
}
_getvideoconfig(&v); /*lee datos modo v<>deo:*/
maxcol = v.numcolors; /*color m<>ximo*/
dimx = v.numxpixels; /*l<>mites pantalla*/
dimy = v.numypixels;
centroX = dimx/2; /*calcula centro <2>*/
centroY = dimy/2;
cuadra = (dimx/(double)dimy)/(4.0/3.0); /*cuadratura <3>*/
pi = 4.0*atan(1.0); /*n<>mero pi <4>*/
grad = pi/180.0; /*constante convers. <5>*/
srand((unsigned int)time(NULL)); /*inicia random*/
while (kbhit()) getch(); /*vac<61>a buffer*/
while (! kbhit()) { /*sale con una tecla*/
Espiral(); /*dibuja una espiral*/
t = time(NULL)+PAUSA; /*espera o tecla <6>*/
while (! kbhit() && time(NULL) < t)
;
}
if (kbhit()) getch(); /*vac<61>a posibles teclas*/
_setvideomode(_DEFAULTMODE); /*vuelve al modo texto*/
}
/* Notas sobre main:
<1> El paso al modo gr<67>fico es id<69>ntico al de REBOTE.
<2> Dado que el n<>mero de pixels es par, no existe un centro exacto.
<3> El factor de cuadratura se utilizar<61> para corregir la dimensi<73>n
horizontal de forma que la figura aparezca con las mismas proporciones
tanto en vertical como en horizontal, independientemente de la forma
de los pixels en un determinado ordenador. Las operaciones con
(double) son necesarias para evitar que dimx/dimy sea una divisi<73>n
entera con p<>rdida del resto.
<4> Aprovechando el hecho de que 45<34> es <20>/4 y que la tangente de 45<34> es
1.0, se puede obtener el valor de pi sin tener que escribirlo.
<5> Es m<>s c<>modo disponer de una constante para convertir entre grados
sexagesimales (una vuelta = 360<36>) y radianes (una vuelta = 2<>).
<6> El tiempo de espera establecido (PAUSA segundos) se interrumpe si el
usuario pulsa una tecla para terminar el programa. Si se desea una
mayor precisi<73>n, se deber<65>a utilizar clock en lugar de time.
*/
/********************************************************************
* Espiral: dibuja una espiral poligonal aleatoria.
********************************************************************/
void Espiral(void) /*<1>*/
{
double r; /*radio*/
double ia; /*incremento <20>ngulo*/
double ir; /*incremento radio*/
double rlim; /*l<>mite radio*/
double s,c; /*seno y coseno actuales <2>*/
double ca; /*coseno anterior*/
double isin,icos; /*incremento seno y coseno*/
int x,y;
rlim = centroY*2.5; /*fija l<>mite*/
ia = (double)((rand()%3600)/10.0); /*extrae incrementos <3>*/
ir = 1.0+(double)((rand()%200)/100.0);
isin = sin(ia*grad);
icos = cos(ia*grad);
r = 0.0; /*parte del centro*/
s = sin(0.0); /*con <20>ngulo 0 grados*/
c = cos(0.0);
_setcolor(1+rand()%maxcol); /*y color, no negro <4>*/
_clearscreen(_GCLEARSCREEN); /*borra pantalla*/
_moveto(centroX,centroY); /*va al centro*/
while (r < rlim) {
ca = c; /*copia coseno*/
c = c*icos-s*isin; /*nuevo coseno <5>*/
s = s*icos+ca*isin; /*nuevo seno*/
x = centroX+(int)(floor(r*c*cuadra+0.5)); /*nuevas coordenadas <6>*/
y = centroY+(int)(floor(r*s+0.5));
lineto(x,y); /*traza l<>nea*/
r += ir; /*incrementa radio*/
}
}
/* Notas sobre Espiral:
<1> Una espiral poligonal se obtiene girando a velocidad constante
alrededor del centro y aumentando progresivamente el radio. A
intervalos regulares (en t<>rminos de <20>ngulo) se fija un punto y
se une con un segmento rectil<69>neo al punto anterior.
<2> La funci<63>n Espiral usa un truco para no tener que llamar a dos
funciones trigonom<6F>tricas relativamente lentas (seno y coseno) en
cada vuelta. Es posible calcular una sola vez, al principio, las dos
variables isin y icos, y utilizarlas con simples multiplicaciones
para calcular la posici<63>n sucesiva a lo largo de una circunferencia.
<3> La rotaci<63>n se obtiene aumentando en cada vuelta el <20>ngulo actual un
determinado valor (utilizamos el truco descrito en la nota 2).
Ejecutando rand()%3600 se obtiene un valor entre 0 y 3599, y
dividi<64>ndolo por 10.0 se subdivide el <20>ngulo de giro en d<>cimas de
grado: el valor de ia resulta entonces comprendido entre 0.0 y 359.9
grados. El valor de ir (incremento radio) estar<61> comprendido, sin
embargo, entre 1.0 y 2.99.
<4> Extrae un color entre los disponibles, excluido el cero. En el caso
de un monitor monocromo, extrae siempre el blanco.
<5> Este es el atajo utilizado para evitar calcular en cada vuelta el
seno y el coseno del <20>ngulo actual. No profundizamos en la t<>cnica
trigonom<6F>trica empleada.
<6> La coordenada horizontal se multiplica por cuadra (el factor de
cuadratura) para asegurar unas proporciones 'cuadradas'. Utilizamos
el sistema habitual para aproximar un double al entero m<>s cercano:
a<>adir 0.5 y aproximar con floor al entero inferior. La utilizaci<63>n
de (int) no es estrictamente necesaria, pero muestra sin ninguna
duda que se ejecuta un truncamiento de la parte decimal pasando de
un double a un int (la parte decimal ya era cero, de todas formas,
por el efecto de floor).
*/
#endif /*fin opci<63>n Turbo C/Quick C*/