Menú

Mostrar Mensajes

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

Mostrar Mensajes Menú

Mensajes - Serapis

#2331
De entrada, decirte que éste es el foro de vb6, el de NEt está mas arriba... pero bueno ya lo moverá algún moderador si se percata de ello.

También señalarte que con las etiquetas Geshi, has hecho la mitad, le has puesto el 'code', pero te falta asignarle al VBNET, desplegando el combo, s epuede buscar. No se indica el lenguaje específico, cuando no sigue ningún lenguaje esecífico, pero si es así, es preferible usarlo, porque se colorea basado en su sintaxis y resulta más cómodo de leer...



Iba a ir al asunto que trata, pero visto lo visto, procede primero una larga crítica sobre aspectos que conviene usar correctamente...

Por ejemplo la forma de nombrar variables y métodos, más que nada para enseñarte a hacerlo correctamente....

- Una varible, propiedad, debe llevar por nombre SIEMPRE lo que en la gramática del español se llama NOMBRE COMUN.... porque son eso, nombres... Valor, Temperatura, Edad, Año, etc... En cambio si son constantes (valores preconfigurados, conviene además que lleven un adjetivo. Ejemplo: ColorRojo= hex0000FF ColorAzul= HexFF0000)
- Los métodos, en cambio son verbos... Imprimir(esto)... Ordenar(lalista)... Añadir(UnItem)... Vaciar(), etc...
- Aunque el lenguaje lo admita, no uses las barras bajas para dar nombres a tus variables, en general se deben dejar para las constantes y sobretodo son usados por los eventos de objetos instanciados...
...que el propio lenguaje crea así. Como una medida de evitar en lo posible la coincidencia con métodos que los usuarios pudieran tener... Aunque es harto difícil que un método que uno cree venga a llamarse igual que la suma de un "nombre instancia de objeto" + "nombre de evento del objeto instanciado", no es infalible.... siguiendo la norma de "nombre instancia de  objeto" + "_" + "nombre evento", se puede garantizar la ausencia de duplicidad de nombres de métodos y con ello la conflictividad, pero solo si a cambio el propio programador se aplica su parte no usando barras bajas en los nombres.

Usar nombre, no usar verbo ni barra baja, en nombres de variables, propiedades, etc...
CitarDim ingrese_butacas As Byte
Dim CantidadButacas as Byte ' o también CantidadButacasReservadas

Usar verbo, no nombre ni barra baja en nombres de métodos y funciones.
CitarSub Ingreso_butacas(...)
Sub IngresarButacas(...)

Luego está línea es muy deficiente:
Código (vbnet) [Seleccionar]
Ingreso_butacas("Ingrese numero de butacas a reservar: ", ingrese_butacas)
Aparte del nombre del método ya comentado y de la variable pasada en el segundo parámetro... resulta que no precisa ser pasado ningún parámetro.
El primero porque si el método va a recibir siempre la misma cadena de texto, ese parámetro (el texto), puede yacer en el propio método, no perdiendo tiempo en pasarlo desde fuera, además se aísla más claramente el método y si a futuro hay que cambiar el texto, basta buscar la función y cambiar el texto ahí... ahora si decides cambiar el texto y el método es llamado desde 20 sitios, tendrías que cambiarlo en los 20 sitios).
El segundo parámetro también sobra... a la entrada siempre es 0 y es usado para devolución (por referencia), y como es un método y por tanto no devuelve nada, lo razonable es que se convierta en una función y devuelva dicho valor...

Luego esa línea y el propio método serán cambiados mucho mejor así:
Código (vbnet) [Seleccionar]
CantidadButacas = IngresarButacas()

private function IngresarButacas() as byte
   dim msj as string = "Ingrese numero de butacas a reservar: "
   Dim cantidad as byte  ' ingreso
 
    ' ...
   ' ....

  Devolver cantidad
End function


La siguiente crítica es que siempre que se solicita a un usuario un valor, un algo en general, debe dársele la oportunidad de cambiar de opinión o corregir/confirmar... imagina que quisera poner 4, pero por error hubiera tecleado 44 (a veces la pulsación de teclas tienen un tiempo de repetición inesperado por el usuario, y sin darse cuenta su pulsación genera dos pulsaciones.... que le exigen por ejemplo tener que introducir 44 nombres, DNIs, (que ni siquiera tiene, ni sabe), etc... sería inaceptable... imagina si introduje 4444...
En tu caso, como limitas a 4 el valor máximo, por ahí corriges cierta parte, pero todavía dejas al aire si pone 0...

Con esas ideas en mente, rediseñamos, la función para ser más coherente y certera con la propia realidad cotidiana.

Código (vbnet) [Seleccionar]
private function IngresarButacas() as byte
   dim msj1 as string, msj2 as string  
   Dim cantidad as byte  ' ingreso
   Dim Confirmacion as boolean

   msj1 = "Ingrese numero de butacas a reservar (máximo 4, 0 para abortar) "  
   msj2 = "Confirme si está de acuerdo con el valor ingresado (0=Cambiar, 1=Conforme)" ' el valor se ve en la consla justo en la línea previa
   Do
       Do
           Console.WriteLine(msj1)
           cantidad = Console.ReadLine()
       Loop While (cantidad > 4)
       Console.WriteLine(msj1)
       Confirmacion = (Console.ReadLine()  =  1)
   Loop while Confirmacion=false

   Return Cantidad
End function


A la devolución de la función debes verificar si el valor devuelto es 0 (Abortar), en cuyo caso se sale de la función y no se hace nada más.
Si un valor 0 no es admisible, en el bucle dentro de la función debe condicionarse a repetirse "While ((Cantidad=0) or ( Cantidad>4)) "   (tambien "Until ((cantidad>=1) and (Cantidad<=4)) " )

Lo siguiente es que si se debe obtener los DNI, se aproveche la misma función para solicitarlo...
Naturalmente entonces ahora procede cambiar el nombre de la función para que qrefleje mejor lo que hace: IngresarDatos o mejor aún ReservarEntradas

Otro punto a resolver es que si se aportan más de un DNI, no hay ningún sustrato para almacenarlos, es decir el nuevo valor entrado sobrescribe el valor previo... Si la cantidad máxima de reserva es 4, procede declarar un array de 4 elementos a nivel del módulo (es un valor pequeño, no hay problema en ocupar algo más de espacio, si a cambio nos resuelve cuanlquier número entre 1 y 4 ).

Código (vbnet) [Seleccionar]

private dim Identificaciones(0 to 3) as uint32

private function IngresarDatos() as byte
   dim msj1 as string, msj2 as string, msj3 as string  
   Dim cantidad as byte  ' ingreso
   Dim Confirmacion as boolean
   dim i as byte, j as byte, k as byte  

   msj1 = "Ingrese numero de butacas a reservar (máximo 4, 0 para abortar) "  
   msj2 = "Confirme si está de acuerdo con el valor ingresado (0=Cambiar, 1=Conforme)"
   msj3 = "Ingrese DNI persona  {0}  (un valor positivo mayor que 0)"

   ' 1º Ingresar cantidad de butacas...
   Do
       Do
           Console.WriteLine(msj1)
           cantidad = Console.ReadLine()
       Loop While (cantidad > 4)
       If Cantidad = 0 ) then exit function ' ABORTAR....

       Console.WriteLine(msj2)
       Confirmacion = (Console.ReadLine()  =  1)
   Loop while (Confirmacion=false)
   
   ' 2º Ingresar DNI
   for i= 0 to cantidad-1
       do
           do
               Console.WriteLine(msj3, i)
               k = Console.ReadLine()  '
           loop while  (k<1)  ' se exige que sea positivo y razonablemente mayor que 0

           ' Verificamos que no esté repetido (comprobando con los valores anteriores ya entrados
           Confirmacion = TRUE
           for j= 0 to i-1
               if (k = Identificaciones(j) ) then
                   Confirmacion = FALSE
                   exit for
               end if
           next            
       loop While (Confirmacion=False) ' se vuelve a preguntar mientras se repita el valor entrado...

       Identificaciones(i) = k
   next

   Return Cantidad
End function




Respecto de la segunda parte, declaras como se reparte el teatro, pero no señalas que pide el problema...



