Foro de elhacker.net

Programación => Scripting => Mensaje iniciado por: engel lex en 19 Enero 2015, 07:15 am



Título: [Python] Espiral de Ulam
Publicado por: engel lex en 19 Enero 2015, 07:15 am
Los que me conocen por aquí saben que e gusta jugar con las mates... esta vez le toco el turno a la espiral de Ulam (articulo de la wiki (http://es.wikipedia.org/wiki/Espiral_de_Ulam))

me dio curiosidad su representación y quería jugar un poco con gráficos en Python... entonces esto quedó...

primero lo intenté con kivy... a 200 capas consumió 4gb de ram y congeló el pc... entonces decidí probar pygame, mucho más rápido y eficiente para esto...

a 100 capas es rápido... sobre eso vayan con cuidado... tiene una cantidad de segundos marcados para detener el calculo (cuando estaba probando con kivy era eso o mi pc)

lo punedo hacer sin problemas a 500 capas (el tamaño es limitante), pero le calculo es bastante rapido...

el algoritmo de recorrido lo basé en

suponiendo direcciones del 1 al 4 como en el codigo, sigue un patron
Código:
1,1,2,2,3,3,3,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,3,0,0,0,0,0...
cada 2 direccionas crece la repetición... "control" maneja esa cantidad de repeticiones, menor maneja que sean 2 direcciones por repeticion, mayor maneja la cantidad de capas en general

ya despues de mucho decir, aquí el código
Código
  1. import sys
  2. import pygame
  3. import pygame.gfxdraw
  4. import time
  5. pygame.init()
  6.  
  7. #globales
  8. tamano = 0 #tamano del punto, 0 = 1px, 1=3px... etc
  9. separacion = 1 #el desplazamiento entre punto y punto, 1px
  10. niveles = 100 #cuantas capas tendra la espiral
  11. tiempo_maximo = 10 #si no termina de dibujar en este tiempo detiene el trabajo... switch de seguridad si tienen un pc poco potente
  12. PRIMO = (255,255,255) #color si es primo
  13. NO_PRIMO = (64,64,64) #color si no es primo
  14. pantalla = {"w":niveles*2+100,"h":niveles*2+100} #tamano de la pantalla... suficiente para puntos de 1px + 100px de margen
  15.  
  16. window = pygame.display.set_mode((pantalla["w"], pantalla["h"]))
  17.  
  18.  
  19.  
  20.  
  21. def dibujar():
  22. posicion = {"x":pantalla["w"]/2, "y":pantalla["h"]/2} #cursor en centro de pantalla
  23. direccion = 1 #0 derecha, 1 arriba, 2 izquierda, 3 abajo
  24. control = 2 #variable de control
  25. cantidad = 1 #cantidad de puntos dibujados
  26. dibCir(posicion, PRIMO) #punto central... direccion va por "referencia"
  27.  
  28. inicio = time.clock() + tiempo_maximo #calcular tiempo para finalizar
  29. for i in range(2):#dibuja los primeros 2 puntos
  30. mover_dibujar(direccion, posicion, separacion, PRIMO)
  31. direccion += 1
  32. cantidad += 1
  33. puntos_totales = (niveles*2 + 1)**2 - 1 #cantidad de puntos a dibujar
  34.  
  35. detener = False
  36.  
  37. for mayor in range(niveles*2):
  38. for menor in range(2):
  39. for punto in range(control):
  40. if esPrimo(cantidad): #color a dibujar
  41. mover_dibujar(direccion, posicion, separacion, PRIMO)
  42. else:
  43. mover_dibujar(direccion, posicion, separacion)
  44.  
  45. if time.clock() > inicio: detener=True #si se pasa del tiempo
  46. if (cantidad == puntos_totales): detener=True #si se dibujaron los puntos necesarios
  47. cantidad +=1
  48. if(detener): break
  49. direccion = (direccion+1)%4 #cambia la direccion del recorrido
  50. if(detener): break
  51. control += 1
  52. if(detener): break
  53. pygame.display.flip() #dibuja la capa calculada
  54. print cantidad #imprime los puntos dibujados en la consola
  55. return 0
  56.  
  57.  
  58. def mover_dibujar(direccion, posicion, separacion, color=NO_PRIMO): #dirije el recorrido y dibuja
  59. if direccion == 0: posicion["x"] -= separacion
  60. if direccion == 1: posicion["y"] += separacion
  61. if direccion == 2: posicion["x"] += separacion
  62. if direccion == 3: posicion["y"] -= separacion
  63. dibCir(posicion, color)
  64.  
  65. def dibCir(posicion, color ,r=tamano):
  66. pygame.gfxdraw.filled_circle(window, posicion["x"],posicion["y"], r, color) #dibuja el circulo
  67. #pygame.gfxdraw.aacircle(window, posicion["x"],posicion["y"], r, color) #lo suaviza mas
  68.  
  69.  
  70. def esPrimo(n): #calcula si es primo
  71.   if n <= 3:
  72.       return n >= 2
  73.   if n % 2 == 0 or n % 3 == 0:       return False
  74.   for i in range(5, int(n ** 0.5) + 1, 6):
  75.       if n % i == 0 or n % (i + 2) == 0:
  76.           return False
  77.   return True
  78.  
  79.  
  80.  
  81. dibujar() #ejecuta todo
  82.  
  83.  
  84. #input handling (somewhat boilerplate code):
  85.  
  86. while True:  #copypaste para mentener abierta la ventana
  87.   time.sleep( 1 ) #sin esto se consume todos los recursos
  88.   for event in pygame.event.get():
  89.      if event.type == pygame.QUIT:
  90.          sys.exit(0)
  91.      #else:
  92.      #   print event
  93.  
  94.  


Título: Re: [Python] Espiral de Ulam
Publicado por: Gh057 en 19 Enero 2015, 12:00 pm
Gracias por el aporte engel lex, esta noche lo miro con detalle ya que es muy interesante el trabajo de Ulam, y me llamó muchísimo la atención esta implementación en Python. (también soy un apasionado de las matemáticas jajaaa es más, ayer intentaba -sin lograrlo- volver a instalar stream para hacer unas cositas con la gpu amd, y la biblioteca gmp... seguiré otro día en algún rato libre)