Beispiel #1
0
    def dealHands(self, hands):
        """Deal out full hands."""
	# Allow for a single hand
	if isinstance(hands, Hand):
	    h = hands
	    hands = Hands()
	    hands.addHand(h)
        while True:
            cardDealt = False
            for hand in hands:
		if not isinstance(hand, Hand):
		    raise InvalidHandTypeException("Bad hand type (%s)"
						   % hand.__class__)
                if len(hand) < hand.getMaxCards():
		    try:
			hand.addCard(self.pop())
		    except IndexError:
			raise NotEnoughCardsException
                    cardDealt = True
            if cardDealt == False:
                break
Beispiel #2
0
    def __init__(self,
                 packer,
                 table_corners: tuple,
                 packing_side,
                 frame_size=(1366, 768)):
        self.animator = Animator(30)
        self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM
        self.show_after_completion = True
        self.part_detections = []
        self.active_wrist = None
        self.all_parts_are_in_box = False
        self.pack_task_completed = False
        self.all_visible_parts = []
        self.box_detection = None
        self.previous_blurred_table = None
        self.part_tracker = ObjectTracker()
        self.part_detector = PartDetector()
        self.box_detector = BoxDetector()
        self.opened_box_tracker = ObjectTracker(distance_threshold=150)
        self.closed_box_tracker = ObjectTracker()
        self.next_pack_task_time = None
        self.cur_pack_task = None
        self.table_corners = {
            'tl': table_corners[0],
            'tr': table_corners[1],
            'br': table_corners[2],
            'bl': table_corners[3]
        }
        self.packer = packer
        self.packing_side = packing_side
        self.frame_size = frame_size

        self.rect_table_corners = self.calculate_rect_table_area()

        self.rect_work_place_corners = self.define_work_place_corners()
        self.worker_hands = Hands(self.rect_work_place_corners['tl'])
        self.width = self.rect_table_corners['br'][
            0] - self.rect_table_corners['tl'][0]
        self.height = self.rect_table_corners['br'][
            1] - self.rect_table_corners['tl'][1]
Beispiel #3
0
    def __init__(self, numHands = 0, hands=None):
	assertInstance(numHands, int)
	self.deck = self.deckClass()
	if numHands and (numHands > self.getMaxHands()):
	    raise TooManyHandsException
	self.numHands = numHands
	self.hands = Hands()
	self.lowHandsWin = (self.lowHandRankerClass != None)
        if self.lowHandRankerClass:
            self.lowHandRanker = self.lowHandRankerClass()
	self.highHandsWin = (self.highHandRankerClass != None)
        if self.highHandRankerClass:
            self.highHandRanker = self.highHandRankerClass()
	self.highWins = []
	self.lowWins = []
	self.scoops = []
	if hands:
	    self.addHands(hands)
Beispiel #4
0
    def simulateGame(self):
	self.__checkStatArrays()
	self.gameNum += 1
	# Make a copy of deck, hands and board
	deck = self.deck.copy()
	deck.shuffle()
	hands = Hands()
	for hand in self.hands:
	    if isinstance(hand, HandGenerator):
		hands.addHand(hand.generateHand(deck = deck))
	    else:
		hands.addHand(hand.copy())
	# If we have less than numHands, fill it out
	while len(hands) < self.numHands:
	    hands.addHand(self.handClass())
	if self.board is None:
	    board = None
	else:
	    board = self.board.copy()
	# Fill out hands and board
	deck.dealHands(hands)
	if board is not None:
	    # Deal board
	    deck.dealHands(board)
	    for hand in hands:
		hand.setBoard(board)
	    self.lastGameBoard = board
	self.lastGameHands = hands
	# Find winning hands
	if self.highHandsWin:
	    (bestHighRank, highWinners) = self._findHighHands(hands, board)
	    self.lastGameHighWinners = highWinners
	    self.lastGameHighRank = bestHighRank
	    for winner in highWinners:
		self.highWins[winner] += 1
	if self.lowHandsWin is True:
	    (bestLowRank, lowWinners) = self._findLowHands(hands, board)
	    self.lastGameLowWinners = lowWinners
	    self.lastGameLowRank = bestLowRank
	    for winner in lowWinners:
		self.lowWins[winner] += 1
	if self.lowHandsWin and self.highHandsWin:
	    self.lastGameScooper = self._findScooper(lowWinners, highWinners)
	    if self.lastGameScooper is not None:
		self.scoops[self.lastGameScooper] += 1
Beispiel #5
0
    def simulate_game(self):
	# Make a copy of deck, hands and board
	deck = self.deck.copy()
	deck.shuffle()
	hands = Hands()
        # Deal out predefined hands
        if self.predefined_hands is not None:
            for hand in self.predefined_hands:
                if isinstance(hand, HandGenerator):
                    hands.addHand(hand.generateHand(deck = deck))
                else:
                    hands.addHand(hand.copy())
                    deck.removeCards(hand)
	# If we have less than numHands, fill it out
	while len(hands) < self.number_of_hands:
	    hands.addHand(self.HandClass())
	if self.board is None:
	    board = None
	else:
	    board = self.board.copy()
	# Fill out hands and board
	deck.dealHands(hands)
	if board is not None:
	    # Deal board
	    deck.dealHands(board)
	    for hand in hands:
		hand.setBoard(board)
        result = Result(hands, board=board)
	# Find winning hands
	if self.high_ranker is not None:
	    (high_winners, bestHighRank) = self.high_ranker.bestHand(hands)
            result.high_winners = high_winners
            result.winning_high_rank = bestHighRank
	if self.low_ranker is not None:
	    (low_winners, bestLowRank) = self.low_ranker.bestHand(hands)
            result.low_winners = low_winners
            result.winning_low_rank = bestLowRank
        return result