Y en cuanto a la última cuestión...
Cuando algo es lineal y finito suele recurrirse a un array.
Si las eliminaciones e inserciones serán contínuas, redimensionar un array constantemente no es admisible a tales casos se suele usar listas enlazadas, donde las inserciones y eliminaciones tienen un coste fijo y admisible.
Si las búsquedas priman sobre el resto, debe considerarse que métodos se disponen para proveer solución rápida, para textos y sobretodos cuando son en cantidad enorme, una tabla hash, es iremplazable, el coste de búsqueda es unitario al de acceso aleatorio en un array + el tiempo de hashear el texto a buscar.
Nuevamente si la cantidad es pequeña, un array puede valer, pero redimensionar 1 millón de elemtnos cada vez que se añade o elimina no es práctica... para cantidad pequeñas vale.
Una técnica con arrays es declarar un tamaño mínimoy cuando se alcanza duplicarlo, pero eaunque es válido para añadidos, noes igualmente válido si hay eliminaciones.

Cuando los datos a almacenar son algo más complejos que un simple datos suele recurrirse a una simple estructura que mantenga los datos, en tu caso del ejemplo dado es lo más apropiado.
Código (vbnet) [Seleccionar]

private structure DatosButaca
   DNI as uint32
   Butaca as short 'si están numeradas del 1 al x vale un número, si tiene fila y asiento, lo siguiente
   ' Usa butaca o esto de aquí abajo, no ambas cosas
   Fila as byte
   Asiento as Byte
end structure

Bin CantidadReservas as byte
Dim Entradas(0 to 3) as DatosButaca  ' aunque se declaren 0 a 3, solo se ocupan la cantidad que señala 'CantidadReservas


Si los datos requieren cierta manipulación, la propia estructura puede contener métodos para adecuar los datos...

Cuando los datos van a precisar ciertos métodos genéricos (como ordenar), puede recurrirse a colecciones genéricas o específicas que reúnan los cometidos que precisamos... no puede darse una indicación precisa, porque cada caso debe tratarse y considerarse individualmente.

