# 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), ))