Haferman Carpet

The Haferman Carpet is a fractal, which kind of looks like a woven carpet. To generate it, you start with a single black pixel and apply in each cycle a set of rules.
In each generation every pixel in the carpet will be replaced by nine pixels according to the rules. A black pixel is represented by a 0, a white one by a 1.

The rules

  • 0 \rightarrow \left( \begin{array}{ccc}1&0&1\\0&1&0\\1&0&1\end{array} \right) \text{and } 1 \rightarrow \left( \begin{array}{ccc}0&0&0\\0&0&0\\0&0&0\end{array} \right)

6 iterations of the Haferman Carpet


# Python 2.7.7 Code
# Pygame 1.9.1 (for Python 2.7.7)
# Jonathan Frech 26th of February, 2016

# importing needed modules
import pygame, sys, time, math, os, random

# maximum iterations
ITERATIONS = 7

# usage: 'q' weaves the carpet, 'space' saves a screenshot
# (Weaving can take some time, let your computer calculate!)

""" GAME """
# game class
class GAME():
	# initialize program
	def __init__(self):
		self.width, self.height = 3**ITERATIONS, 3**ITERATIONS
		self.size = [self.width, self.height]
		self.surface = pygame.Surface(self.size)
		self.screen = pygame.display.set_mode(self.size)

		self.ticks = 0
		self.running = True

		self.iteration = 0
		self.carpet = pygame.Surface([3**self.iteration, 3**self.iteration])

		# functions
		pygame.display.set_caption("Haferman Carpet")
	
	# weave get to the next generation
	def weave(self):
		# do not overweave!
		if self.iteration >= ITERATIONS:
			return

		# the new carpet will be 3 times as big in each dimension
		self.iteration += 1
		carpet = pygame.Surface([3**self.iteration, 3**self.iteration])
		
		# go thru old carpet
		rct = self.carpet.get_rect()
		for x in range(0, rct.right):
			for y in range(0, rct.bottom):
				# apply rules
				if self.carpet.get_at([x, y]) != (255, 255, 255, 255):
					carpet.set_at([3*x, 3*y], [255, 255, 255])
					carpet.set_at([3*x+2, 3*y], [255, 255, 255])
					carpet.set_at([3*x+1, 3*y+1], [255, 255, 255])
					carpet.set_at([3*x, 3*y+2], [255, 255, 255])
					carpet.set_at([3*x+2, 3*y+2], [255, 255, 255])

		# update carpet
		self.carpet = carpet

	# tick function
	def tick(self):
		# handle events
		for event in pygame.event.get():
			if event.type == pygame.QUIT:
				self.quit()
			if event.type == pygame.KEYDOWN:
				if event.key == pygame.K_SPACE:
					self.screenshot()

				if event.key == pygame.K_q:
					self.weave()

	# render function
	def render(self):
		# fill
		self.surface.fill([0, 0, 0])

		self.surface.blit(pygame.transform.scale(self.carpet, self.size), [0, 0])

		# blit and flip
		self.screen.blit(self.surface, [0, 0])
		pygame.display.flip()
	
	# quits
	def quit(self):
		self.running = False

	# takes a screenshot
	def screenshot(self):
		path = os.getcwd() + "/out/"
		
		try:
			if not os.path.isdir(path):
				os.mkdir(path)
			
			name = "img" + str(len(os.listdir(path))) + ".png"
			pygame.image.save(self.surface, path + name)
		except:
			pass

	# run function (uses tick() and render())
	def run(self):
		ticksPerSecond = 60
		lastTime = time.time() * 1000000000
		nsPerTick =  1000000000.0 / float(ticksPerSecond)
	
		ticks = 0
		frames = 0
	
		lastTimer = time.time() * 1000
		delta = 0.0
		
		while self.running:
			now = time.time() * 1000000000
			delta += float(now - lastTime) / float(nsPerTick)
			lastTime = now
			shouldRender = False
					
			while delta >= 1:
				ticks += 1
				self.ticks += 1
				self.tick()
				delta -= 1
				shouldRender = True
			
			if shouldRender:
				frames += 1
				self.render()
			
			if time.time() * 1000 - lastTimer >= 1000:
				lastTimer += 1000
				
				# debug
				#print("Frames: " + str(frames) + ", ticks: " + str(ticks))
			
				frames = 0
				ticks = 0

# start game
G = GAME()
G.run()
Advertisements

One thought on “Haferman Carpet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s