Beispiel #6
0
class PokerGame:
    # Type of hand used in this game, should be redefined in subclasses
    handClass = Hand

    # Type of Deck used in this game
    deckClass = Deck

    # Name of this game
    gameName = "Poker"

    # Support for board here, but don't allow setting in this class
    board = None

    # Class to use to determine rank for hi and/or low
    # If == None then no winner in that direction.
    highHandRankerClass = Ranker
    lowHandRankerClass = None

    # Ranker instances to use to determine hand ranks
    highHandRanker = None
    lowHandRanker = None

    # Low hand must be eight or berrer?
    lowHandEightOrBetter = False

    # For each hand, number of wins high
    highWins = []

    # For each hand, number of wins low
    lowWins = []

    # For each hand, number of scoops (wins both ways)
    scoops = []

    # What game number are we playing
    gameNum = 0

    # Hands from last game simulated
    lastGameHands = None

    # Board from last game simulated
    lastGameBoard = None

    # High winners for last game simulated
    lastGameHighWinners = None

    # High rank for last game simulated
    lastGameHighRank = None

    # Low winners for last game simulated
    lastGameLowWinners = None

    # Low rank for last game simulated
    lastGameLowRank = None

    # Scoopers for last game simulated
    lastGameScoopers = None

    def __init__(self, numHands = 0, hands=None):
	assertInstance(numHands, int)
	self.deck = self.deckClass()
	if numHands and (numHands > self.getMaxHands()):
	    raise TooManyHandsException
	self.numHands = numHands
	self.hands = Hands()
	self.lowHandsWin = (self.lowHandRankerClass != None)
        if self.lowHandRankerClass:
            self.lowHandRanker = self.lowHandRankerClass()
	self.highHandsWin = (self.highHandRankerClass != None)
        if self.highHandRankerClass:
            self.highHandRanker = self.highHandRankerClass()
	self.highWins = []
	self.lowWins = []
	self.scoops = []
	if hands:
	    self.addHands(hands)

    def resetStats(self):
	numHands  =  max(len(self.hands), self.numHands)
	if self.highHandsWin:
	    self.highWins = [ 0 ] * numHands
	if self.lowHandsWin:
	    self.lowWins = [ 0 ] * numHands
	if self.lowHandsWin and self.highHandsWin:
	    self.scoops = [ 0 ] * numHands
	self.gameNum = 0

    def __checkStatArrays(self):
	"""Make sure all the statistic arrays are long enough.
	In case a hand was added since we last simualted a game."""
	if len(self.highWins) < len(self.hands):
	    self.highWins.extend([ 0 ] * (len(self.hands)-len(self.highWins)))
	if len(self.lowWins) < len(self.hands):
	    self.lowWins.extend([ 0 ] * (len(self.hands)-len(self.lowWins)))
	if len(self.scoops) < len(self.hands):
	    self.scoops.extend([ 0 ] * (len(self.hands)-len(self.scoops)))

    @classmethod
    def getHandClass(cls):
	return cls.handClass

    def addHands(self, hands):
	if hands is None:
	    return
	if isinstance(hands, Hand) or isinstance(hands, HandGenerator):
	    hands = [ hands ]
	if len(self.hands) + len(hands) > self.getMaxHands():
	    raise TooManyHandsException
	for hand in hands:
	    if hand is None:
		self.hands.addHand(self.handClass())
	    else:
		self.hands.addHand(hand)
		self.deck.removeCards(hand)
				     
    def addHand(self, hand):
	assertInstance(hand, Hand)
	self.addHands(hand)

    def addHandGenerator(self, hg):
	assertInstance(hg, HandGenerator)
	self.hands.addHand(hg)

    @classmethod
    def getMaxHands(cls):
	cardsPerHand = cls.handClass.maxCards
	if cls.hasBoard():
	    boardCards = cls.handClass.boardClass.maxCards
	else:
	    boardCards = 0
	numCards = cls.deckClass.numCards - boardCards
	return int(numCards/cardsPerHand)
	
    def getNumHands(self):
	return max(self.numHands, len(self.hands))

    def getHands(self):
	return self.hands

    @classmethod
    def hasBoard(cls):
	return (cls.handClass.boardClass != None)

    def setBoard(self, board):
	if not self.hasBoard():
	    raise HandHasNoBoardException()
	if board:
	    assertInstance(board, Cards)
	    self.deck.removeCards(board)
	self.board = board

    def getBoard(self):
	if not self.hasBoard():
	    raise HandHasNoBoardException()
	return self.board

    def getHighWins(self):
	"""Return an array with how many times each hand won high."""
	if not self.highHandsWin:
	    return None
	return self.highWins

    def getLowWins(self):
	"""Return an array with how many times each hand won low."""
	if not self.lowHandsWin:
	    return None
	return self.lowWins

    def getWins(self):
	"""Return total wins by each hand (high or low)."""
	if not self.lowHandsWin:
	    return self.highWins
	if not self.highHandsWin:
	    return self.lowWins
	wins = []
	for hand in self.highWins:
	    wins = self.highWins[hand] + self.lowWins[hand]
	return wins

    def getScoops(self):
	"""Return an array with how many times each hand won both ways."""
	if not (self.highHandsWin and self.lowHandsWin):
	    return None
	return self.scoops

    def simulateGames(self, numGames = 100, callback=None, callbackArg=None,
		      resetStats = True):
	"""Simulate a bunch of games with starting hands. Returns
	a array with number of wins for each hand."""
	assertInstance(numGames, int)
	if self.getNumHands() == 0:
	    raise PokerGameStateException("Zero hands defined.")
	if resetStats:
	    self.resetStats()
	while self.gameNum < numGames:
	    self.simulateGame()
	    if callback is not None:
		if callbackArg:
		    callback(self, callbackArg)
		else:
		    callback(self)

    def simulateGame(self):
	self.__checkStatArrays()
	self.gameNum += 1
	# Make a copy of deck, hands and board
	deck = self.deck.copy()
	deck.shuffle()
	hands = Hands()
	for hand in self.hands:
	    if isinstance(hand, HandGenerator):
		hands.addHand(hand.generateHand(deck = deck))
	    else:
		hands.addHand(hand.copy())
	# If we have less than numHands, fill it out
	while len(hands) < self.numHands:
	    hands.addHand(self.handClass())
	if self.board is None:
	    board = None
	else:
	    board = self.board.copy()
	# Fill out hands and board
	deck.dealHands(hands)
	if board is not None:
	    # Deal board
	    deck.dealHands(board)
	    for hand in hands:
		hand.setBoard(board)
	    self.lastGameBoard = board
	self.lastGameHands = hands
	# Find winning hands
	if self.highHandsWin:
	    (bestHighRank, highWinners) = self._findHighHands(hands, board)
	    self.lastGameHighWinners = highWinners
	    self.lastGameHighRank = bestHighRank
	    for winner in highWinners:
		self.highWins[winner] += 1
	if self.lowHandsWin is True:
	    (bestLowRank, lowWinners) = self._findLowHands(hands, board)
	    self.lastGameLowWinners = lowWinners
	    self.lastGameLowRank = bestLowRank
	    for winner in lowWinners:
		self.lowWins[winner] += 1
	if self.lowHandsWin and self.highHandsWin:
	    self.lastGameScooper = self._findScooper(lowWinners, highWinners)
	    if self.lastGameScooper is not None:
		self.scoops[self.lastGameScooper] += 1

    def _findHighHands(self, hands, board):
	highWinners = [ 0 ]
	bestHighRank = self.highHandRanker.rankHand(hands[0])
	for index in range(1,len(hands)):
	    rank = self.highHandRanker.rankHand(hands[index])
	    if rank == bestHighRank:
		highWinners.append(index)
	    elif rank > bestHighRank:
		highWinners = [index]
		bestHighRank = rank
	return (bestHighRank, highWinners)

    def _findLowHands(self, hands, board):
	if self.lowHandEightOrBetter and (board is not None):
	    # See if low is possible given board
	    if board.eightLowPossible() is False:
		# Nope, don't bother checking for low hands
		return (None, [])
	bestLowRank = None
	lowWinners = []
	for index in range(len(hands)):
	    hand = hands[index]
	    if (self.lowHandEightOrBetter and
		(hand.eightLowPossible() is False)):
		# Hand cannot qualify for low, don't bother checking
		continue
	    rank = self.lowHandRanker.rankHand(hand)
	    if (self.lowHandEightOrBetter and
		(not rank.isEightOrBetterLow())):
		# Hand did not qualify for low
		continue
	    if ((bestLowRank is None) or
		(rank < bestLowRank)):
		lowWinners = [index]
		bestLowRank = rank
	    elif rank == bestLowRank:
		lowWinners.append(index)
	return (bestLowRank, lowWinners)

    def _findScooper(self, lowWinners, highWinners):
	"""Was there one winner of the whole pot?"""
	if ((len(lowWinners) == 1) and
	    (len(highWinners) == 1) and
	    (lowWinners[0] == highWinners[0])):
	    return lowWinners[0];
	return None

    def lastGameToString(self):
	import string
	s=""
	if self.hasBoard():
	    s += "Board: " + str(self.lastGameBoard) + " "
	if self.highHandsWin:
	    s += "High: %s " % self.lastGameHighRank
	    s += "("
	    s += ",".join(["%d:%s" % (hand + 1, self.lastGameHands[hand])
			   for hand in self.lastGameHighWinners])
	    s += ") "
	if self.lowHandsWin and len(self.lastGameLowWinners):
	    s += "Low: %s " % self.lastGameLowRank
	    s += "("
	    s += ",".join(["%d:%s" % (hand + 1, self.lastGameHands[hand])
			   for hand in self.lastGameLowWinners])
	    s += ") "
	if self.lowHandsWin and self.highHandsWin:
	    if self.lastGameScooper is not None:
		s += "(Hand %d scoops)" % (self.lastGameScooper + 1)
	s.strip()
	return s

    def statsToString(self):
	s = ""
	for hand in range(self.getNumHands()):
	    s += "%2d:" % (hand + 1)
	    if hand >= len(self.hands):
		handStr = "XX " * self.handClass.getMaxCards()
		s += handStr
	    else:
		s += str(self.hands[hand]) + " "
	    if self.highHandsWin:
		wins = self.highWins[hand]
		s += "High wins %4d (%3.0f%%)" % (
		    wins,
		    100.0 * wins / self.gameNum)
	    if self.lowHandsWin:
		wins = self.lowWins[hand]
		s += " Low wins %4d (%3.0f%%)" % (
		    wins,
		    100.0 * wins / self.gameNum)
	    if self.highHandsWin and self.lowHandsWin:
		s += " Scoops: %d" % self.scoops[hand]
	    s += "\n"
	return s