Si los datos serán bastante complejos y los métodos de las colecciones nos resultan inútiles (no los vamos a usar), o bien los queremos usar, pero no se adecúan al modo en que precisamos, toca crearse una clase que albergue el tipo de datos específico y dotarle de métodos propios, incluso una clase que sea una colección y que almacene tipos primarios (array), estructuras, clases... e incluso si una colección se aproxima a lo que queremos hacer si la colección deja extender métodos, podríamos crear tales métodos y para el resto (inserciones, eliminaciones, búsquedas, cuenta, iterar) utilizar los métodos extendidos (ésto último suele ser a menudo más rápido que construir una colección propia desde cero...

El punto d epartida siempre ha de ser el array, y si no resulta suficiente ver si un array de estructuras, etc...
En fin, no puede darse una regla genérica, solo aproximaciones, orientaciones, pero cada caso debe estudiarse según sus propias circunstancias... cantidades que puede albergar, concurrencia de acceso a ítems, si prolifran las búsquedas, las inserciones, las eliminaciones... el tipo de datos/datos almacenados y qué se va a hacer con tales datos... aunque las colecciones suelen compartir métodos comunes, cada cual tiene sentido explícito para ciertas cosas  y otras para otros (si no para qué hacer distintas implementaciones)...

Para saber sobre cada cual de las colecciones, lo mejor es visitar la página de Mocosoft (MSDN)... y leer, que para eso está... carece de sentido hacer un copy-paste de allí, ni tampoco tiene sentido que uno tenga que hacer un resumen de cada colección... el trabajo de aprendizaje exige leer por tu cuenta y no que te den todo mascado de 'segunda mano'...

Si aclaras que te reclama el problema en la segunda parte, miro de hecharte un pequeño cable...
#2332
A veces llega algún usuario, al que resulta extremadamente difícil de ayudar, por varias razones...

- La primera es porque tiene conocimientos excesivamente sesgados (de algunas cosas parece tener cierto conocimiento y de otras cosas simples, lagunas completas).
- Quieren que las cosas se ajusten a su modo de hacer, cuando lo inevitable que es que para algo existente sea 'el nuevo' el que deba adaptarse a lo que hay.
- Insisten en lo que creen entender, sin meditar las respuestas que se les dan... pasan por encima (si es que las leen), como aquel que pisa una alfombra que está ahí para ser pisada.
- Muchas más razones, pero no quiero extenderme, ni tampoco pretendo que nadie se sienta ofendido...

El caso es que tú encajas en este tipo de usuarios, donde la dificultad, no radica en lo que se pide (que es relativamente fácil) si no en hacer entender lo que se dice...
Es como dar las respuestas correctas a alguien que luego tomará tu texto, lo traducirá al chino, luego al hebreo, luego al latín luego al ruso, luego al inglés, luego al estonio, luego al portugués y al final de nuevo al español, para luego intentar digerirlo... se perderá todo el sentido tras tanta traducción, siempre sucede de un idioma a otro, luego cuantas más atraviese, más distancia existirá entre el original y la traducción final, de hecho puede que al final, no tenga nada que ver con el original y hasta haya dificultades para saber qué tema trataba.

Intentaré por última vez, arrojar un poco de luz en tu oscuridad y me conformaré solo con que intentes entenderlo, sin más pretensiones, que luego avances a partir de ahí o sigas en tu luna es cosa tuya...



1 - Los paréntesis también son operadores (no los ignores).
Igual que '+' es para una operación aritmética y 'and' para una operación lógica, un paréntesis aplica una operación de 'prioridad' (orden de ejecución).
Es una lástima que en prácticamente ningún lenguaje se describa así... como un operador de prioridad. Quizás porque todo parte de un cuerpo matemático, en el que se da por sentado que todo el mundo que pretende aprender algo de programación tiene al menos una base matemática mínima... o dicho de otro modo, que no se considera necesario explicarlo porque se da por sobreentendido.

2 - Es bueno aprender (en realidad si uno estudió, recordar, porque es algo que puede olvidarse), el significado de las propiedades (conceptos mtemáticos): distributivas (que reparten), conmutativas, asociativas (que conecta, que lo une...). Explicadode forma matemática puede llegar a entenderse, o puede ser complejo si se le da todo el cuerpo matemático lleno de término que quien lo oye también desconoce...

Una sencilla forma de entenderlo, es que en programación los operadores lógicos cumplen dichas funciones, y particularmente resultan mucho más fácil de entender (el cuerpo matemático, al final solo es entendible por otros matemáticos, a causa de la excesiva jerga verborreica que se emplea sin ton ni son, ni tregua de ningún tipo en las matemáticas (no en todas partes eso sí), en programación hay cierta licencia, gracias a que hay muchos programadores que son autodidactas.
Tampoco se puede caer en 'describo todo con mi propio lenguaje', porque entonces no nos entenderíamos. Habría tantas formas de llamar a algo como personas y eso tampoco puede ser... ambos extremos incurren en ineficacia.

3 - Los paréntesis... tu pelea.
Citar
CitarCualquier lenguaje por miserable que sea, admitirá paréntesis para resolver la precedencia de operadores (debe importarte nada que un operador sea 'or', 'and' ó '+', '/', o cualquier otro... un operador es un operador sea del tipo que sea y a tí debe bastarte con saber que como tal cualquier operador tiene un valor de precedencia (prioridad en ser resuelto cuando no tiene paréntesis que lo delimite)

Si es tan simple como dices, entonces bárbaro, pero yo no sabía y antes de hacer la prueba menos.
De hecho había planteado este tema a un programador que conozco y me dijo que la interpretación dependía del lenguaje, que no había una respuesta única. Tú mismo también me preguntaste por mi lenguaje como si fuese relevante.

Para ayudarte a entender mejor los paréntesis, voy a partir de exponer un ejemplo práctico asequible de entender para todo el mundo, y luego desde ahí, hacer una traslación al asunto programático, y espero que entonces (al menos), acabes de otorgarle la importancia que merece... y por lo tanto aplicarlo, en vez de querer matarlo (obviarlo).

Mira de construir tu árbol genealógico (basta con 10-20 nombres, es suficiente para darte la idea): Podrás escribir tu nombre y al lado, el de tus hermanos, y encima el de tus padres... tu padre y tu madre también tendrán (se supone) hermanos, luego procede ponerlos, a su vez también cada uno de ellos tendrán ó tuvieron su padre y madre respectivamente...
No importa cuan detallado sea el árbol genealógico, puedes imaginártelo elaborado con flechitas, o mas prosaico en columna, algo similar a esto:


Pedro Eva
   Juan Rosa
       Fermin Raquel
       Antonio
       Rosa Fernando
       Felipe
   Luis Encarna
       Daniel Sara
           Enrique
           Daniela Fabian
               Rosa
               Joaquin
           Evaristo
   Maria
   Andres Rocio
   Ana Martin
       Luis
       Antonio
       Marta Rafael
           Ines
           Francisco
           Miguel Maria
               Sonia
               Miguel
               Felipe


Como se puede entender de un simple vistazo, bajo cada pareja yacen los hijos que tienen, los 'casados' nuevamente tienen pareja, y si tienen hijos bajo ellos aparece la lista.

Veamos como queda si los ponemos en línea:
Pedro Eva Juan Rosa Fermin Raquel Antonio Rosa Fernando Felipe Luis Encarna Daniel Sara Enrique Daniela Fabian Rosa Joaquin Evaristo Maria Andres Rocio Ana Martin Luis Antonio Marta Rafael Ines Francisco Miguel Maria Sonia Miguel Felipe

Se pueden poner en columna igualmente:

Pedro
Eva
Juan
Rosa
Fermin
Raquel
Antonio
Rosa
Fernando
Felipe
Luis
Encarna
Daniel
Sara
Enrique
Daniela
Fabian
Rosa
Joaquin
Evaristo
Maria
Andres
Rocio
Ana
Martin
Luis
Antonio
Marta
Rafael
Ines
Francisco
Miguel
Maria
Sonia
Miguel
Felipe


¿Eres capaz en esta lista de determinar quienes son los hijos de quién?. Imposible... Incluso basado en la idea de que detrás de un hombre aparece su pareja (y viceversa), no hay ningún indicador de relación, podría ser hermano y hermana o hermana y hermano....
En cambio, fíjate como en el árbol jerárquico, no hay lugar a dudas quien es hijo de quien.
Bueno, esta lista de nombres equivale a 'tus' expresiones, y la lista jeráquica a una expresión expresada con paréntesis... luego vuelvo a esto... ahora otro ejemplo, de naturaleza más cercana a la programación...

Mira el menú de la calculadora (de win2). Este es su menú (te lo pongo en inglés):

(Menu)
   Edit
       Copy
       Paste
   View
       Standard
       Scientific
       -
       Hex
       Decimal
       Octal
       Binary
       -
       Qword
       Dword
       Word
       Byte
       -
       Digit Grouping
   Help
       Help topics
       -
       About Calculator


Nuevamente puede verse con claridad, que ítems están bajo que otros ítems.
nota: Los ítems Qword... aparecen si se seleccionó: binary, Octal ó Hex, si se elige Decimal aparece Grados, Radianes...

Pongámoslo en columna sin indentacion (o en línea da igual):


Menu
Edit
Copy
Paste
View
Standard
Scientific
-
Hex
Decimal
Octal
Binary
-
Qword
Dword
Word
Byte
-
Digit Grouping
Help
Help topics
-
About Calculator



Igualmente cuando se ponen en columna son una lista sin concierto, todos al mismo nivel son hijos de... pero no se oberva ninguna relación más entre ellos, todos del mismo orden.

Se puede mejorar aún el menú jerárquico a base de poner indicadores de inicio y fin... en muchos menús (la mayoría) no se ponen porque al ocupar espacio, aumenta el área visible que ocupan...
...dando algo con sentido que solo inicio, podría ser algo como esto:


Menu
   Edit
       Portapapeles
           Copy
           Paste
       Fin menu
   View
       Modelo
           Standard
           Scientific
       Fin grupo
       Base numérica
           Hex
           Decimal
           Octal
           Binary
       Fin grupo
       Tipos de datos
           Qword
           Dword
           Word
           Byte
       Fin grupo
       Otros
           Digit Grouping
       Fin grupo
   Help
       Ayuda
           Help topics
       fin grupo
       Autoria
           About Calculator
       Fin grupo
Fin menu



Igualmente podemos proceder con el árbol genealógico, encabezando el padre, y debajo indentado los hijos y terminando con el nombre de la madre (precedido por ejemplo por 2 puntos), a modo de: fin grupo - fin menú.

Si encabeza un hombre, él es el hijo, y por tanto la mujer que cierra los hijos es su cónyuge, en cambio si la lista encabeza por una mujer, es la mujer la descendiente de la familia, y quien cierra la lista de hijos será el hombre, su cónyuge. Si no tienen hijos, solo aparece el nombre del cónyuge...

...a reconstruir el árbol de esta manera:  


Pedro
   Juan
       Fermin
       :Raquel
       Antonio
       Rosa
       :Fernando
       Felipe
   :Rosa
   Luis
       Daniel
           Enrique
           Daniela
               Rosa
               Joaquin
           :Fabian
           Evaristo
       :Sara
    :Encarna
   Maria
   Andres
   :Rocio
   Ana
       Luis
       Antonio
       Marta
           Ines
           Francisco
           Miguel
               Sonia
               Miguel
               Felipe
           :Maria
       :Rafael
   :Martin
:Eva


Ahora puede parecer un poco más lioso de verlo pero al programarlo se podrá buscar recursivamente, mientras esté un nivel más abajo (a la derecha), es hijo. Mientras se mantiene el nivel se suma, cuando cambia el nivel, si sube se hace otra llamada, como padre el actual, los que se devuelvan serán sus hijos, si baja un nivel, se devuelve la cantidad de hijos -1 (se terminó de contar y el último erá el cónyuge).

Bien, todo esto parece no tener nada que ver con tu problema, pero no es así... pese a quien pese y pese a que muy poca gente lo perciba, las expresiones son árboles jerárquicos... en cambio tus expresiones son solo listas...

Vamos a demostrarlo...

z= A + 3 * 5 - B + W / 5 AND T - 2 + X OR P OR H
Podemos obviar los operadores (nos quedamos con los identificadores y las constantes numéricas)y pongámoslos en columna:

Z
A
3
5
B
W
5
T
2
X
P
H

Como se ve es una lista plana, todos al mismo nivel, todos 'hijos' de un supuesto padre... como tus expresiones.

Añadamos paréntesis.... y veremos que pasa...
Supongamos que esta fuera la exresión:
Z = (A + 3) * ((((5 - B) + W) / 5) AND ((T - 2) + X) OR (P OR H))
Ahora pongámoslo en vertical jerárquico (obviando también los operadores, excepto los paréntesis):


Z (
   A
   3
   )
   (
       (
           (
               (
               5
               B
               )
           W
           )
       5
       )
       (
           (
           T
           2
           )
       X
       )
   (
   P
   H
   )
)



Et voilá, eliminando los operadores, esto es dejando el único que al caso importa, puedes ver que subyace una jerarquía... la apertura de paréntesis y cierre delimitan la propia jerarquía, el orden de ejecución... el últérrimo hijo de la descendencia, es el primero que debe ser resuelto, luego el padre, luego el abuelo, etc...

Espero que ahora veas claramente adonde lleva no usar paréntesis. Su uso cordina, da sentido específico...
Igual que si indentas un hijo en otra parte supone que les estás asignando un padre distinto (hijo de su hermano, o nieto, o tío de su hermano, o abuleo de su hermano y padre dle suyo propio), del mismo modo colocar un paréntesis en sitio equivocado cambia el sentido (y el resultado) de la expresión... y del mismo modo que un nieto siempre tendrá padres, es adecuado que ciertos operandos estén entre paréntesis... si deben ejecutarse antes.
También se puede ver que un arbol jerárquico puede ser expresado en línea, y mantiene plenamente su sentido, siempre y cuando sea 'canonizado' con cierres y aperturas, que es lo que hemos hecho anteriormente con el menú de la calculadora y con el árbol geneálogico.

Iguala tu expresión a la lista genealógica, sin pies ni cabezas, sin saber quien es padre y quien es hijo.
Te decía en otro mensaje más arriba, que otra forma es separar una expresión en las subexpresiones que las componen, de modo que sean simples... pero eso da bastante trabajo y tampoco limita la posibilidad de error por confusión...
Observa la genealógica:
Pedro Juan Luis Maria andres Ana Eva
El primer cónyuge es el que aparece en primer lugar, el otro cónyuge el último y en medio los hijos.


Pedro Juan Luis Maria andres Ana Eva
Juan Fermin Antonio Rosa Felipe Rosa
Fermin Raquel
Antonio
Rosa Fernando
Felipe
Luis Daniel Encarna
Daniel Enrique Daniela Evaristo Sara
Daniela Rosa joaquin Fabian
Maria
Andres Rocio
Ana Luis antonio Marta Martin
Luis
antonio
Marta Ines Francisco Miguel Rafael
Miguel Sonia Miguel felipe Maria

Es decir desmontando cada expresión con su propios términos, no requiere paréntesis, pero puedes ver como crece la cantidad de expresiones. Una vez resueltas las subexpresiones, pueden volver a crearse nuevas expresiones con los resultados previos...  hasta llegar a la raíz (la asignación en programación).

La otra forma como ya he expresado varias veces es la notación polaca (no 'el polaco', ni 'en polaco', no es un idioma notación quiere decir "forma, sistema que se usa para expresar conceptos más o menos abstractos", el tipo que lo ideó era polaco, eso sí...).
Usando la notación polaca, no es ni más ni menos que para poder hacer los cálculos ya directamente sin tener que volver a buscar el orden... losd compiladores lo usan, porque al compilar, lo hará de tal forma que la expresión se vaya ejecutando (correctamente) avanzando hacia adelante, sería una caída de rendimiento si tras compilar, cada vez que se evaluara una expresión tuviera que localizar el orden para ejecutarla correctamente... el compilador lo hace una vez y cuando de traduzca a código máquina, ya estará listo, no requiere posterior toqueteo, solo ejecutar...

Resumiendo, no puedes vivir sin paréntesis, la notación polaca primero debes dominarla, pero si te cuesta entender los paréntesis, no es el momento de intentar profundizar en dicha notación...

CitarYo creo que tendría que hacer lo inverso: Que el programa genere expresiones en polaco y luego las transforme a normal sin paréntesis. Porque el problema que quería evitar es que las generadas tengan paréntesis, porque no sé cómo hacer eso bien
...
Porque quiero que las expresiones las genere un programa. Hacer que genere Variable1 Comparador1 Variable2 Operador1 y así todo lo que quiera, es fácil, pero si quisiera hacer que ponga paréntesis por ahí no tengo mucha idea
Es que no sé para que lo necesitas... por lo que alcanzo a entender de como te explicas es que tienes alguna función que 'genera' operandos y operadores (ignoro si al azar o si basado en algo específico)... entonces dado lo poco que he leído respcto de lo que intentas hacer, intuyo que tu programa también debe generar los paréntesis, porque como ya te señalé en el punto 1, y como me he extendido en explicaciones a lo largo de la respuesta, son operadores de prioridad, o si quieres jerárquicos (si se entiende como un árbol), cada paréntesis de apertura aumenta (profundiza) la jerarquía y cada cierre la reduce...

Nota como todos los lenguajes tiene términos o símbolos cuyo único objetivo es precisamente jerárquico, abrir o cerrar expresiones, anidamientos, etc... en C por ejemplo, un comedero de cabeza para los principantes es olvidarse de terminas las expresiones convenientemente con ';' en la mayoría d  lenguajes, el salto de línea es un indicador explícito de fin de una expresión, en C, una expresión continua en varias líneas hasta qwue encuentre dicho símbolo... (el punto y coma). Cada lenguaje tiene su propia convención, pero tiene dichos delimitadores...

CitarAcordate además que cuando inicié este tema ni siquiera sabía eso del orden de procedencia o sea que para mí era un lío mayor que ahora.
Espero que con los ejemplos explícitos que te he expuesto más arriba, puedas finalmente entender la utilidad de la prioridad, la relación de 'inclusión, pertenencia o jerarquía (es todo lo mismo visto bajo diferente prisma). si para una expresión puede ser complejo entenderlo, en cambi sobre un menú, o más cercano un árbol genealógico, es imposible no entender que si no se define debidamente donde empieza y termina los hijos, la confusión es total... Aquí se ha seguido una forma simple y luego la hemos canonizado (se llama canonizar a no omitir nada aunque sea 'sobreentendido', por ejemplo canonizar la frase 'Trabajo el martes', sería: No trabajo el lunes, trabajo el martes, no trabajo el miércoles, ni el jueves, ni el viernes ni el sábado ni el domingo). los hijos quedan encerados en un nivel (+1) indentado entre el padre y la madre, en realidad, los 2 puntos se pueden omitir, si hay indentación el siguiente que aparezca en el mismo nivel será el cónyuge, pero por claridad a veces conviene añadir símbolos, así de un simple vistazo, se acota rápido... (es decir por comodidad 'humana', no estrictamente necesario matemáticamente hablando).

Citar
CitarHay 3 tipos de notaciones básicas:
Notación de infijo (o normal): Las que solemos usar, porque las entendemos bién al 'leerlas', los operadores aparecen a ambos lados y el operador en medio.
Ejemplos: A + B;  (A*B)+(C-(D*E)) <-- nota que los ejemplos son los mismos para los 3, para que veas las diferencias).
Notación de prefijo (o polaca): Los operadores van delante, los operadores detrás.
Ejemplos: +AB; +*ABC-*DE  
Notación de sufijo (o postfijo, inversa):Los operandos van delante, los operadores al final.
Ejemplos: AB+; AB*C+DE*-

Lo decía por:...
Ok, sí. Lapsus mío, pero se deduce que si hay tres espacios y he señalado el centro, y un lado, el del lapsus será el otro lado.  No tiene más importancia.

Citar
CitarXOR no es más complejo que OR ni AND, sino a su mismo nivel...

Tabla de verdad de XOR
----------------------------
0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0

En resumen es TRUE si solo una de ellas es TRUE. Si se aplica a más de 2 operandos es TRUE, si el número de evaluaciones TRUE es impar, FALSE si son pares...

1 xor 1 xor 1 xor 1 = 0   (4 unos, son pares luego = FALSE)
1 xor 1 xor 1 xor 0 = 1   ( 3 unos, son impares luego es = TRUE)

XOR te puede ahorrar muchas comparaciones..
Me parece más difícil de entender que los otros operadores, pero con lo último que dices tendré que ver.

No creas, es cuestión de práctica...En realidad suple a esta otra expresión:
Z = (Not(A) or B) and (A or Not(B))
Imagina que tienes un un valor para activar y desactivar algo.
Si quieres encenderlo harías algo como:
Enabled = TRUE
Si quieres apagarlo:
Enabled = FALSE
Pero si simplemente quieres poner el estado opuesto, puedes poner:
Enabled = Enabled xor TRUE
En realidad equivale a: Enabled = Not(enabled)
...pero ojo, el not es válido solo porque estamos trabajando con un valor buleano... un valor buleano es un valor donde todos sus bits se comportan como si fueran un único bit.
En cambio si tienes un valor que noe s buleano, el resultado de XOR y NOT, es muy disitnto... con NOT invierte cada bit por el contrario, con XOR solo se invierte si el bit aparece una sola vez (en A o en B)
Not(0011.1010 ) = 1100.0101
0011.1010 xor
1010.1101
-----xor------
1001.0111
Como se ve da un valor muy distinto a los operandos de origen... Xor en realidad es muy interesante se comporta como una suma o como una resta, según el valor de ambos operandos...

Con práctica y tiempo, que consigas entenderlo bien, XOR se volverá un 'amigo invalorable'...
#2333
A ver si es verdad que para otoño, me toca comprar nuevo equipo... y no quiero pagar más de lo justo.  :silbar: :silbar: :silbar:
#2334
Lo entnedería si fuer ala propia fundación Mozilla la que estuviera detrás del ¿proyecto Fénix? (juraría haber escuchado proyecto Fenix en relación a la programación, lo menos 4 ó 5 veces antes (proyectos alternativos) si nnada que ver entre sí)...

Parece que Mozilla, se ha acostumbrado a retirarse una y otra vez cuando ve algo de 'hostilidad'... a esto se le suele llamar vulgarmente, cobardía. Cierto que los valientes mueren antes, pero... quién quiere un cobarde a su lado?.
#2335
Mala respuesta de TPB...

Es sitios así, es preferible otras soluciones como reclamar donaciones a los visitantes asíduos o registrados... y si ni aún así se consiguiera recabar la cantidad suficiente para mantener el hospedaje, entonces crear 'usuarios premium', donde el que done tiene algunos privilegios más que el resto...
#2336
ASM / Re: ¿como aprender ensamblador?
11 Julio 2018, 15:00 PM
Pués yo disiento por completo, recomiendo justamente al revés . Si uno aprende algo aunque sea básico en ensamblador, luego a cualquier lenguaje de alto nivel, le sabrás sacar mucho más provecho, y te costará mucho menos de aprender...

...y jamás se me ocurriría recomendar a nadie aprender C, ni C++ (si C#), antes que eso recomendaría aprender un par de lenguajes alternativos, precisamente ensamblador y algún otro de alto nivel como Visual Basic, Phyton (y en menor medida Java).

La curva de aprendizaje de C, es tan alta, que vale más aprender ensamblador (que a fin de cuentas es más potente y la curva de aprendizaje es considerablemente menor), y para hacer cosas rápidas y no enfangarse cada vez, un segundo lenguaje de alto nivel, cuya curva de aprendizaje tampoco resulte elevada.

Ademas, si alguien sabe aunque solo sea lo básico en ensamblador, siempre le resultará mucho más asequible, aprender adecuadamente un lenguaje de alto nivel, que si es al revés.

Libros hay a patadas para aprender ensamblador...
Te dejo un par de imágenes de uno de mis estantes...





Así que lo mejor para inciarse es empezar con 80x86, porque ahí reside gran parte de la base... luego es ya ir ampliando y actualizando, cuando tengas nociones más o menos sólidas aprender por ejemplo el ensamblador de otros procesadores (RISC por ejemplo), será mucho más llevadero...
#2337
Saque un tiempo el fin de semana para hacer un sencillo ejemplo de prueba, pero me faltó tiempo para probarlo y subirlo...

Aunque se puede hablar largo y variado sobre la trnasparencia, vamos a ir al grano...
En los controles d eusuario de VB6, hay dos formas de dibujar:

A - La primera es usar el evento paint del propio usercontrol... cuando una parte dle control queda expuesta y luego liberada, salta un evento paint, que da la ocasión de redibujar el control. Así que en éste caso todo lo que se deba dibujar debe estar dentro de ese evento.
B - Un defecto del método propio, es que en generla se procede a dibujar por completo el control aunque solo hay sido expuesta una pequeña área. VB6, provee un método alternativo.
Cuando se pone la propiedad Autoredraw a TRUE, una vez pintado, VB6, hace una especie de 'capura' del gráfico, luego cuando se tapa y expone, VB6, solo pega parcialmente el área recién descubierta en vez de redibujar todo.
Naturalmente cuando haya que hacer cambios, hay que redibujar el control al completo por lo general...
Es importante saber que si se pone Autoredraw a TRUE, el evento paint, no salta, porque VB6 se encarga de repintar el área que lo precise, sin embargo o mejor dicho queda a cargo del programador actualizar convenientemente el gráfico cuando convenga...

Aclarado el tema, podemos crear una función llamada por ejemplo "Redibujar", si autoredraw está a false, saltará el evento paint, allí simplemente innnvocamos a esta función y listo. Y si Autoredraw está a TRUE, simplemente desde nuestro código debemos invocar dicha función cuando necesitemos actualizar el gráfico...

Vamos a  lo primero, algunas propiedades para controlar y que sirvan de ejemplo...

' OK: Devuelve o establece si el color del fondo del display es transparente y deja ver lo que hay bajo él.

Código (vb) [Seleccionar]

' En la sección de declaraciones:
Private p_Transparente          As Boolean
Private p_ColorTapiz              As Long
Private p_ColorTinta              As Long



Public Property Get Transparente() As Boolean
    Transparente = p_Transparente
End Property
    Public Property Let Transparente(ByVal X As Boolean)
        If (X <> p_Transparente) Then
            p_Transparente = X
            Call Redibujar
            PropertyChanged "Transparente"
        End If
    End Property

' Devuelve o establece el color del fondo del control.
'   Todo lo que se pinte de este color será transparente.
' No hay problema en delegar la propiedad en Usercontrol.Backcolor
Public Property Get ColorTapiz() As OLE_COLOR
    ColorTapiz = p_ColorTapiz
End Property
    Public Property Let ColorTapiz(ByVal X As OLE_COLOR)
        If (X <> p_ColorTapiz) Then
            p_ColorTapiz = X
            Call Redibujar
            PropertyChanged "ColorTapiz"
        End If
    End Property

' Devuelve o establece el color de la tinta del control. Por defecto, lo que se dibue se hará con este color.
'  puede delegarle la propiedad en Usercontrol.Forecolor sin problemas...
Public Property Get ColorTinta() As OLE_COLOR
    ColorTinta = p_ColorTinta
End Property
    Public Property Let ColorTinta(ByVal X As OLE_COLOR)
        If (X <> p_ColorTinta) Then
            p_ColorTinta = X             'UserControl.ForeColor = X
            Call Redibujar
            PropertyChanged "ColorTinta"
        End If
    End Property


Añade tus funciones gráficas, en general pinta con el 'ColorTinta', digamos que es el color por defecto para pintar...
Es útil disponer también de una propiedad: "ColorPreset". que no es otra cosa que un array de colores...
Si son fijos los estableces en código, si son elegibles por el usuario, que el mismo los pueda remplazar, aunque siempre conviene que existan por defecto... en generla basta con 16 colores, digamos 15 para el array + el 'color Tinta' (el valor por defecto).
La ventaja de un color preset, es que si tiene spongamos 300 líneas que dibujar y 35 de ellas tienen un color morado y decides cambiarlo a amarillo, en vez de recordar que líneas son es preferible asignar un color preset a cada línea, luego cuando se queira cambiar el color, la propiedad detecta que ha cambiado y al dibujar lo hará con el nuevo color... sin tener que recorrer las 300 líneas para asignarle un nuevo color... así pasamos por ejemplo de la estructura:
Código (vb) [Seleccionar]

public type DatosLinea
    X1 as integer
    Y1 as integer
    X2 as integer
    Y2 as integer
    Color as long
end type

Es preferible usar una estructura ligeramente diferente...
Código (vb) [Seleccionar]

public type DatosLinea
    X1 as integer
    Y1 as integer
    X2 as integer
    Y2 as integer
    IndexColor as Integer
end type


IndexColor apunta a un índice en el array de ColorPreset, así cambiar el color a 52 líneas no exige más que cambiar el color al índice concreto, y no a todas las 52 lineas recorriendo las 300... Una vez hecho el cambio, al dibujar sería algo como:
Código (vb) [Seleccionar]

    For k = 0 to p_NumLineas
        with ColLineas(k)  ' una colección o array de 'DatosLinea'
            UserControl.Line (.x1, .y1)-(.x2, .y2), p_ColorPreset(.IndexColor), BF
        end with
    Next


La propiedad ColorPreset, requiere dos parámetros, el índice y el color que se asigna a dicho índice:
Código (vb) [Seleccionar]

' en las declaraciones:
private p_ColorPreset(-1 to 15)    as long  ' el valor del índice -1, refleja el ColorTinta

public property get ColorPreset(byval Indice as byte) as OLE_Color
    ColorPreset = p_ColorPreset(indice)
end property
    ' Como indice está declarado como byte, el índice -1 no puede ser alterado externamente
    Public property let ColorPreset(byval Indice as byte, byval X as OLE_Color)
        if (indice > 15) then err.raise 381  ' indice de array fuera de rango.
        If (p_ColorPreset(Indice) <> X) then
            p_ColorPreset(Indice) = X
            Call Redibujar
            PropertyChanged "ColorPreset"
        end if
    end property


Esto sin embargo es mejorable en dos aspectos.
Lo primero es que al poner dos parámetros en una propiedad, ya no puede aparecer en la "ventana de propiedades" durante el diseño y por tanto durante diseño, la aplicación cliente, no podrá poner reasignar colores salvoque se añada una página d epropiedades, que es complicarlo solo para esto.
Hay una técnica muy sencilla, que admeás puede también aplicarse a otros objetos que posena índice  y varia spropiedades... y consiste en desdoblar la propiedad en dos...
por un lado el índice y por otro el color, como se muestra a continuación:
Código (vb) [Seleccionar]

' en las declaraciones:
    private p_IndexPreset     as byte
    private p_ColorPreset(-1 to 15)    as long  ' el valor del índice -1, refleja el ColorTinta   

' Esta propiedad refleja en diseño el índice al que se aplica el colorPreset...
public property get IndexPreset() as byte
    IndexPreset = p_IndexPreset
end property
    ' Como indice está declarado como byte, el índice -1 no puede ser alterado externamente
    Public property let IndexPreset(byval X as byte)
        if (x > 15) then err.raise 381  ' indice de array fuera de rango.
        If (p_IndexPreset <> X) then
            p_IndexPreset(Indice) = X
            ' no necesita guardarse esta propiedad, puede ser 0 cada vez... que se carguen las propiedades.
        end if
    end property

public property get ColorPreset() as OLE_Color
    ColorPreset = p_ColorPreset(p_IndexPreset)
end property
    ' Como indice está declarado como byte, el índice -1 no puede ser alterado externamente
    Public property let ColorPreset(byval X as OLE_Color)
        If (p_ColorPreset(p_IndexPreset) <> X) then
            p_ColorPreset(p_IndexPreset) = X
            Call Redibujar
            PropertyChanged "ColorPreset"
        end if
    end property

Ahora ya aparece esa propiedad en la 'ventana de propiedades', para cambiar un color del array, basta cambiar el array y luego asignar un color...

Antes decía que tenía dos carencias, una ya ha quedado subsanada, la otra es que anque tenemos 16 colores, no necesariamente deben estar todos en uso, sin embargo al cambiar un color del preset, forzamos un redibujado... algo caro si resulta que nada está dibujado con ese color.
Algo más optimo es mantener un array paralelo que lleve la cuenta de 'objetos' que usan cada color...
Cuando se añade un nuevo 'objeto gráfico', se añade 1 a la cuenta, si se elimina (o se cambia de índice asignado de color), se resta 1 para ese índice (y se suma uno al otro si cambió de índice).
Entonces ahora la última propiedad puede mejorarse así:
Código (vb) [Seleccionar]

private p_CuentaObjColor(0 to 15)         as integer

public property get ColorPreset() as OLE_Color
    ColorPreset = p_ColorPreset(p_IndexPreset)
end property
    ' Como indice está declarado como byte, el índice -1 no puede ser alterado externamente
    Public property let ColorPreset(byval X as OLE_Color)
        If (p_ColorPreset(p_IndexPreset) <> X) then
            p_ColorPreset(p_IndexPreset) = X
            if (p_CuentaObjColor(p_indexPreset)>0) then
                Call Redibujar
            end if
            PropertyChanged "ColorPreset"
        end if
    end property

Ahora es más eficiente, al coste de mantener convenientemente actualizado el array con la cuenta de objetos que mantienen tal o cual color...
Claramente si el número de líneas a dibujar son pocas, redibujarlo todo cada vez, no sea pesado y a cambio uno se olvida de la complejidad añadida por la eficiencia, en cambio sin son algunas miles d elínea sa dibujar... redibujarlas todas cuando ningún objeto utiliza dicho color, no es ideal... En fin uno debe decidir que conviene mas dado el caso de que vaya a usarse muchas o pocos objetos gráficos...

Todo lo previo es para optimizar operaciones, ahora veremos unamanera de reutilizar el mismo control para 3 tareas diferentes...
- Polilínea: Son varios puntos conectados entre sí, formando un único objeto gráfico, más o menos complejo...
Se dibuja una línea de un punto a otro, si uno no está activo se pasa al siguiente (es decir el que noes
´te activo se ignora).
- Múltiples líneas inconexas entre sí. Es decir cada línea tiene dos puntos que definen su inicio y su fin.
Cad alínea comienza en un índice par como X1,Y1 y termina en el siguiente punto delarray (punto impar), como X2, Y2.
- Poligonos: Cada polígono se compone de varios vértices. realmente también puede considerarse múltples polilíneas, ya que ser polígono, exige que la última línea del polígono se conecte a la primera.
Un poligono dibuja de un punto a otro, hasta encontrar uno no activo, momento en que se considera que acaba e polígono (o polilínea en múltiples polilineas).
Todo ello soportado con una misma y única colección o array (luego un par de párrafos al respecto).

Aquí, código para dar salida a todas esas ideas...
Código (vb) [Seleccionar]

' en las declaraciones:
Public Type PuntoPolilinea
    X       As Single
    Y       As Single
    Activo  As Byte         ' Valor 255 = activo, se dibuja, otro valor no se dibuja
    ' (interesa un byte mejor que Boolean, porque incluso puede usarse como cuenta y al alcanzar el valor 255 será 'dibujable', en cualquier caso, un boolean en vb6 ocupa 2 bytes).
End Type

' Comportamiento del control a la hora de dibujar.
Public Enum ModosDeDibujado
    DIBUJA_INCONEXA = 0        ' De un punto par al siguiente impar, del impar salta (sin dibujar) al siguiente par.
    DIBUJA_POLILINEA = 1       ' Se comporta como una línea continua de un punto (activo) a otro.
    DIBUJA_POLIGONOS = 2       ' Se comporta como si fueran polígonos, cada polígono termina cuando un punto está desactivado.
End Enum

Private p_Polilinea         As ModosDeDibujado  ' Se comporta de diferentes maneras...

Private p_ptActual          As Integer              ' para señalar valores dado su índice.
' Permite dibujar desde un punto a otro específico...
Private p_ptInicio          As Integer             ' Punto desde el que se empieza a dibujar.
Private p_ptFinal           As Integer             ' Punto donde se termina de dibujar (si circular hasta el sigiente).
Private p_ptEvento          As Integer          ' dispara un evento al dibujar dicho punto, para tener ocasión de asignar color, ancho paqra la siguiente línea (o para el resto), incluso para poder cambiar el índice de otro punto para evento...

' en las propiedades:

' Devuelve o establece un valor que determina si los puntos se comportan como una polílínea, como líneas inconexas o como polígonos (o múltiples polilíneas). Actuando como líneas inconexas cada línea queda definidar por un punto par y el siguiente.
' OJO: Dado que como múltiples líneas, cada línea(inconexa) requiere dos puntos, queda definida por un punto par y el siguiente impar,
'  luego definir como punto inicial (para empezar a dibujar) uno impar, haría una conexión errónea (conectando el punto final de una línea con el punto inicial de otra), para todas ellas.
Public Property Get ModoDibujo() As ModosDeDibujado
    ModoDibujo = p_Polilinea
End Property
    ' La idea es que el control se utilice para una sola cosa durante su tiempo de ejecución.
    Public Property Let ModoDibujo(ByVal X As ModosDeDibujado)
        If (X <> p_Polilinea) Then
            If (p_Polilinea = DIBUJA_POLIGONOS) Then
                p_Polilinea = X
                Call AjustarArray
               
                If (X = DIBUJA_INCONEXA) Then
                    ' Garantiza la integridad de dibujar líneas como se definieron.
                    If (p_ptInicio And 1) Then          ' si es impar, se resta uno,
                        p_ptInicio = (p_ptInicio - 1)   ' para apuntar al punto inicial de la línea.
                    End If
                End If
               
                If (p_Autodibujar = True) Then
                    Call Redibujar
                End If
            Else
                p_Polilinea = DIBUJA_POLIGONOS
                ' no se debe redibujar, sin cargar primero los puntos.
            End If
            PropertyChanged "ModoDibujo"
        End If
    End Property


Los campos para otras propiedades:
- p_ptActual: Sirve para usar la misma técnica anterior y poder asignar línea durante diseño, sobre la ventana d epropiedades... va bien cuando son pocas, si son muchas es preferible usar un fichero externo y proveer una función de carga d elos datos...

- p_ptInicio, p_ptFinal... aunque se comentan brevemente en su declaración, sirven para dibujar en un bucle... por defecto una vale 0 y la otra el último punto del array/colección, pero en la práctica, puede ser usado como separador de objetos, por ejemplo podrías tener olilíneas entre el indice 0 y el 60, línea ssueltas entre el índice 61 y 130 y poligonos (de pocos lados cada uno) entre el punto índice 131 y el 540, y otro objeto más complejo entre el índice 541 y el 650 (por ejemplo)... así si precisas redibujar solo las líneas, estbalece inicio y fin a los valores 61 y 130 respectivamente y luego con polilinea = DIBUJA_INCONEXA, si está establecda una propiedad AutoRedibujar , ya haría el redibujado, y si no puede crearse una función publica que admita dichos parámetros...

Ahora la función de dibujado que aplica las diferentes formas de dibujado:
Código (vb) [Seleccionar]

' redibuja toda la figura desde el punto inicial hasta el final (perop uede hacerse pública y admitir los parámetros antedichos más arriba, para ser invocada también desde fuera...
Private Sub DibujarMiContenido()
    Dim k As Integer, j As Integer, i As Integer, n As Integer
    Dim X1 As Single, X2 As Single, Y1 As Single, Y2 As Single
    Dim kol As Long, Ancho As Byte
    Dim pts() As PuntoPolilinea
   
    If (p_NumPuntos > 1) Then
        ' para permitir (durante evento de punto), dibujar con coloy ancho distintos sin alterar el valor 'general'.
        kol = p_ColorTinta ' UserControl.ForeColor
        Ancho = UserControl.DrawWidth
       
        If (p_ptInicio < p_ptFinal) Then
            i = p_ptInicio: j = p_ptFinal: n = 1
        Else
            j = p_ptInicio: i = p_ptFinal: n = -1
        End If
                       
        ' 2 arrays, uno mantiene los puntos originales para no perse rprecisión por escalados contínuos, el otro
        '    mantiene los valores escalados...
        If (p_AutoEscalado = True) Then
            pts = s_Escala
        Else
            pts = p_Puntos
        End If
               
        If (p_Polilinea = DIBUJA_POLILINEA) Then
            ' Dibuja como una polílinea. Líneas conexas entre puntos activos...
            ' Donde cada línea queda definida entre un par de puntos activos.
            '  Los puntos pueden estar activos individualmente.
            If (p_NumPtActivos = 0) Then Exit Sub
           
            With pts(p_ptInicio)
                X1 = .X: Y1 = .Y
            End With
       
            For k = i + n To j Step n
                With pts(k)
                    If (.Activo = 255) Then
                        X2 = .X: Y2 = .Y
                        If (k = p_ptEvento) Then
                            ' El cliente tiene con éste evento oportunidad de dibujar algo en ese momento, cambiar valor de puntos
                            '   cambiar color para dibujar, el ancho, e incluso definir otro momento de evento como éste para hacer más cambios.
                            RaiseEvent DibujandoPuntoSel(p_ptEvento, kol, Ancho)
                        End If
                        UserControl.Line (X1, Y1)-(X2, Y2), kol
                        X1 = X2: Y1 = Y2
                    End If
                End With
            Next
           
            If (p_Circular = True) Then
                With pts(i)
                    X2 = .X: Y2 = .Y
                    UserControl.Line (X1, Y1)-(X2, Y2), kol
                End With
            End If
       
        ElseIf (p_Polilinea = DIBUJA_INCONEXA) Then
            ' Dibuja como múltiples líneas inconexas entre sí...
            ' Donde cada línea queda definida por un par de puntos par-impar.
            '  La línea está 'activa' si el primero lo está (obviando el estado del 2º).
            If (i And 1) Then i = (i - 1)
            For k = i To j Step (n * 2)
                With pts(k)
                    If (.Activo = 255) Then
                        X1 = .X: Y1 = .Y
                        ' Como múltiples líneas se ignora el estado activo del segundo punto.
                        With pts(k + n)
                            X2 = .X: Y2 = .Y
                        End With
                       
                        ' Igualmente: éste punto debiera ser par, o modificarse como  está comentado
                        If (k = p_ptEvento) Then   ' or ((k+n) = p_ptEvento) then
                            ' El cliente tiene con éste evento oportunidad de dibujar algo en ese momento, cambiar valor de puntos
                            '   cambiar color para dibujar, el ancho, e incluso definir otro momento de evento como éste para hacer más cambios.
                            RaiseEvent DibujandoPuntoSel(p_ptEvento, kol, Ancho)
                        End If
                       
                        UserControl.Line (X1, Y1)-(X2, Y2), kol
                    End If
                End With
            Next
        Else ' poligonos...
            ' polígonos solo se dibuja en orden hacia arriba...
            Do While (i < j)
                With pts(i)
                    X1 = .X: Y1 = .Y
                End With
               
                ' un polígono acaba cuando encuentra un punto 'no activo'
                Do While pts(i).Activo = True
                    i = (i + 1)
                    With pts(i)
                        X2 = .X: Y2 = .Y
                        ' Igualmente: éste punto debiera ser par, o modificarse como  está comentado
                        If (i = p_ptEvento) Then   ' or ((k+n) = p_ptEvento) then
                            ' El cliente tiene con éste evento oportunidad de dibujar algo en ese momento, cambiar valor de puntos
                            '   cambiar color para dibujar, el ancho, e incluso definir otro momento de evento como éste para hacer más cambios.
                            RaiseEvent DibujandoPuntoSel(p_ptEvento, kol, Ancho)
                        End If
                       
                        UserControl.Line (X1, Y1)-(X2, Y2), kol
                    End With
                    X1 = X2: Y1 = Y2
                Loop
                i = (i + 1)
            Loop
        End If
       
        ' restaura el ancho de dibujado...
        UserControl.DrawWidth = Ancho
    End If
End Sub


El campo "p_ptEvento" da pie a otra propiedad... por eejmplo dado un indice que se debe dibujar con un color o ancho distintos, alllegar aél se lanza el evento, y se responde cambiando el color y/o el ancho de dibujado de la línea y/o también el próximo punto donde parar...

en este ejemplo de función no he hecho uso del array ColorPreset, ya puse un ejemplo muy simple más arriba de como usarlo, aquí se ha puesto para el caso, p_ColorTinta, ya que la estructura definida algo más arriba, no aloja un color, si no otro campo interesante "Activo", para señalar qué hacer o para que sirve o como funcionar con dicho punto de formas diversas...

Y como ya me he extendido más d elo que pretendía, finalmente podrmeos dibujar con transparencia...
Respeta lo que en esta función aparece y lo que modifiques que sea en una función aparte o bien enciam o debajo de la función usada para todo el dibujado...
Código (vb) [Seleccionar]

' Con AutoRedraw=True, nunca se invoca este método,
'  se puede solucionar así...
' Private Sub UserControl_Paint()
'     call Redibujar
' end sub

' siempre conviene tener una funcion externa que redibuje todo...
public sub Refresh
    call Redibujar 
end sub

'  pero si se pone a False, no requiere invocarse otro método.
Private Sub Redibujar()
    With UserControl
        .BackStyle = 1
        .DrawMode = vbCopyPen
        .FillStyle = vbFSTransparent
       
        ' Color del fondo...
        '.Cls ' aplicando el color al usercontrol.backcolor, pero como no delegamos en usercontrol.backcolor...
        ' pintmaos el fondo 'a mano'.
        UserControl.Line (0, 0)-(.Width, .Height), p_ColorTapiz, BF  ' "B"oxed y "F"illed
       
        'Call DibujarFondo ' dibujamos si hay alguna imagen de fondo con algo transparente o no, quizás una cuadrícula
        Call DibujarMiContenido ' dibujamos el valor
        Call DibujarRelieve ' dibujamos el borde. Si el borde va ser sencillo, mejor delegar en el usercontrol.BorderStyle, pero si redondeamos esquinas, o se da un margen mayor, etc... viene bien dibujarlo después del resto.
               
        If (p_Transparente = True) Then
            .MaskColor = p_ColorTapiz
            .BackStyle = 0
            Set .MaskPicture = .Image
        End If
       
        If (p_Activo = False) Then ' usercontrol.Enabled
            Call DibujarEstadoDisabled
        End If
    End With
    'RaiseEvent Pintado
End Sub


pongo alguna imagen... y como ya se me hace tarde para más, mañana (o pasado, si no tengo tiempo mañana) comprimo el proyecto de ejemplo y lo subo a alguna página de descarga... comentaré alguna cosa más antes...




#2338
Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
Dije que no sé si mi lenguaje admite paréntesis en las condiciones, ejemplo "V1<V2 or (V1==V2 and V2==V3)" ni cómo las toma, lo cual evidentemente es algo que yo debo averiguar, no pedí ayuda con eso.
Action Script de Macromedia Flash 5. Es prácticamente el único que uso y mi favorito.
Tienes solo 2 problemas (aunque gordos).
- En primer lugar tienes dificultad para entender... lo que se te dice. Pasas de largo por las soluciones, como esperando una receta mágica (que no existe).
- En segundo lugar 'tu lenguaje' al margen de calificarlo, ni siquiera lo conoces a fondo aún 'siendo tu favorito' como dices.

Cualquier lenguaje por miserable que sea, admitirá paréntesis para resolver la precedencia de operadores (debe importarte nada que un operador sea 'or', 'and' ó '+', '/', o cualquier otro... un operador es un operador sea del tipo que sea y a tí debe bastarte con saber que como tal cualquier operador tiene un valor de precedencia (prioridad en ser resuelto cuando no tiene paréntesis que lo delimite).

Esto quiere decir que siempre que tu pongas una expresión ordenada por precedencia, tampoco necesitarás usar paréntesis... pero esa forma la podrás usar en determinadas ocasiones, en otras ocasiones resultará forzado, poco natural y por tanto difícil de leer  y/o erscribir... aparte dle tiempo perdido en ello (solo por evitar colocar unos paréntesis).

Pero no entiendo a que viene tanto problema con los paréntesis... úsalos cuando y donde correspondan y listo. Y a tu pregunta sobre si existe alguna forma de evitarlos, ya te he aclarado que sí... que un lenguaje no admita directamente la notación polaca no es problema, precisamente para eso como programador uno programa el algoritmo que precise al problema que surja.

La mayoría de lenguajes carecen de interpretación para dicha notación, pero el compilador de todos y cada uno de ellos, acaba teniendo una implementación del algortimo para convertir la expresiones que el programador escribe en el lenguaje, para pasarlo a notación polaca...

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
lo que quisiera saber cómo arreglar, en lo posible sin usar paréntesis.
Ya te he contestado...
O reordenas las expresiones para que de izquierda a derecha, estén ordenados los operadores por precedencia, o recurres a la notaciópn polaca.

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
Ante mi pregunta
"¿Cualquier relación puede expresarse sin necesidad de paréntesis, y se interpretaría bien?" no veo un problema.
Es que insisito... para qué necesitas NO PONER paréntesis, cuando poniéndolos solo de un vistazo queda perfectamente claro y ordenado, sin importar lo compleja que sea una expresión????.

Es que tu te empeñas en no usar paréntesis por simple cabezonería... es como pretender prescindir de barcos o aviones y querer cruzar el océano a nado, y tu preguntas si puedes cruzarlo sin morir en el intento... maneras hay, pero ya son ganas de morir en el intento. Cuando en barco o avión el trayecto es seguro y rápido.

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
El problema son las expresiones que parecen requerirlo (a algún paréntesis) ¿realmente lo requieren o hay otra forma de decirlas que no use paréntesis?
Sí... ya te he explicado, reordena la expresión, para que los operadores de mayor precedencia queden a la izquierda... y el de menor precedencia a la derecha (siguiendo el orden estricto... pero esto resulta complejo incluso con expresiones no muy complejas, ya que si una operación tiene por ejemplo suma y resta y en otra parte aparece multiplicación, pero esta debe aplicarse después de haber hecho las previas, no podrá ponerse a la izquierda... en la misma línea, es decir tendrás que resolverlo en varias líneas... y así resulta tortuoso, pero poder s epuede, complicándolo innecesariamente... cruza el oceáno a nado, si te place.


Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
Hombre, yo estoy hablando de los operadores AND y OR.
Tú me vienes con +, *, -.
En el mundo d ela programación, los operadores que  tiene un lenguaje son los que son, sin importar los que a ti te vengan bien o uses... En la especificación de cad alenguaje hay un apartado que expecifica el orden en que se evalúan los operadores (todos los que dispone el lenguaje, no solo los que a Pepito ó a Juanito le  vienen bien).

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
En tus descripciones de los operadores te has hecho un lío, pero la idea la entendí gracias a los ejemplos.
Vaya hombre... me he hecho un lío... buen chiste.... a estas horas, un poco de humor no viene mal.

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
EDIT2: El "xor" y cosas así más complejas que and y or creo que no las necesito, pero supongo que acortan ciertas expresiones, veremos...
XOR no es más complejo que OR ni AND, sino a su mismo nivel...

Tabla de verdad de XOR
----------------------------
0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0

En resumen es TRUE si solo una de ellas es TRUE. Si se aplica a más de 2 operandos es TRUE, si el número de evaluaciones TRUE es impar, FALSE si son pares...

1 xor 1 xor 1 xor 1 = 0   (4 unos, son pares luego = FALSE)
1 xor 1 xor 1 xor 0 = 1   ( 3 unos, son impares luego es = TRUE)

XOR te puede ahorrar muchas comparaciones...  


Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
(la notación polaca) Probablemente sea la respuesta que necesitaba. Lo que no entiendo bien es cómo se interpretaría cada uno, pero sería cuestión de investigar y de práctica.
Investiga, pero yo te aconsejaría mejor que desistas de no querer usar paréntesis... A no ser que vivas en Marte, y las teclas de paréntesis se hayan fastidiado y no tengas posibilidades de arreglarlo...

Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
Sí, la verdad que sí. Pero si son como las expresiones matemáticas entonces no. ¿Cómo interpretarías esto, si fueses de izquierda a derecha?
A y B y C o D o E y F o G
La precedencia de operadores lógicos: primero AND, luego OR y finalmente XOR... en tu ejemplo sería lo mismo que si AND lo cambiar por '-'  y 'or' por '+', ya qe mantienen entre si la misma recedencia...
La expresión que pides quedaría así:
A B y C y D o E o F y G o
Los operadores aritméticos tienen precedencia sobre los lógicos.
La precedencia en los operadores de comparación, es esta:  =, <, <=, >, >=


Cita de: Tachikomaia en  6 Julio 2018, 01:19 AM
Ni siquiera sé de lo que me estás hablando. Para mí pila es un "aparato" que se guarda en otros para darle energía, o una montaña con cierto orden.
Ni te preocupes en aclarármelo, sólo te comento.
Ya... me hago cargo... por eso decía que si tienes problemas para enteder expresiones sencillas, o para entender la simpleza y elegancia de los paréntesis, no vale la pena decir nada más... La testarudez, no tiene cura. ...pero bueno, si aprendes algo, pués vale.



Buscando por la red, algún pdf sobre ActionScript, aparece claramente...

Citar
() parentheses operator
(expression1 [, expression2])
( expression1, expression2 )
function ( parameter1,..., parameterN )

Performs a grouping operation on one or more parameters, performs sequential evaluation of expressions, or surrounds one or more parameters and passes them as parameters to a function outside the parentheses.

Usage 1: Controls the order in which the operators execute in the expression. Parentheses override the normal precedence order and cause the expressions within the parentheses to be evaluated first. When parentheses are nested, the contents of the innermost parentheses are evaluated before the contents of the outer ones.

Usage 2: Evaluates a series of expressions, separated by commas, in sequence, and returns the result of the final expression.

Usage 3: Surrounds one or more parameters and passes them as parameters to the function outside the parentheses.
Availability: ActionScript 1.0; Flash Player 4

Operands
expression1 : Object - Numbers, strings, variables, or text.
expression2 : Object - Numbers, strings, variables, or text.
function : Function - The function to be performed on the contents of the parentheses.
parameter1...parameterN : Object - A series of parameters to execute before the results are passed as parameters to the function outside the parentheses.

Example
Usage 1: The following statements show the use of parentheses to control the order in which expressions are executed (the value of each expression appears in the Output panel):
trace((2 + 3)*(4 + 5)); // Output: 45
trace((2 + 3) * (4 + 5)); // Output: 45
trace(2 + (3 * (4 + 5))); // // writes 29
trace(2 + (3 * (4 + 5))); // Output: 29
trace(2+(3*4)+5); // writes 19
trace(2 + (3 * 4) + 5); // Output: 19

Usage 2: The following example evaluates the function foo(), and then the function bar(), and returns the result of the expression a + b:
var a:Number = 1;
var b:Number = 2;
function foo() { a += b; }
function bar() { b *= 10; }
trace((foo(), bar(), a + b)); // outputs 23

Usage 3: The following example shows the use of parentheses with functions:
var today:Date = new Date();
trace(today.getFullYear()); // traces current year
function traceParameter(param):Void { trace(param); }
traceParameter(2 * 2); //traces 4
#2339
Citar
y de paso de gratis, porque no creo que que el grupo de ingenieros que trabajar para mark zuckerberg cobren 50 mil dolares al año.

mark si quieres atraer gente talentosa que resuelva tus problemas, no ofrezcas bonos irrisorios, ofrece porcentajes y acciones de la compañía, para que veas que te lo resuelven en semanas!!!
Eso mismo iba a decir... pero claro, s ehan curado en salud...

Citares un llamamiento a académicos y aficionados, para que presenten un proyecto de investigación
Es decir ellos quieren tu idea, y ya ellos luego la patentan y la explotan...

Otra cosa que no soporto, es la nomenclatura 'millonaria' inglesa, mal traducida...
con nada menos que 1,5 billones de cuentas de usuarios
En el mundo somo alrededor de 10mil millones, así que no se de donde salen esos 1'5 Billones...

#2340
Scratch, es y seguirá siendo un ¿lenguaje? de juguete... Es válido para quien no sabe nada, y pretende a futuro seguir sin saber nada.

Parte de la filosofía (tan de moda hoy día), de la creciente pereza y vaguedad en el esfuerzo. La vida es intuitiva, pero todo artefacto artificial, ha requerido y requerirá siempre un aprendizaje, al margen de la destreza natural que cada cual posea en dicho campo... Un lenguaje pretendidamente 100% intuititivo, no puede ser si no totalmente insuficiente, porque la vida guste o no tiene complejidades e incluso hay cosas extremedamente simples, pero que el acceso a ellas exige complejidad. Solo cuando el conocimiento está por encima, lo complejo se vuelve simple, pero la experiencia y la intuición, por sí solas no valen... el conocimiento adquirido por el parendizaje es necesario si se quiere acelerar dicho proceso.

Cuando alguien quiere aprender a programar en seriro, es mejor que lo haga así, para toda la vida y entonces cuanto antes se meta a fondo con algún lenguaje 'completo', mejor que mejor...

No hay nada peor que dedicar 4-5 años de tu vida a aprender algo que al final no servirá para nada profesional, y delo que nunca podrás sacar nada en claro a excepción de 'imágenes mentales obtusas'. Más matemáticas, y menos chorradas de click en 500 sitios... programar empieza por saber que quieres hacer y ordenar las cosas para saber cómo hacerlo. Pero para esto segundo, es preciso saber con qué herramientas cuentas y para esto lo mejor es no perder el tiempo y aprenderlo cuanto antes (aunque no sea a fondo, hasta que uno no lo precise, después de todo es inabarcable por nadie)...