164 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| #!/usr/bin/env python
 | |
| # -*- coding: utf-8 -*-
 | |
| """
 | |
| This module can be used to create and display Mini-Lycacodes
 | |
| 
 | |
| (C) 2022 Louis Heredero  louis.heredero@edu.vs.ch
 | |
| """
 | |
| 
 | |
| import pygame
 | |
| import numpy as np
 | |
| import hamming
 | |
| 
 | |
| S = 600
 | |
| 
 | |
| class LycacodeError(Exception):
 | |
|     pass
 | |
| 
 | |
| class LycacodeMini:
 | |
|     BLACK = (158,17,26)
 | |
|     #BLACK = (0,0,0)
 | |
|     WHITE = (255,255,255)
 | |
|     
 | |
|     OFFSETS = [(0,-1), (1,0), (0,1), (-1,0)]
 | |
|     
 | |
|     FRAME = True
 | |
|     CIRCLES = True
 | |
|     DOTS = True
 | |
|     DB_SQUARES = False
 | |
| 
 | |
|     def __init__(self, id_):
 | |
|         self.id = id_
 | |
|         self.encode()
 | |
|         self.create_matrix()
 | |
| 
 | |
|     def encode(self):
 | |
|         self.bits = f"{self.id:020b}"
 | |
| 
 | |
|         self.bits = list(map(int, self.bits))
 | |
|         parity = [sum(self.bits[i*5:i*5+5])%2 for i in range(4)]
 | |
|         for i in range(4):
 | |
|             self.bits.insert((4-i)*5, parity[3-i])
 | |
| 
 | |
| 
 | |
|     def create_matrix(self):
 | |
|         self.matrix = np.zeros([9, 9])-1
 | |
|         self.matrix[4:5, :] = 0
 | |
|         self.matrix[:, 4:5] = 0
 | |
|         self.matrix[1:2, 3:6] = 0
 | |
|         self.matrix[3:6, 1:2] = 0
 | |
|         self.matrix[-2:-1, -6:-3] = 0
 | |
|         self.matrix[-6:-3, -2:-1] = 0
 | |
|         self.matrix[4,4] = -1
 | |
| 
 | |
|         for y in range(9):
 | |
|             for x in range(9):
 | |
|                 if self.matrix[y,x] == 0:
 | |
|                     self.matrix[y,x] = self.bits.pop(0)
 | |
| 
 | |
|                 if len(self.bits) == 0:
 | |
|                     break
 | |
| 
 | |
|             if len(self.bits) == 0:
 | |
|                 break
 | |
| 
 | |
|     def display(self, surf):
 | |
|         S = min(surf.get_size())
 | |
|         s = int(S/12/3)*3
 | |
|         O = (S-s*9)/2
 | |
| 
 | |
|         surf.fill(self.WHITE)
 | |
| 
 | |
|         # Frame
 | |
|         if self.FRAME:
 | |
|             pygame.draw.rect(surf, self.BLACK, [O-s, O-s, s*11, s*11])
 | |
|             pygame.draw.rect(surf, self.WHITE, [O-s*0.5, O-s*0.5, s*10, s*10])
 | |
| 
 | |
|         # Cross
 | |
|         for i in range(4):
 | |
|             dx, dy = self.OFFSETS[i]
 | |
|             X, Y = S/2 + dx*s*3, S/2 + dy*s*3
 | |
|             if self.CIRCLES:
 | |
|                 for j in range(3):
 | |
|                     dx2, dy2 = self.OFFSETS[(i+j-1)%4]
 | |
|                     pygame.draw.circle(surf, self.BLACK, [X+dx2*s, Y+dy2*s], 0.75*s)
 | |
| 
 | |
|             pygame.draw.rect(surf, self.BLACK, [X-(1.5-abs(dx))*s, Y-(1.5-abs(dy))*s, s*(3-abs(dx)*2), s*(3-abs(dy)*2)])
 | |
| 
 | |
|         pygame.draw.rect(surf, self.BLACK, [O, S/2-s/2, 9*s, s])
 | |