Beispiel #7
0
def hand():
    hand = Hands()
    return hand
Beispiel #8
0
class WorkPlace:
    WORKER_PLACE_SIZE = 300
    FINAL_FRAMES_NUM = 60

    def calculate_rect_table_area(self):
        tcs = self.table_corners
        min_x, min_y = min(tcs['tl'][0],
                           tcs['bl'][0]), min(tcs['tl'][1], tcs['tr'][1])
        max_x, max_y = max(tcs['tr'][0],
                           tcs['br'][0]), max(tcs['bl'][1], tcs['br'][1])
        rect_table_corners = {'tl': (min_x, min_y), 'br': (max_x, max_y)}
        return rect_table_corners

    font = ImageFont.truetype("arial.ttf", 16)
    bold_font = ImageFont.truetype("arial_bold.ttf", 16)
    large_font = ImageFont.truetype("arial.ttf", 20)
    line_height_size = 20

    def get_table_view_from_frame(self, frame: np.ndarray):
        table_rect = self.rect_table_corners
        return frame[table_rect['tl'][1]:table_rect['br'][1],
                     table_rect['tl'][0]:table_rect['br'][0]]

    def get_work_place_view_from_frame(self, frame: np.ndarray):
        work_pl_rect = self.rect_work_place_corners
        return frame[work_pl_rect['tl'][1]:work_pl_rect['br'][1],
                     work_pl_rect['tl'][0]:work_pl_rect['br'][0]]

    def __init__(self,
                 packer,
                 table_corners: tuple,
                 packing_side,
                 frame_size=(1366, 768)):
        self.animator = Animator(30)
        self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM
        self.show_after_completion = True
        self.part_detections = []
        self.active_wrist = None
        self.all_parts_are_in_box = False
        self.pack_task_completed = False
        self.all_visible_parts = []
        self.box_detection = None
        self.previous_blurred_table = None
        self.part_tracker = ObjectTracker()
        self.part_detector = PartDetector()
        self.box_detector = BoxDetector()
        self.opened_box_tracker = ObjectTracker(distance_threshold=150)
        self.closed_box_tracker = ObjectTracker()
        self.next_pack_task_time = None
        self.cur_pack_task = None
        self.table_corners = {
            'tl': table_corners[0],
            'tr': table_corners[1],
            'br': table_corners[2],
            'bl': table_corners[3]
        }
        self.packer = packer
        self.packing_side = packing_side
        self.frame_size = frame_size

        self.rect_table_corners = self.calculate_rect_table_area()

        self.rect_work_place_corners = self.define_work_place_corners()
        self.worker_hands = Hands(self.rect_work_place_corners['tl'])
        self.width = self.rect_table_corners['br'][
            0] - self.rect_table_corners['tl'][0]
        self.height = self.rect_table_corners['br'][
            1] - self.rect_table_corners['tl'][1]

    def set_cur_pack_task(self, cur_pack_task):
        self.cur_pack_task = cur_pack_task

    def set_next_pack_task_time(self, next_pack_task_time):
        self.next_pack_task_time = next_pack_task_time

    def reset_pack_task(self):
        self.part_tracker = ObjectTracker()
        self.closed_box_tracker = ObjectTracker()
        self.opened_box_tracker = ObjectTracker(distance_threshold=150)
        self.pack_task_completed = False
        self.all_parts_are_in_box = False
        self.part_detections = []
        self.all_visible_parts = []
        self.show_after_completion = True
        self.final_num_frames = WorkPlace.FINAL_FRAMES_NUM
        self.box_detection = None

    def define_work_place_corners(self):
        rect_table_corners_copy = copy.deepcopy(self.rect_table_corners)
        rect_table_corners_copy = {
            key: list(value)
            for key, value in rect_table_corners_copy.items()
        }
        rect_work_place_corners = calculate_work_place_size[self.packing_side](
            rect_table_corners_copy)

        rect_work_place_corners['tl'][0] = 0 if rect_work_place_corners['tl'][
            0] < 0 else rect_work_place_corners['tl'][0]
        rect_work_place_corners['tl'][1] = 0 if rect_work_place_corners['tl'][
            1] < 0 else rect_work_place_corners['tl'][1]
        rect_work_place_corners['br'][0] = self.frame_size[0] if rect_work_place_corners['br'][0] > self.frame_size[
            0] else \
            rect_work_place_corners['br'][0]
        rect_work_place_corners['br'][1] = self.frame_size[1] if rect_work_place_corners['br'][1] > self.frame_size[
            1] else \
            rect_work_place_corners['br'][1]
        return rect_work_place_corners

    def detect_parts(self, frame, parts_detections: list):
        if not parts_detections or self.all_parts_are_in_box:
            return

        frame = self.get_work_place_view_from_frame(frame)

        parts_detections = [
            detection for detection in parts_detections
            if self.is_rect_in_work_place(detection[2])
        ]
        best_detections = self.part_detector.detect(self.cur_pack_task,
                                                    parts_detections)
        table_best_detections = []
        for best_detection in best_detections:
            best_detection.object_shape.set_box_rect(
                self.transform_coords_from_whole_frame_to_work_place_axis(
                    best_detection.object_shape.box_rect))
            table_best_detections.append(best_detection)

        self.part_detections = self.part_tracker.track(frame,
                                                       table_best_detections)
        self.update_undetected_pack_items()
        self.update_detected_pack_items()

    def update_detected_pack_items(self):
        in_box_part_detections = [
            (i, part_detection)
            for i, part_detection in enumerate(self.all_visible_parts)
            if part_detection.is_in_box()
        ]

        if len(in_box_part_detections) == len(self.cur_pack_task):
            self.all_parts_are_in_box = True
            return

        tracked_part_detections = [
            (i, part_detection)
            for i, part_detection in enumerate(self.all_visible_parts)
            if part_detection.is_tracked()
        ]

        moved_part_detections = [
            (i, part_detection)
            for i, part_detection in enumerate(self.all_visible_parts)
            if part_detection.is_moved()
        ]
        if self.box_detection:
            box_rect = self.box_detection.object_shape.tl_box_rect
            for j, (i, tracked_part_detection
                    ) in enumerate(tracked_part_detections):
                part_box_rect = tracked_part_detection.object_shape.tl_box_rect
                if are_rectangles_intersect(box_rect, part_box_rect):
                    percent_intersection = int(
                        rect_square(
                            rectangles_intersection(box_rect, part_box_rect)) /
                        rect_square(part_box_rect) * 100)
                    # 30 is an intersection of the part and the box in percent to consider part inside of the box
                    if percent_intersection > 40:
                        self.all_visible_parts[i].set_status_as_in_box()
                        self.part_tracker.del_tracker(
                            self.all_visible_parts[i].part)
                        del tracked_part_detections[j]

            # make sure that worker moved only one item per time into the box
            assert len(moved_part_detections) < 2
            for i, moved_part_detection in moved_part_detections:
                wrist_point, _ = self.get_active_wrist_point()
                if wrist_point and is_point_in_rect(wrist_point, box_rect):
                    self.all_visible_parts[i].set_status_as_in_box()
                    self.active_wrist = None

        for i, tracked_part_detection in tracked_part_detections:
            shift_history = self.part_tracker.get_shift_histories_by_part(
                tracked_part_detection.part)
            # part shift in through n-frames in pixels to consider the part as moved by a hand
            if sum(shift_history) > 20:
                nearest_wrist, dist = self.worker_hands.get_nearest_wrist_to_rect(
                    tracked_part_detection.object_shape.box_rect)
                #  100 is empirical value
                if dist < 100:
                    self.all_visible_parts[i].set_status_as_moved()
                    self.part_tracker.del_tracker(
                        self.all_visible_parts[i].part)
                    pack_task = [
                        pack_task_item for pack_task_item in self.cur_pack_task
                        if pack_task_item.part is tracked_part_detection.part
                    ][0]
                    self.active_wrist = nearest_wrist, pack_task

                    self.animator.generate_animation(
                        self.generate_color_by_index(pack_task.index),
                        (255, 255, 255))

    def get_active_wrist_point(self):
        if not self.active_wrist:
            return None, None
        wrist_point = self.worker_hands.points[self.active_wrist[0]]
        pack_task = self.active_wrist[1]

        return (wrist_point, pack_task) if wrist_point else (None, None)

    def update_undetected_pack_items(self):
        not_detected_parts = [
            pack_task_item.part for pack_task_item in self.cur_pack_task
            if not pack_task_item.is_detected()
        ]
        for i, part_detection in enumerate(self.part_detections):
            if part_detection.part in not_detected_parts:
                index = [pack_task.part for pack_task in self.cur_pack_task
                         ].index(part_detection.part)

                # NOT SMART BUT THAT IS WHAT IT IS
                if self.cur_pack_task[index].part_class == 'dt_pack_small':
                    indices = [
                        i for i, pack_task in enumerate(self.cur_pack_task)
                        if pack_task.part_class == 'dt_pack_small'
                    ]
                    position = indices[1] if index == indices[0] else indices[0]
                    self.cur_pack_task[position].set_status_as_detected()
                    self.all_parts_are_in_box = True

                self.cur_pack_task[index].set_status_as_detected()
                self.all_visible_parts.append(part_detection)

    def visualize_part_detections(self, frame):

        for i, part_detection in enumerate(self.part_tracker.get_detections()):
            shape = part_detection.object_shape
            points = [
                shape.box_rect_center, shape.tm_point_rect, shape.rm_point_rect
            ]
            points = [(point[0] + self.rect_work_place_corners['tl'][0],
                       point[1] + self.rect_work_place_corners['tl'][1])
                      for point in points]

            print_pos, index = \
                [(next_pack_task.print_pos, next_pack_task.index) for next_pack_task in self.cur_pack_task if
                 next_pack_task.part is part_detection.part][0]

            color = self.generate_color_by_index(index)

            box_rect = tuple(
                (shape.box_rect[0] + self.rect_work_place_corners['tl'][0],
                 shape.box_rect[1] + self.rect_work_place_corners['tl'][1],
                 *shape.box_rect[2:]))

            cv2.rectangle(frame, box_rect, color, 2)

            def putText(x, y, value: float):
                cv2.putText(frame, f'{int(value)} px', (x, y),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.65, (0, 0, 255), 2)

            putText(*points[0], sum(self.part_tracker.shift_histories[i]))

            print_pos = (print_pos[0] - 3,
                         int(print_pos[1] + WorkPlace.line_height_size / 2 -
                             1))
            cv2.circle(frame, print_pos, 3, color, -1)
            cv2.circle(frame, points[0], 3, color, -1)
            cv2.line(frame, print_pos, points[0], color, 2)

    def apply_tasks_on_frame(self, frame):
        im = Image.fromarray(frame)
        draw = ImageDraw.Draw(im)

        packed_parts = [
            part_detection.part for part_detection in self.all_visible_parts
            if part_detection.is_in_box()
        ]

        def draw_text(x, y, task, color, is_labeling, is_bold=False):
            label = ' X ' if is_labeling else ''
            color = (0, 255, 0) if is_labeling else color
            font = WorkPlace.bold_font if is_bold else WorkPlace.font
            draw.text(
                (x, y), f"{label}{task.part.name} ({task.amount}), "
                f"{task.part.height}x{task.part.width}x{task.part.depth}",
                color,
                font=font)

        def draw_name_info(x, y, name, pack_number, color):
            font = WorkPlace.large_font
            color = (0, 255, 0) if self.pack_task_completed else color
            draw.text((x, y), f"Task #{pack_number}", color, font=font)

        x_value, y_value = None, None
        if self.packing_side == 'Left':
            y_value = 110
            x_value = 5
        elif self.packing_side == 'Right':
            y_value = 110
            x_value = frame.shape[1] - 450

        pack_number = self.cur_pack_task[0].part.pack_number
        draw_name_info(x_value, 10,
                       self.packer.split(' ')[0], pack_number, (0, 255, 255))

        for cur_task in self.cur_pack_task:
            bold = False
            # HARDCODE
            label_item = cur_task.part in packed_parts or self.all_parts_are_in_box

            color = self.generate_color_by_index(
                cur_task.index) if cur_task.is_detected() else (0, 0, 0)
            if cur_task.is_detected():
                bold = True
            draw_text(x_value,
                      y_value,
                      cur_task,
                      color,
                      label_item,
                      is_bold=bold)
            cur_task.print_pos = (x_value, y_value)
            y_value += WorkPlace.line_height_size

        frame = np.asarray(im)
        return frame

    def generate_color_by_index(self, index):
        if index is None:
            return None
        tasks_num = len(self.cur_pack_task)
        color_step = int(255 / (tasks_num / 3))
        bgr = 255, 255, 255
        lvl = index // 3
        bgr = [channel - lvl * color_step for channel in bgr]
        bgr[index % 3] -= color_step
        return tuple(bgr)

    def visualize_box_detections(self, frame):
        table_part_of_frame = self.get_work_place_view_from_frame(frame)

        def draw_box(box, color):
            cv2.rectangle(table_part_of_frame, box.object_shape.box_rect,
                          color, 2)
            cv2.putText(
                table_part_of_frame,
                f'{PackBox.reversed_statuses[box.status]} ({box.probability}%)',
                box.object_shape.box_rect_center, cv2.FONT_HERSHEY_COMPLEX,
                0.7, color, 2)

        if self.opened_box_tracker:
            for box in self.opened_box_tracker.detections:
                draw_box(box, (255, 255, 255))

        if self.closed_box_tracker:
            for box in self.closed_box_tracker.detections:
                draw_box(box, (0, 0, 255))

    def visualize_closed_box(self, frame):
        def draw_box(box, color):
            table_part_of_frame = self.get_work_place_view_from_frame(frame)

            cv2.rectangle(table_part_of_frame, box.object_shape.box_rect,
                          color, 2)
            cv2.putText(
                table_part_of_frame,
                f'{PackBox.reversed_statuses[box.status]} ({box.probability}%)',
                box.object_shape.box_rect_center, cv2.FONT_HERSHEY_COMPLEX,
                0.7, color, 2)

        draw_box(self.box_detection, (255, 255, 255))
        self.decrease_final_frames_num()

    def decrease_final_frames_num(self):
        self.final_num_frames -= 1
        if self.final_num_frames <= 0:
            self.show_after_completion = False

    def detect_opened_boxes(self, frame, opened_box_detections):
        pack_box = self.get_pack_box_from_boxes(opened_box_detections,
                                                PackBox.statuses['Opened'],
                                                0.40, None)
        return self.opened_box_tracker.track(frame, pack_box)

    def detect_closed_boxes(self, frame, closed_box_detections):
        pack_box = self.get_pack_box_from_boxes(
            closed_box_detections,
            PackBox.statuses['Closed'],
            0.40,
            self.box_detection.object_shape.box_rect_center,
            distance=200)
        return self.closed_box_tracker.track(frame, pack_box)

    def get_pack_box_from_boxes(self,
                                box_detections,
                                status,
                                probability,
                                reference,
                                distance=math.inf):
        opened_box_detections = [
            detection for detection in box_detections
            if self.is_rect_in_work_place(detection[2])
        ]
        pack_box = []
        if opened_box_detections:
            opened_box_detections = [
                (box_detection[1],
                 self.transform_coords_from_whole_frame_to_work_place_axis(
                     box_detection[2]))
                for box_detection in opened_box_detections
            ]
            opened_box_detections = [(box_dect[0], ObjectShape(box_dect[1]))
                                     for box_dect in opened_box_detections]

            if reference:
                # for bx in opened_box_detections:
                #     print('dist',
                #           dist.cdist([bx[1].box_rect_center], [self.box_detection.object_shape.box_rect_center]))

                opened_box_detections = [
                    (prob, shape) for prob, shape in opened_box_detections
                    if dist.cdist([shape.box_rect_center], [
                        self.box_detection.object_shape.box_rect_center
                    ])[0][0] < distance
                ]
            if opened_box_detections:
                best_box_detection = max(opened_box_detections,
                                         key=lambda detection: detection[0])
                if best_box_detection[0] > probability:
                    pack_box = [
                        PackBox(best_box_detection[1], status,
                                int(best_box_detection[0] * 100))
                    ]
        return pack_box

    def is_rect_in_work_place(self, rect):
        wp = self.rect_work_place_corners

        xs = rect[0] - rect[2] / 2, rect[0] + rect[2] / 2
        ys = rect[1] - rect[3] / 2, rect[1] + rect[3] / 2
        return all([wp['tl'][0] <= x <= wp['br'][0] for x in xs]) and all(
            [wp['tl'][1] <= y <= wp['br'][1] for y in ys])

    def is_point_in_work_place(self, point):
        tb = self.rect_work_place_corners
        return is_num_in_range(point[0],
                               (tb['tl'][0], tb['br'][0])) and is_num_in_range(
                                   point[1], (tb['tl'][1], tb['br'][1]))

    def transform_coords_from_whole_frame_to_work_place_axis(self, rect):
        if not rect:
            return None
        wp = self.rect_work_place_corners
        new_rect = (rect[0] - wp['tl'][0], rect[1] - wp['tl'][1], *rect[2:])
        return new_rect

    def transform_coords_from_work_place_axis_to_whole_frame(self, rect):
        if not rect:
            return None
        wp = self.rect_work_place_corners
        new_rect = (rect[0] + wp['tl'][0], rect[1] + wp['tl'][1], *rect[2:])
        return new_rect

    def detect_boxes(self, frame, boxes_detections):
        frame = self.get_work_place_view_from_frame(frame)

        if not self.box_detection:
            boxes_detections = tuple(detection
                                     for detection in boxes_detections
                                     if detection[0] == 'pb_open')
            result = self.detect_opened_boxes(frame, boxes_detections)
            self.box_detection = result[0] if result else None

        elif self.box_detection.status == PackBox.statuses[
                'Opened'] and not self.all_parts_are_in_box:
            result = self.opened_box_tracker.update(frame)
            self.box_detection = result[0] if result else None

        elif self.box_detection.status == PackBox.statuses[
                'Opened'] and self.all_parts_are_in_box:
            self.opened_box_tracker = None
            boxes_detections = tuple(detection
                                     for detection in boxes_detections
                                     if detection[0] == 'pb_closed')
            result = self.detect_closed_boxes(frame, boxes_detections)
            if result:
                self.box_detection = result[0]
                self.pack_task_completed = True

    def visualize_hand_detections(self, frame):
        table_area_frame = self.get_work_place_view_from_frame(frame)
        self.worker_hands.draw_skeleton(table_area_frame)
        wrist_point, pack_task = self.get_active_wrist_point()

        if self.animator.is_animation_not_finished():
            wrist_point = self.transform_coords_from_work_place_axis_to_whole_frame(
                wrist_point)
            label_point = pack_task.print_pos if pack_task else None
            self.animator.play_animation(frame, wrist_point, label_point)
        if wrist_point:
            color = self.generate_color_by_index(pack_task.index)
            cv2.circle(table_area_frame, wrist_point, 10, color, -1)

    def detect_hands(self, hands_detections):
        for hands_detection in hands_detections:
            for point in hands_detection.values():
                if not point:
                    continue
                if self.is_point_in_work_place(point):
                    self.worker_hands.set_new_points(hands_detection)
                break
