Jam/src/polyomino.py
2024-02-22 16:41:45 -05:00

155 lines
5.6 KiB
Python

# Copyright 2021-2023 Ian Jauslin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# a polyomino is a collection of elements, defined in elements.py
from kivy.graphics import Color,Line
from point import l_infinity
from element import Element_square,Element_circle
# parent class of all polyominos
class Polyomino():
def __init__(self,**kwargs):
# elements that make up the polyomino
self.elements=kwargs.get("elements",[])
self.color=kwargs.get("color",(0,0,1))
self.selected=False
# mesh of background grid (no grid for mesh size 0)
self.grid=kwargs.get("grid",0)
# draw Voronoi cell
self.voronoi=kwargs.get("voronoi",False)
# draw function
def draw(self,painter,**kwargs):
alpha=kwargs.get("alpha",1)
# set color
if not self.selected:
Color(*self.color,alpha)
else:
(r,g,b)=self.color
# darken selected
Color(r/2,g/2,b/2,alpha)
for element in self.elements:
element.draw(painter)
# draw boundary
self.stroke(painter)
# draw boundary (override for connected polyominos)
def stroke(self,painter):
# white
Color(1,1,1)
for element in self.elements:
element.stroke(painter)
# move by delta
def move(self,delta):
for element in self.elements:
element.pos+=delta
# whether x is in the support of the polyomino
def in_support(self,x):
for element in self.elements:
if element.in_support(x):
return True
return False
# check whether self interacts with candidate if candidate were moved by offset
def check_interaction(self,candidate,offset):
for element1 in self.elements:
for element2 in candidate.elements:
# add offset
element2.pos+=offset
if element1.check_interaction(element2):
# reset offset
element2.pos-=offset
return True
# reset offset
element2.pos-=offset
return False
# square
class Square(Polyomino):
def __init__(self,x,y,**kwargs):
super(Square,self).__init__(**kwargs,elements=[Element_square(x,y,size=kwargs.get("size",1.0))])
# cross
class Cross(Polyomino):
def __init__(self,x,y,**kwargs):
super(Cross,self).__init__(**kwargs,elements=[\
Element_square(x,y,1,aspect=3),\
Element_square(x+1,y,1),\
Element_square(x-1,y,1)\
])
# redefine stroke to avoid lines between touching elements
def stroke(self,painter):
# convert to graphical coordinates
coordx=painter.pos_tocoord_x(self.elements[0].pos.x)
coordy=painter.pos_tocoord_y(self.elements[0].pos.y)
Color(1,1,1)
Line(points=(
*(coordx-0.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy-1.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy-1.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx+1.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx+1.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy+1.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy+1.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx-1.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx-1.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy-0.5*painter.base_size),
))
# disk
class Disk(Polyomino):
def __init__(self,x,y,**kwargs):
super(Disk,self).__init__(**kwargs,elements=[Element_circle(x,y,size=kwargs.get("size",1.0))])
# 3-staircase
class Staircase(Polyomino):
def __init__(self,x,y,**kwargs):
super(Staircase,self).__init__(**kwargs,elements=[\
Element_square(x,y+1,1,aspect=3),\
Element_square(x+1,y,1),\
Element_square(x+1,y+1,1),\
Element_square(x+2,y,1)\
])
# redefine stroke to avoid lines between touching elements
def stroke(self,painter):
# convert to graphical coordinates
coordx=painter.pos_tocoord_x(self.elements[0].pos.x)
coordy=painter.pos_tocoord_y(self.elements[0].pos.y)
Color(1,1,1)
Line(points=(
*(coordx-0.5*painter.base_size,coordy-1.5*painter.base_size),
*(coordx+2.5*painter.base_size,coordy-1.5*painter.base_size),
*(coordx+2.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx+1.5*painter.base_size,coordy-0.5*painter.base_size),
*(coordx+1.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy+0.5*painter.base_size),
*(coordx+0.5*painter.base_size,coordy+1.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy+1.5*painter.base_size),
*(coordx-0.5*painter.base_size,coordy-1.5*painter.base_size),
))