1
+ from drawing import FLOOR_HEIGHT_PXL
2
+ from drawing import FLOOR_WIDTH_PXL
3
+ from Box import MAX_BOX_SIZE_PXL
4
+ import random
5
+ import copy
6
+
7
+
8
+ class Solution_Position (object ): #gives the box the angle and the down & left or down & right position
9
+ def __init__ (self , Boxes_list , solution , X = 0 , Y = 0 ):
10
+ Copy_Of_Boxes_List = copy .copy (Boxes_list )
11
+ if len (solution ) >= len (Copy_Of_Boxes_List ):
12
+ print "all boxes fitted in"
13
+ for i in solution :
14
+ for j in Copy_Of_Boxes_List :
15
+ if j .box_Num == i .box_Num :
16
+ Copy_Of_Boxes_List .remove (j )
17
+ box = random .choice (Copy_Of_Boxes_List )
18
+ self .box_Num = box .box_Num
19
+ self .angle = random .choice ((0 ,1 ))
20
+ self .position = random .choice ((0 ,1 )) #0 - down & left, 1- down & right
21
+ self .width = box .width
22
+ self .height = box .height
23
+ self .X = X
24
+ self .Y = Y
25
+ self .color = box .color
26
+
27
+
28
+
29
+ class Evristic_solution (object ):
30
+ def __init__ (self , Boxes_List ):
31
+ self .Boxes_List = Boxes_List
32
+ self .positions = []
33
+ self .solve_properly ()
34
+ self .Put_Cost_Value ()
35
+
36
+ def solve_properly (self ):
37
+ self .clear_copies ()
38
+ #flag_of_overfill = False
39
+ #while not(flag_of_overfill):
40
+ self .positions .append (Solution_Position (self .Boxes_List ,self .positions ))
41
+ self .Put_X_Y_to_positions ()
42
+ self .Put_Cost_Value ()
43
+
44
+ def copy (self ,positions ):
45
+ self .positions = []
46
+ for i in positions :
47
+ self .positions .append (copy .copy (i ))
48
+ self .Put_Cost_Value ()
49
+
50
+ def sort_By_X (self ,positions ):
51
+ return positions .X
52
+
53
+ def clear_copies (self ):
54
+ boxes = []
55
+ for position in self .positions :
56
+ boxes .append (position .box_Num )
57
+ if boxes .count (position .box_Num ) > 1 :
58
+ self .positions .remove (position )
59
+
60
+
61
+ def Put_X_Y_to_positions (self ):
62
+ for j in self .positions :
63
+ if j .angle :
64
+ j .height , j .width = j .width , j .height #turn
65
+
66
+ list_of_Y = []
67
+ positions_with_X_Y = []
68
+ flag_of_overfill = False
69
+ for current_box in self .positions : #here begins looking for empty space
70
+ flag_put_in_place = False
71
+ #if not(flag_of_overfill):
72
+ list_of_Y = [1 ]
73
+ for position in positions_with_X_Y :
74
+ list_of_Y .append (position .Y + position .height + 2 ) #+2 is to avoid pixels crosses
75
+ list_of_Y .sort ()
76
+
77
+ for Y in list_of_Y :
78
+ if not (flag_put_in_place ): #to see if we have found space
79
+ possible_positions_list_in_Y_line = [0 ]
80
+ for position in positions_with_X_Y :
81
+ if (position .Y <= Y + current_box .height and position .Y + position .height > Y ): #pay attention to this place with <= or <
82
+ possible_positions_list_in_Y_line .append (position .X )
83
+ possible_positions_list_in_Y_line .append (position .X + position .width )
84
+ possible_positions_list_in_Y_line .append (FLOOR_WIDTH_PXL )
85
+ if len (possible_positions_list_in_Y_line )> 0 :
86
+ possible_positions_list_in_Y_line .sort (reverse = current_box .position )
87
+
88
+
89
+ for current_X in possible_positions_list_in_Y_line :
90
+ if current_box .position :
91
+ possible_X = current_X - current_box .width
92
+ else :
93
+ possible_X = current_X
94
+ if not (flag_put_in_place ):
95
+ if self .Check_for_crosses_of_list (positions_with_X_Y , possible_X , Y , current_box .width , current_box .height ):
96
+ flag_of_overfill , positions_with_X_Y = self .Put_in_X_Y_Position_Down_Right_or_Down_Left (current_box .position , flag_put_in_place , Y , current_box , possible_X , positions_with_X_Y , flag_of_overfill )
97
+ flag_put_in_place = True
98
+ #else:
99
+ #self.positions.remove(current_box)
100
+ #print "removed"
101
+ self .positions = []
102
+ for i in positions_with_X_Y :
103
+ self .positions .append (i )
104
+ return flag_of_overfill
105
+
106
+
107
+ def Put_in_X_Y_Position_Down_Right_or_Down_Left (self , Right_Or_Left , flag_put_in_place ,Y , current_box , possible_X , positions_with_X_Y , flag_of_overfill ):
108
+ if Y + current_box .height < FLOOR_HEIGHT_PXL :
109
+ if Right_Or_Left : #true means to right
110
+ current_box .X = possible_X
111
+ else :
112
+ current_box .X = possible_X
113
+ current_box .Y = Y
114
+ positions_with_X_Y .append (current_box )
115
+ else :
116
+ flag_of_overfill = True
117
+ '''self.positions.remove(current_box)'''
118
+ return flag_of_overfill , positions_with_X_Y
119
+
120
+
121
+
122
+ def Check_for_crosses_of_list (self ,positions_with_X_Y , X , Y , width , height ):
123
+ if (X < 0 or X + width > FLOOR_WIDTH_PXL ):
124
+ return False
125
+ for position in positions_with_X_Y :
126
+ if self .Check_for_crosses (position .X , position .Y ,
127
+ position .X + position .width , position .Y + position .height ,
128
+ X , Y ,
129
+ X + width , Y + height ):
130
+ return False
131
+ return True
132
+
133
+ def Check_for_crosses (self , AX1 , AY1 , AX2 , AY2 , BX1 , BY1 , BX2 , BY2 ):
134
+ if (abs (AX1 - BX1 ) > MAX_BOX_SIZE_PXL or abs (AY1 - BY1 ) > MAX_BOX_SIZE_PXL ):
135
+ return False
136
+ if self .Dot_inside_recktangle (AX1 + 1 , AY1 + 1 , BX1 , BY1 , BX2 , BY2 ):
137
+ return True
138
+ if self .Dot_inside_recktangle (AX1 + 1 , AY2 - 1 , BX1 , BY1 , BX2 , BY2 ):
139
+ return True
140
+ if self .Dot_inside_recktangle (AX2 - 1 , AY1 + 1 , BX1 , BY1 , BX2 , BY2 ):
141
+ return True
142
+ if self .Dot_inside_recktangle (AX2 - 1 , AY2 - 1 , BX1 , BY1 , BX2 , BY2 ):
143
+ return True
144
+
145
+ if self .Dot_inside_recktangle (BX1 + 1 , BY1 + 1 , AX1 , AY1 , AX2 , AY2 ):
146
+ return True
147
+ if self .Dot_inside_recktangle (BX1 + 1 , BY2 - 1 , AX1 , AY1 , AX2 , AY2 ):
148
+ return True
149
+ if self .Dot_inside_recktangle (BX2 - 1 , BY1 + 1 , AX1 , AY1 , AX2 , AY2 ):
150
+ return True
151
+ if self .Dot_inside_recktangle (BX2 - 1 , BY2 - 1 , AX1 , AY1 , AX2 , AY2 ):
152
+ return True
153
+
154
+ if (AX1 < BX1 and AX2 > BX2 and AY1 > BY1 and AY2 < BY2 ):
155
+ return True
156
+ if (BX1 < AX1 and BX2 > AX2 and BY1 > AY1 and BY2 < AY2 ):
157
+ return True
158
+
159
+ return False
160
+
161
+ def Dot_inside_recktangle (self ,X ,Y ,AX ,AY ,BX ,BY ):
162
+ return (X >= AX and X <= BX and Y >= AY and Y <= BY )
163
+
164
+ def Put_Cost_Value (self ):
165
+ Cost = 0.0
166
+ for i in self .positions :
167
+ Cost = Cost + i .width * i .height
168
+ self .cost = Cost / (FLOOR_HEIGHT_PXL * FLOOR_WIDTH_PXL )
169
+
170
+
171
+
172
+
173
+ class Solutions_List (object ):
174
+ def __init__ (self , count , Boxes_List ):
175
+ self .count = count
176
+ self .Boxes_List = Boxes_List
177
+ self .solutions = []
178
+ for i in range (count ):
179
+ self .solutions .append (Evristic_solution (Boxes_List ))
180
+
181
+ def Cycle (self ):
182
+ self .solutions .sort (key = self .sort_By_Cost , reverse = True )
183
+ spliting_percent = 0.4
184
+
185
+ to_Mutation = int (self .count * spliting_percent )
186
+ i = 0
187
+ while i < self .count - 1 :
188
+ if i < to_Mutation :
189
+ self .solutions .append (self .Mutation_of_solution (self .solutions [i ]))
190
+ else :
191
+ solution1 , solution2 = self .Crossbreeding (self .solutions [i ], self .solutions [i + 1 ])
192
+ self .solutions .append (solution1 )
193
+ self .solutions .append (solution2 )
194
+ i = i + 1
195
+ i = i + 1
196
+
197
+ #taking best solutions
198
+ solutions_new = []
199
+ while len (solutions_new ) < self .count and len (self .solutions ) > 1 :
200
+ num = random .randint (0 ,len (self .solutions )- 1 )
201
+ solution1 = self .solutions [num ]
202
+ self .solutions .remove (solution1 )
203
+ solution2 = self .solutions [random .randint (0 ,len (self .solutions )- 1 )]
204
+ self .solutions .remove (solution2 )
205
+ solutions_new .append (self .Selection (solution1 ,solution2 ))
206
+ self .solutions = solutions_new
207
+ self .solutions .sort (key = self .sort_By_Cost , reverse = True )
208
+
209
+
210
+ def Mutation_of_solution (self , solution ):
211
+ mutation_rate = 0.1
212
+ mutated_solution = Evristic_solution (self .Boxes_List )
213
+ mutated_solution .copy (solution .positions )
214
+
215
+ for i in mutated_solution .positions :
216
+ if random .random () <= mutation_rate :
217
+ mutated_solution .positions .insert (mutated_solution .positions .index (i ),Solution_Position (self .Boxes_List , mutated_solution .positions ))
218
+ mutated_solution .positions .remove (i )
219
+ if random .random () <= mutation_rate :
220
+ i .angle = not (i .angle )
221
+ if random .random () <= mutation_rate :
222
+ i .position = not (i .position )
223
+
224
+ mutated_solution .solve_properly ()
225
+ return mutated_solution
226
+
227
+ def Crossbreeding (self , s1 , s2 ):
228
+ crossbreeding_points = 1
229
+ point = 0
230
+ solution1 = copy .copy (s1 )
231
+ solution2 = copy .copy (s2 )
232
+ solution1 .copy (s1 .positions )
233
+ solution2 .copy (s2 .positions )
234
+ min_length = min (len (solution1 .positions ),len (solution2 .positions ))
235
+ for crosbreeding_point in range (crossbreeding_points ):
236
+ point = random .randint (0 , min_length )
237
+ for position in range (point ):
238
+ solution1 .positions [position ], solution2 .positions [position ] = solution2 .positions [position ], solution1 .positions [position ]
239
+
240
+ solution1 .solve_properly ()
241
+ solution2 .solve_properly ()
242
+ return solution1 , solution2
243
+
244
+ def Selection (self , solution1 , solution2 ):
245
+ if solution1 .cost > solution2 .cost :
246
+ return solution1
247
+ else :
248
+ return solution2
249
+
250
+ def sort_By_Cost (self ,solution ):
251
+ return solution .cost
252
+
253
+
0 commit comments