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)
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
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
import sys
import pygame
import pygame.gfxdraw
import time
pygame.init()
#globales
tamano = 0 #tamano del punto, 0 = 1px, 1=3px... etc
separacion = 1 #el desplazamiento entre punto y punto, 1px
niveles = 100 #cuantas capas tendra la espiral
tiempo_maximo = 10 #si no termina de dibujar en este tiempo detiene el trabajo... switch de seguridad si tienen un pc poco potente
PRIMO = (255,255,255) #color si es primo
NO_PRIMO = (64,64,64) #color si no es primo
pantalla = {"w":niveles*2+100,"h":niveles*2+100} #tamano de la pantalla... suficiente para puntos de 1px + 100px de margen
window = pygame.display.set_mode((pantalla["w"], pantalla["h"]))
def dibujar():
posicion = {"x":pantalla["w"]/2, "y":pantalla["h"]/2} #cursor en centro de pantalla
direccion = 1 #0 derecha, 1 arriba, 2 izquierda, 3 abajo
control = 2 #variable de control
cantidad = 1 #cantidad de puntos dibujados
dibCir(posicion, PRIMO) #punto central... direccion va por "referencia"
inicio = time.clock() + tiempo_maximo #calcular tiempo para finalizar
for i in range(2):#dibuja los primeros 2 puntos
mover_dibujar(direccion, posicion, separacion, PRIMO)
direccion += 1
cantidad += 1
puntos_totales = (niveles*2 + 1)**2 - 1 #cantidad de puntos a dibujar
detener = False
for mayor in range(niveles*2):
for menor in range(2):
for punto in range(control):
if esPrimo(cantidad): #color a dibujar
mover_dibujar(direccion, posicion, separacion, PRIMO)
else:
mover_dibujar(direccion, posicion, separacion)
if time.clock() > inicio: detener=True #si se pasa del tiempo
if (cantidad == puntos_totales): detener=True #si se dibujaron los puntos necesarios
cantidad +=1
if(detener): break
direccion = (direccion+1)%4 #cambia la direccion del recorrido
if(detener): break
control += 1
if(detener): break
pygame.display.flip() #dibuja la capa calculada
print cantidad #imprime los puntos dibujados en la consola
return 0
def mover_dibujar(direccion, posicion, separacion, color=NO_PRIMO): #dirije el recorrido y dibuja
if direccion == 0: posicion["x"] -= separacion
if direccion == 1: posicion["y"] += separacion
if direccion == 2: posicion["x"] += separacion
if direccion == 3: posicion["y"] -= separacion
dibCir(posicion, color)
def dibCir(posicion, color ,r=tamano):
pygame.gfxdraw.filled_circle(window, posicion["x"],posicion["y"], r, color) #dibuja el circulo
#pygame.gfxdraw.aacircle(window, posicion["x"],posicion["y"], r, color) #lo suaviza mas
def esPrimo(n): #calcula si es primo
if n <= 3:
return n >= 2
if n % 2 == 0 or n % 3 == 0: return False
for i in range(5, int(n ** 0.5) + 1, 6):
if n % i == 0 or n % (i + 2) == 0:
return False
return True
dibujar() #ejecuta todo
#input handling (somewhat boilerplate code):
while True: #copypaste para mentener abierta la ventana
time.sleep( 1 ) #sin esto se consume todos los recursos
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
#else:
# print event