|         pygame.draw.rect(surf, self.BLACK, [S/2-s/2, O, s, 9*s])
 | |
| 
 | |
|         # Dots
 | |
|         if self.DOTS:
 | |
|             for y in range(9):
 | |
|                 for x in range(9):
 | |
|                     if self.matrix[y, x] == 1:
 | |
|                         pygame.draw.circle(surf, self.WHITE, [O+(x+0.5)*s, O+(y+0.5)*s], s/3)
 | |
| 
 | |
|         # Center
 | |
|         pygame.draw.circle(surf, self.WHITE, [O+4.5*s, O+4.25*s], s/6)
 | |
|         pygame.draw.circle(surf, self.WHITE, [O+4.25*s, O+4.75*s], s/6)
 | |
|     
 | |
|     def save(self, path):
 | |
|         S = 600
 | |
|         s = int(S/12)
 | |
|         O = (S-s*9)/2
 | |
|         
 | |
|         BLACK = "#9E111A"
 | |
|         WHITE = "#FFFFFF"
 | |
|         
 | |
|         with open(path, "w") as f:
 | |
|             f.write(f"<svg width='{S}px' height='{S}px' viewbox='0 0 {S} {S}'>\n")
 | |
|             # Background
 | |
|             f.write(f"<rect x='0' y='0' width='{S}' height='{S}' fill='{WHITE}' />\n")
 | |
|             
 | |
|             # Frame
 | |
|             f.write(f"<rect x='{O-s*0.75}' y='{O-s*0.75}' width='{s*10.5}' height='{s*10.5}' style='fill:none;stroke:{BLACK};stroke-width:{0.5*s};' />\n")
 | |
|             
 | |
|             # Cross
 | |
|             for i in range(4):
 | |
|                 dx, dy = self.OFFSETS[i]
 | |
|                 X, Y = S/2 + dx*s*3, S/2 + dy*s*3
 | |
|                 if self.CIRCLES:
 | |
|                     for j in range(3):
 | |
|                         dx2, dy2 = self.OFFSETS[(i+j-1)%4]
 | |
|                         f.write(f"<circle cx='{X+dx2*s}' cy='{Y+dy2*s}' r='{0.75*s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
 | |
|                 
 | |
|                 f.write(f"<rect x='{X-(1.5-abs(dx))*s}' y='{Y-(1.5-abs(dy))*s}' width='{s*(3-abs(dx)*2)}' height='{s*(3-abs(dy)*2)}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
 | |
|             
 | |
|             # Cross
 | |
|             f.write(f"<rect x='{O}' y='{S/2-s/2}' width='{9*s}' height='{s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
 | |
|             f.write(f"<rect x='{S/2-s/2}' y='{O}' width='{s}' height='{9*s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
 | |
|             
 | |
|             # Dots
 | |
|             if self.DOTS:
 | |
|                 for y in range(9):
 | |
|                     for x in range(9):
 | |
|                         if self.matrix[y, x] == 1:
 | |
|                             f.write(f"<circle cx='{O+(x+0.5)*s}' cy='{O+(y+0.5)*s}' r='{s/3}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
 | |
|             
 | |
|             # Center
 | |
|             f.write(f"<circle cx='{O+4.5*s}' cy='{O+4.25*s}' r='{s/6}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
 | |
|             f.write(f"<circle cx='{O+4.25*s}' cy='{O+4.75*s}' r='{s/6}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
 | |
|             
 | |
|             f.write("</svg>")
 | |
| 
 | |
| def save(self):
 | |
|     path = input("Save as (.png or .svg): ")
 | |
|     
 | |
|     if path.endswith(".svg"):
 | |
|         code.save(path)
 | |
|     
 | |
|     else:
 | |
|         pygame.image.save(w, path)
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     import base
 | |
|     
 | |
|     b = base.Base(S, S, "Mini-Lycacode generator")
 | |
|     
 | |
|     code = LycacodeMini(16048)
 | |
|     code.display(b.w)
 | |
|     
 | |
|     b.save = save
 | |
|     b.main() |