Beispiel #9
0
def play_game():
    global DISPLAY_SCREEN, DEFAULT_FONT
    #declared display screen and a default font as global variables so they can be accessed in other functions
    #initialize pygame
    pygame.init()
    #loads music file
    file = 'music.wav'
    pygame.mixer.music.load(file)
    #plays music file
    pygame.mixer.music.play()

    FOOTBALL_SPEED = 0.1
    POINTS_PER_CATCH = 2

    ROUND_SIZE = 1
    ROUND_LEVEL_UP = 8
    SPEED_UP = 1.01
    pygame.init()
    clock = pygame.time.Clock()

    DISPLAY_SCREEN = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT), 0, 32) #creates display screen
    pygame.display.set_caption("PYCATCH 2K17") # set display screen caption

    DEFAULT_FONT = pygame.font.Font('freesansbold.ttf', 12)

    instructSurf = DEFAULT_FONT.render('Move Mouse Left and Right or Hold on to Mouse to Catch as Many Footballs As You Can! (K)Pause Screen (S)Unpause Screen', 1, BLUE)

    instructRect = instructSurf.get_rect()
    instructRect.topleft = (5, DISPLAY_HEIGHT - 40)
    #instructions will appear on the bottom of the screen while playing the game

    score = Score(DISPLAY_SCREEN, SCORE_HEIGHT)
    #create an instance of Score Class

    footballs = [Footballs(DISPLAY_SCREEN, FOOTBALL_SPEED)]
    #create an instance of Footballs class

    hands = Hands(DISPLAY_SCREEN, SCORE_HEIGHT)
    #create an instance of hand class
    gameOver = False
    gameLoop = False
    game_win = False

    while not gameLoop:

        time_elapsed = clock.tick(FPS)
        DISPLAY_SCREEN.fill(BACKGROUND_COLOR) #Fill in background of Display with a color
        mouse_x_pos, mouse_y_pos = pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1]
        #get mouse position
        DISPLAY_SCREEN.blit(instructSurf, instructRect)
        #blit the instructions onto screen

        hands.x_change = mouse_x_pos
        
        #img hands can be moved across the screen if clicked and held onto
        if hands.grabbed:
            hands.y_change = mouse_y_pos
        else:
            hands.y_change = hands.img_height / 2 + SCORE_HEIGHT

        hands.refresh()
        hands.output()
        #display hands and update
        check_events(hands, mouse_x_pos, mouse_y_pos)
        #calls check events function to check if mouse was clicked or held onto

        
        #if there are no footballs on the screen, speed up footballs and append onto screen
        if len(footballs) == 0:
            for x in range(0, ROUND_SIZE):
                FOOTBALL_SPEED *= SPEED_UP
                footballs.append(Footballs(DISPLAY_SCREEN, FOOTBALL_SPEED))

        #if footballs missed is greater than footballs catched, game over loop runs
        if score.footballs_missed > score.footballs_catched:
            gameOver = True
        #gameover loop, outputs a message and gives user options to play again or quit
        while gameOver == True:
            DISPLAY_SCREEN.fill(BLUE)
            font = pygame.font.Font('freesansbold.ttf', 21)
            screen_text = font.render("GAME OVER! MISSED > CATCHED! (P) PLAY AGAIN"
                                      " (Q) QUIT GAME", 1, ORANGE)
            gameRect = screen_text.get_rect()
            gameRect.topleft = (20, DISPLAY_HEIGHT/2)
            DISPLAY_SCREEN.blit(screen_text, gameRect)
            #checks for events, if user presses p then the game starts again if q, then game exits.
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        gameOver = False
                        gameLoop = True
                    if event.key == pygame.K_p:
                        play_game()
            pygame.display.update()
        #if footballs catched is greater than 225 then game_win loop runs
        if score.footballs_catched > 225:
            game_win = True
        #displays a message on screen indicating that the winner has won.
        #Give user options to play again or quit
        while game_win == True:
            DISPLAY_SCREEN.fill(BLUE)
            font = pygame.font.Font('freesansbold.ttf', 19)
            screen_text = font.render("YOU WIN! Caught more than 225 FOOTBALLS! (P) PLAY AGAIN"
                                      " (Q) QUIT GAME", 1, ORANGE)
            gameRect = screen_text.get_rect()
            gameRect.topleft = (10, DISPLAY_HEIGHT/2)
            DISPLAY_SCREEN.blit(screen_text, gameRect)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    sys.exit()
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_q:
                        gameOver = False
                        gameLoop = True
                    if event.key == pygame.K_p:
                        play_game()
            pygame.display.update()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            pressed = pygame.key.get_pressed()
            if pressed[pygame.K_p]:
                play_game()
            if pressed[pygame.K_q]:
                sys.exit()
        
        #updates score and removes it from the screen if it collided with hands. 
        # This indicates that the basketball was catched
        # Basketball speed increases 
        for ball in footballs:
            ball.update(time_elapsed)
            #score increases if objects collide
            if ball.rect.colliderect(hands.rect):
                score.footballs_catched += 1
                score.score += POINTS_PER_CATCH
                footballs.remove(ball)
                FOOTBALL_SPEED *= 1.01
                
                if score.footballs_catched % ROUND_LEVEL_UP == 0:
                    ROUND_SIZE += 1
                continue
            #if footballs goes off screen and has not collided with hands then the basketball was missed
            #missed score increments by 1
            if ball.y_change < -ball.img_height / 2 + SCORE_HEIGHT:
                score.footballs_missed += 1
                footballs.remove(ball)


            ball.output()
            #blits the football

        score.output()
        #displays the scoreboard
        
        pygame.display.update()