Related
Your friend bought you a present for the New Year, it's a puzzle! The puzzle consists of a number of
wooden rectangular pieces of varying lengths and widths and a board. The goal is to position the
wooden pieces on the board in a way such that all of the pieces will fit.
I have this program and I need help fixing my breadth first search algorithm.
Right now it is very slow and using a lot of memory. I think it is because I deep copy multiple times. The solve function is the main function and will do the heavy work.
I added a text file that has the first line as the dimensions of the puzzle and the rest of the lines are pieceID, pieceWidth and pieceLength respectively.
This is the Input File. Thank you so much.
10,10
1,10,1
2,1,10
3,1,5
4,3,5
5,20,2
6,1,5
7,1,5
8,2,5
import argparse, copy
import queue
import copy
import numpy as np
class PuzzleBoard():
def __init__(self, board_length, board_width ):
self.l = board_length
self.w = board_width
self.state = [[0 for _ in range(board_width)] for _ in range(board_length)]
self.used_piece = []
# Input: point - tuple cotaining (row_index, col_index) of point in self.state
# Returns true if point is out of bounds; otherwise, returns false
def __out_of_bounds(self, point):
# TODO: Implement this function
if(point < 0 or point > (len(self.state)) or (point > (self.state[0]))):
return True
return False
# Finds the next available open space in the PuzzleBoard (looking from the top-left in row-major order)
def __next(self):
for i in range(len(self.state)) :
for j in range(len(self.state[0])):
if (self.state[i][j] == 0):
return (i, j)
return False
# Input: piece - PuzzlePiece object
# Check if piece fits in the next available space (determined by __next method above)
def fits(self, piece):
position = self.__next()
if not position:
return False
#TODO: Check if any part of the piece is out of bounds
#if piece will be out bounds when place rotate to see if that helps
if((( piece.w + position[0] ) > len( self.state )) or (( piece.l + position[1] )> len( self.state[0] ))):
piece.rotate()
if((( piece.w + position[0] ) > len( self.state )) or (( piece.l + position[1] )> len( self.state[0] ))):
return False
#TODO: Check if piece can be placed without intersecting another placed piece
return True
# Input: piece - PuzzlePiece object
# Insert piece into the next available position on the board and update state
def place(self, piece):
# TODO: Bug in this function. Pieces not being placed correctly.
position = self.__next()
if self.fits(piece):
for i in range(position[0], position[0] + piece.w ):
for j in range(position[1], position[1] + piece.l):
if((( piece.w + position[0] ) > len( self.state )) or (( piece.l + position[1] )> len( self.state[0] ))):
return
if(self.state[i][j]== 0):
#self.used_piece.append(piece)
self.state[i][j] = piece.id
else:
continue
return position
def check(self, piece):
position = self.__next()
if(position[0] + piece.w > self.w or position[1] + piece.l > self.l):
return False
return True
# Returns whether the board has been filledwith pieces
def completed(self):
return True if not self.__next() else False
def copy(self):
copied = PuzzleBoard(self.l, self.w)
copied.state = copy.deepcopy(self.state)
return copied
class PuzzlePiece():
def __init__(self, pid, length, width):
self.id = pid
self.l = length
self.w = width
itfits = False
def rotate(self):
#TODO: Bug in this function. Pieces are not rotating correctly
temp = self.l
self.l = self.w
self.w = temp
def orientation(self):
return "H" if self.w >= self.l else "V"
def __str__(self):
return f"ID: {self.id}, LENGTH: {self.l}, WIDTH: {self.w}, ROTATED: {self.rotated}"
def parse_input(filepath) :
#TODO: Bug in this function. Error raised when called
parsed = {'board' : {}, 'pieces' : {}}
with open(filepath, 'r') as f:
file_contents = f.read().strip().split("\n")
board_length, board_width = file_contents[0].strip().split(",")
parsed['board']['length'] = int(board_length)
parsed['board']['width'] = int(board_width)
for i in range(1, len(file_contents)):
#FIX: the issue was fix
pid, l, w = file_contents[i].strip().split(",")
pid, l, w = int(pid), int(l), int(w)
parsed['pieces'][pid] = {}
parsed['pieces'][pid]['length'] = l
parsed['pieces'][pid]['width'] = w
return parsed
def helper(board, piece):
unused = []
#for piece in pieces:
if board.fits(piece):
position = board.place(piece)
board.used_piece.append((piece, position))
return board
def solve(board, remaining, used_pieces=[]):
# TODO: Implement a solution for a variable amount of pieces and puzzle board size.
# HINT: Recursion might help.7
poss = queue.Queue()
poss.put(board)
currboard = PuzzleBoard(len(board.state), len(board.state[0]))
while not currboard.completed():
currboard = poss.get()
#print(currboard.state)
for piece in remaining:
fakeboard = copy.deepcopy(currboard)
if(not (piece.id in np.array(fakeboard.state))):
#if( fakeboard.check(piece)):
poss.put(helper(fakeboard, piece))
print("Suff done")
return currboard
'''if(len(remaining) != 0):
board, used_pieces, unused_pieces = helper(board, remaining, used_pieces)
if board.completed():
return board, used_pieces
for i in board.state:
print(i)
print("\n \n")
return solve(board, unused_pieces, used_pieces)
return board'''
def main():
#TODO: Bug in this function. Positions are not correct after solution is found.
parser = argparse.ArgumentParser()
parser.add_argument('input')
args = parser.parse_args()
parsed = parse_input(args.input)
board = PuzzleBoard(parsed['board']['length'], parsed['board']['width'])
pieces = []
for k, v in parsed['pieces'].items():
pieces.append(PuzzlePiece(k, v['length'], v['width']))
solved = solve(board, pieces)
if not solved:
print("No solution found for given input.")
else:
print("Solution found.")
board = solved
for u, position in solved.used_piece:
print(f"Piece ID: {u.id}, Position:{position}, Orientation: {u.orientation()}")
if __name__ == "__main__":
main()
My question is pretty straightforward. Is there a library in Python that has a data structure that can represent items on a shelf? Essentially, it would need to be a matrix where each row is the same length but the items in each row can be of varying lengths.
Here's a visual representation:
This should tell you if two shelf items overlap on the shelves (in the sense that one is below or above the other).... Assuming you know where your shelf items are by index.
class Item(list):
pass
shelves = [
[Item([1, 2, 3, 4]) ,Item([5, 6 ])],
[Item([7, 8]),Item([9]),Item([10, 11]), Item([12])]
]
# shelf items are indexed by two indices, shelf and item
def shelf_items_overlap(shelves, shelf1, item1, shelf2, item2):
item1_real_index = sum(map(len, shelves[shelf1][:item1]))
item2_real_index = sum(map(len, shelves[shelf2][:item2]))
return range_overlaps(
item2_real_index, item2_real_index + len(shelves[shelf2][item2]),
item1_real_index, item1_real_index + len(shelves[shelf1][item1])
)
def range_overlaps(x11,x12,x21,x22):
''' return if (x11, x12) overlaps (x21, x22) '''
return x21<=x12<=x22 or x21<=x11<=x22 or x11<=x21<=x12 or x11<=x22<=x12
print(shelf_items_overlap(shelves, 0, 1, 1, 0), shelf_items_overlap(shelves, 0, 1, 1, 2))
I think your problem should make a better use of classes than arrays. I know that this maybe this is not the answer you're looking but here is a quick code of a class implementation of items and shelf_rows that gets you the info of what it is in a shelf.
class Item ():
# Init the item class with a lenght
def __init__(self, length, name = 'Item'):
self.name = name
self.length = length
# Allow us to use the len method on item to get the length
def __len__(self):
return self.length
# Show us a clear print of the Item
def __repr__(self):
return '%r of length (%r)' % (self.name,self.length)
class ShelfRow ():
#Make a ShelfRow of a fixed length
def __init__ (self, length):
self.length = length
self.space_left = length
self.items = []
#Use append like if it was a list
def append (self,Item):
if Item.length > self.space_left:
return 'This should throw an error because the length is too long for the space left'
else:
self.items.append (Item)
self.space_left = self.space_left - Item.length
# Use the __getitem__ special method to get the position of an item
def __getitem__(self,position):
return self.items[position]
#Print the content of items
def __repr__(self):
return '%r' % self.items
# Make three items
item_a = Item(4, 'Big Box')
item_b = Item(2, 'Medium Box')
item_c = Item(2, 'Medium Box')
item_d = Item(8, 'Super Big Box')
#Make a shelfRow
shelf_row1 = ShelfRow(8)
shelf_row2 = ShelfRow(8)
#Populate shelfs
shelf_row1.append(item_a)
shelf_row1.append(item_b)
shelf_row1.append(item_c)
shelf_row2.append(item_d)
#Make a shelf, it could be an object too (it should probably)
shelf = [shelf_row1,shelf_row2]
#Print what is in every shelf_row
for shelf_row in shelf:
print(shelf_row)
The other answer is probably the closest to what you want but I get the feeling that maybe you could do for something a little more abstract to solve your problem.
Anyways I hope that this was useful.
I am not aware of any module, but this seems like a traditional "Make this data structure" type of question. So here's a base you can work with, and it may seem similar to other questions, but this should work and satisfy your needs. Its pretty much an implementation that uses the idea used in page allocation as your problem can be seen as you need frame to contain a certain amount of pages of a fixed size. It could be optimized by using a better algorithm (or process to add) but I forgot which one I used is called nor did I feel like implementing something more complicated.
class Item:
def set_width(self, width):
self.width = width
def get_width(self):
return self.width
def __init__(self, width=0):
self.width = width
class Shelf:
def add_item(self, item):
if item.get_width() > self.max_width:
print("Item will not fit in the shelf.")
return False
row = 0
while (row < len(self.rows)):
if (self.get_row_tot(row) + item.get_width()) <= self.max_width:
self.rows[row].append(item)
return True
row += 1
# Stop here, we want to prevent addition of a shelf
if max_height != -1 and row >= max_height:
print("Item will not fit in the shelf.")
return False
self.rows.append([item])
return True
def get_row_tot(self, row):
tot = 0
for i in self.rows[row]:
tot += i.get_width()
return tot
def remove_item(self, row, item):
if row < len(self.rows):
self.rows[row].remove(item)
return True
else:
print("Row does not exist")
return False
def __init__(self, max_width, max_height=-1):
"""
max_height = -1 means no height limit
"""
self.max_width = max_width
self.max_height = max_height
self.rows = []
self.head = 0
a = Shelf(3)
b = Item(1)
c = Item(1)
d = Item(2)
e = Item(2)
a.add_item(b)
a.add_item(c)
a.add_item(d)
a.remove_item(0, c)
a.remove_item(2, e)
a.add_item(e)
Like I said, this could be optimized and some additions could be made such as a method to swap, set, search, sort and so on so forth. You can also modify Item to be an object you're working with.
I'm creating a class for a K-Order Min-heap. I'm storing the heap as a list. I'm having trouble with implementing remove_min. I know that the process of removing the minimum of a heap is:
Remove first element. This is the minimum.
Swap the first element and the last element.
Bubble the new top element down until it satisfies the heap property.
So I need a remove_min and a helper function, bubbledown. I can't use heapq because it only accounts for binary heaps and this class needs to take a k-order heap. Here's what I have so far:
class KHeap:
def __init__(self, lst=[], k=2):
self.heap = []
self.k = k #order of heap
for v in lst:
self.insert(v)
def children(self, i): #returns a list of the children of the item in index i
heap = self.heap
result = []
for x in range(self.k*i+1, self.k*i+self.k+1):
if x<len(heap):
result.append(heap[x])
else:
pass
return result
def parent(self, i): #returns the parent of item in index i
heap = self.heap
if i==0:
return None
result = i//self.k
return heap[result]
def bubbleup(self, i):
if i == 0:
return None
elif self.heap[i] < self.parent(i):
self.heap[i], self.heap[i // self.k] = self.heap[i // self.k], self.heap[i]
self.bubbleup(i // self.k)
def insert(self, value): #use bubbleup
self.heap.append(value)
self.bubbleup(len(self.heap)-1)
def bubbledown(self, i, d=1):
if i==0:
return None
small = i
for k in range(self.children(i)):
if self.heap[k]<self.heap[small]:
small = k
self.heap[i], self.heap[small] = self.heap[small], self.heap[i]
self.bubbledown(small)
def remove_min(self): #use bubbledown
if len(self.heap) == 0:
return None
if len(self.heap) == 1:
return self.heap.pop()
minimum = self.heap[0]
self.heap[0] = self.heap.pop()
self.bubbledown(0)
return minimum
Now, when I remove_min, the result isn't heapified. For example, if I have a ternary heap [1, 10, 18, 22, 15, 30], k=3 and I remove the minimum, the result is [30, 10, 18, 22, 15]. It seems like the element that I move to the top never gets bubbled down.
So I post a iteration version, which can solve the i == 0 problem.
def bubbledown(self, i, d=1):
small = i
size = len(self.heap)
while (i < size):
// find the smallest child
for k in range(self.children(i)):
if self.heap[k] < self.heap[small]:
small = k
self.heap[i], self.heap[small] = self.heap[small], self.heap[i]
// stop here
if small == i:
break
else:
i = small
So i was given this question. Consider the Stack and the Queue class with standard set of operations. Using the Stack and Queue class, what items are contained in them just before the mysteryFunction is called AND just after the mysteryFunction is called?
Here is the code:
def mysteryFunction(s, q):
q.enqueue('csc148')
q.enqueue(True)
q.enqueue(q.front())
q.enqueue('abstract data type')
for i in range(q.size()):
s.push(q.dequeue())
while not s.is_empty():
q.enqueue(s.pop())
if __name__ == '__main__':
s=Stack()
q=Queue()
#About to call mysteryFunction
#What are contents of s and q at this point?
mysteryFunction(s, q)
#mysteryFunction has been called.
#What are contents of s and q at this point?
I'm having trouble understanding object oriented programming as i'm new to this topic. Is there any link that breaks down Stacks and Queues and what they do?
In general, stacks are LIFO and queues are FIFO.
In Python, you can use the collections module to experiment with stacks and queues:
>>> from collections import deque
>>> stack = deque()
>>> stack.append(10)
>>> stack.append(20)
>>> stack.append(30)
>>> stack
deque([10, 20, 30])
>>> stack.pop() # LIFO
30
>>> stack.pop()
20
>>>
>>> queue = deque()
>>> queue.append(10)
>>> queue.append(20)
>>> queue.append(30)
>>> queue
deque([10, 20, 30])
>>> queue.popleft() # FIFO
10
>>> queue.popleft()
20
See following links for more information:
Stack
Queue
Visually these two data structures can be seen in a following way:
Stack:
Description:
There are variations of this data structure. However, in simple terms - as one can observe in the image provided, when you add to this data structure you place on top of what is already there and when you remove you also take from the top. You can view it as a stack of books which you go through one by one starting from the top and all the way down.
Queue
Description:
There are also variations on this particular data structure, however in simple terms - as you can see in the image provided, when you add to this data structure the new element goes in the begining and when you remove its the last element from the list which is being removed. You can imagine it as a queue you got in a shop where you stand behind a lot of people waiting for your turn to come to the counter to pay for your items.
To test this line by line, here are implementations of the classes (wrappers around deque) that are used in the task:
from collections import deque
class Queue(deque):
enqueue = deque.append
dequeue = deque.popleft
def front(self):
return self[-1]
def size(self):
return len(self)
class Stack(deque):
push = deque.append
def is_empty(self):
return not self
STACK #LIFO
class stack(object):
def __init__(self):
self.items = []
def isEmpty(self):
return self.items==[]
def push(self,item):
self.items.append(item)
def pop (self):
return self.items.pop()
def peek(self):
return self.items[len(self.items) - 1]
def size(self):
return (len(self.items))
s = stack()
print (s.isEmpty())
>> True
s.push(1)
s.push('3')
s.peek()
>>'3'
s.size()
>> 2
Queue #FIFO
class Queue(object):
def __init__(self):
self.items = []
def isEmpty(self):
return self.items==[]
def enqueue(self,item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return (len(self.items))
q = Queue()
q.isEmpty()
>>True
q.enqueue(1)
q.enqueue(2)
q.dequeue()
>>1
The first code explains about the stack , we need to create a list and while pushing the element use append and fill the list , similar to what we have in array stack. While pop , pop out the end from where you pushed it.
class Stack:
def __init__(self):
self.stack = []
def push_element(self,dataval):
self.stack.append(dataval)
return self.stack
def pop_element(self):
if len(self.stack) ==0:
print("Stack is empty")
else:
self.stack.pop()
return self.stack
def peek_element(self):
return self.stack[0]
class Queue:
def __init__(self):
self.stack = []
def push_ele(self,data):
self.stack.append(data)
def pop_ele(self):
self.stack.pop(0)
def display(self):
print(self.stack)
class stack:
def __init__(self,n): #constructor
self.no = n # size of stack
self.Stack = [] # list for store stack items
self.top = -1
def push(self): # push method
if self.top == self.no - 1: # check full condition
print("Stack Overflow.....")
else:
n = int(input("enter an element :: "))
self.Stack.append(n) # in list add stack items use of append method
self.top += 1. # increment top by 1
def pop(self): # pop method
if self.top == -1: # check empty condition
print("Stack Underflow....")
else:
self.Stack.pop(). # delete item from top of stack using pop method
self.top -= 1 # decrement top by 1
def peep(self): #peep method
print(self.top,"\t",self.Stack[-1]) #display top item
def disp (self): # display method
if self.top == -1: # check empty condition
print("Stack Underflow....")
else:
print("TOP \tELEMENT")
for i in range(self.top,-1,-1): # print items and top
print(i," \t",self.Stack[i])
n = int(input("Enter Size :: ")) # size of stack
stk = stack(n) # object and pass n as size
while(True): # loop for choice as a switch case
print(" 1: PUSH ")
print(" 2: POP ")
print(" 3: PEEP ")
print(" 4: PRINT ")
print(" 5: EXIT ")
option = int(input("enter your choice :: "))
if option == 1:
stk.push()
elif option == 2:
stk.pop()
elif option == 3:
stk.peep()
elif option == 4:
stk.disp()
elif option == 5:
print("you are exit!!!!!")
break
else:
print("Incorrect option")
I have an entire Deque Array class that looks like this:
from collections import deque
import ctypes
class dequeArray:
DEFAULT_CAPACITY = 10 #moderate capacity for all new queues
def __init__(self):
self.capacity = 5
capacity = self.capacity
self._data = self._make_array(self.capacity)
self._size = 0
self._front = 0
def __len__(self):
return self._size
def __getitem__(self, k): #Return element at index k
if not 0 <= k < self._size:
raise IndexError('invalid index')
return self._data[k]
def isEmpty(self):
if self._data == 0:
return False
else:
return True
def append(self, item): #add an element to the back of the queue
if self._size == self.capacity:
self._data.pop(0)
else:
avail = (self._front + self._size) % len(self._data)
self._data[avail] = item
self._size += 1
#def _resize(self, c):
#B = self._make_array(c)
#for k in range(self._size):
#B[k] = self._A[k]
#self._data = B
#self.capacity = capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
def removeFirst(self):
if self._size == self.capacity:
self._data.pop(0)
else:
answer = self._data[self._front]
self._data[self._front] = None
self._front = (self._front + 1) % len(self._data)
self._size -= 1
print(answer)
def removeLast(self):
return self._data.popleft()
def __str__(self):
return str(self._data)
and when I try to print the deque in the main it prints out something like this,
<bound method dequeArray.__str__ of <__main__.dequeArray object at 0x1053aec88>>
when it should be printing the entire array. I think i need to use the str function and i tried adding
def __str__(self):
return str(self._data)
and that failed to give me the output. I also tried just
def __str__(self):
return str(d)
d being the deque array but I still am not having any success. How do I do i get it to print correctly?
you should call the str function of each element of the array that is not NULL, can be done with the following str function:
def __str__(self):
contents = ", ".join(map(str, self._data[:self._size]))
return "dequeArray[{}]".format(contents)
What I get when I try to q = dequeArray(); print(q) is <__main__.py_object_Array_5 object at 0x006188A0> which makes sense. If you want it list-like, use something like this (print uses __str__ method implicitly):
def __str__(self):
values = []
for i in range(5):
try:
values.append(self._data[i])
except ValueError: # since accessing ctypes array by index
# prior to assignment to this index raises
# the exception
values.append('NULL (never used)')
return repr(values)
Also, several things about the code:
from collections import deque
This import is never user and should be removed.
DEFAULT_CAPACITY = 10
is never used. Consider using it in the __init__:
def __init__(self, capacity=None):
self.capacity = capacity or self.DEFAULT_CAPACITY
This variable inside __init__ is never user and should be removed:
capacity = self.capacity
def _make_array(self, c):
capacity = self.capacity
return (capacity * ctypes.py_object)()
Though this is a valid code, you're doing it wrong unless you're absolutely required to do it in your assignment. Ctypes shouldn't be used like this, Python is a language with automated memory management. Just return [] would be fine. And yes, variable c is never used and should be removed from the signature.
if self._data == 0
In isEmpty always evaluates to False because you're comparing ctypes object with zero, and ctypes object is definitely not a zero.