Ejemplo n.º 1
0
class cardTableWidget(QWidget):
    server_receivedSig = pyqtSignal(str)
    """ main widget for handling the card table """
    def __init__(self, parent=None):
        super(QWidget, self).__init__(parent)
        # init is done in start_server.py

    def initUI(self, path_to_options):
        """ initialize the view-scene graphic environment """
        self.scene = QGraphicsScene()
        #self.scene.setSceneRect(0, 0, 640, 480)
        self.view = QGraphicsViewExtend(self.scene)
        self.view.setSceneRect(QRectF(self.view.viewport().rect()))
        self.view.setSceneRect(QRectF(0, 0, 850, 900))
        self.view.setRenderHint(QPainter.Antialiasing)
        layout = QGridLayout()
        layout.addWidget(self.view)
        self.setLayout(layout)
        self.setBackgroundColor(QColor('green'))

        # special properties
        self.svgCardsPath = "../cards"
        self.cardsGraphItems = []  #holds all the cards items
        self.defInsertionPos = QPointF(0, 0)
        self.defAngle = 0
        self.defScale = 0.5
        self.deckBackSVG = 'back_1'
        self.numOfPlayers = 4
        self.playersHandsPos = [(75, 50, 0), (210, 50, 180), (680, 50, 0),
                                (210, 385, 0)]  #(x,y,angle)
        self.defHandSpacing = 24
        self.midCards = []
        self.options_file_path = path_to_options

        # Card fields
        pen = QPen()
        brush = QBrush()
        self.scene.addRect(QRectF(200, 230, 100, 80), pen, brush)
        self.scene.addRect(QRectF(200 + 120, 230, 100, 80), pen, brush)
        self.scene.addRect(QRectF(200 + 120 * 2, 230, 100, 80), pen, brush)
        self.scene.addRect(QRectF(200 + 120 * 3, 230, 100, 80), pen, brush)

        # Player Names
        self.player1_label = self.addPlayerLabel(425, 350, "Player 1")
        self.player2_label = self.addPlayerLabel(0, 240, "Player 2")
        self.player3_label = self.addPlayerLabel(425, 20, "Player 3")
        self.player4_label = self.addPlayerLabel(782, 240, "Player 4")

        self.card1_label = self.addPlayerLabel(200, 210, "")
        self.card2_label = self.addPlayerLabel(200 + 120, 210, "")
        self.card3_label = self.addPlayerLabel(200 + 120 * 2, 210, "")
        self.card4_label = self.addPlayerLabel(200 + 120 * 3, 210, "")

        self.card_label_l = [
            self.card1_label, self.card2_label, self.card3_label,
            self.card4_label
        ]
        self.card_label_pla = [
            self.player1_label, self.player2_label, self.player3_label,
            self.player4_label
        ]

        self.play_1_state = self.addPlayerLabel(200, 250, "")
        self.play_2_state = self.addPlayerLabel(200 + 120, 250, "")
        self.play_3_state = self.addPlayerLabel(200 + 120 * 2, 250, "")
        self.play_4_state = self.addPlayerLabel(200 + 120 * 3, 250, "")
        self.game_indicator = self.addPlayerLabel(650, 5, "Game: ")
        self.mode_label = self.addPlayerLabel(150, 5, "Mode: ")

        playbtn = QPushButton('Start', self)
        playbtn.resize(50, 32)
        playbtn.move(10, 10)
        playbtn.clicked.connect(self.start_clicked)

        options = QPushButton('Options', self)
        options.resize(80, 32)
        options.move(65, 10)
        options.clicked.connect(self.options_clicked)

        nextRound = QPushButton('nextRound', self)
        nextRound.resize(80, 32)
        nextRound.move(150, 10)
        nextRound.setVisible(False)
        nextRound.clicked.connect(self.nextRound_clicked)

        self.scene.addWidget(playbtn)
        self.scene.addWidget(nextRound)
        self.scene.addWidget(options)

        self.my_game = None

        # Testing tree:
        self.my_tree = None

        # Storing game_play
        self.game_play = {}

        self.corrString = ""
        # emit signal:
        self.server_receivedSig.connect(self.parseClient)

        ### Client stuff:
        self.clientTimer = QTimer(self)
        self.tcpSocket = None
        self.games_played = 0
        self.reset_client()

        self.server_thread = None

    def reset_client(self):
        # used  also in "Restart"
        self.removeAll()
        self.deckBackSVG = 'back_1'  # in shifting phase soll man karten sehen!
        self.clientCards = None
        self.ClientName = ""
        self.dealAgain = False
        self.GameOver = False
        self.gotCards = 0
        self.rounds_played = 1
        self.nuSend = 0
        self.nuReceived = 0
        self.wantPlay = ""
        self.games_played += 1

    def options_clicked(self):
        '''
        Read in json, modify, write it read it in as dict again!
        '''
        with open(self.options_file_path) as json_file:
            test = json.load(json_file)
            txt = prettyjson(test)
        text = easygui.textbox("Contents of file:\t" + self.options_file_path,
                               "Adjust your options", txt)
        if text is not None:  # Cancel pressed (None case)
            dict = (json.loads(text))
            with open(self.options_file_path, 'w') as outfile:
                json.dump(dict, outfile)

    def nextRound_clicked(self):
        '''
        Reset the game with the same options as before!
        '''
        print("This option is not available!")

#########################CLIENT #################################
#########################CLIENT #################################
#########################CLIENT #################################

    def convertCardsArray(self, stringArray):
        cards = []
        for ele in ast.literal_eval(stringArray):
            cards.append(self.convertCardString2Card(ele))
        return cards

    def convertCardString2Card(self, cardmsg):
        tmp = cardmsg.split("of")
        value = int(tmp[0].replace("'", ""))
        color = str(tmp[1].replace("of", "").replace(" ", "").replace("'", ""))
        return card(color, value)

    def send_msgClient(self, msg):
        self.tcpSocket.waitForBytesWritten(
            100)  # waitForBytesWritten  waitForConnected
        self.tcpSocket.write(bytes(str(msg), encoding='ascii'))

    def displayErrorClient(self, socketError):
        self.changePlayerName(
            self.mode_label,
            "Wait for server your ip:  " + str(self.options["open_ip"]))
        if socketError == QAbstractSocket.RemoteHostClosedError:
            pass
        else:
            print("Server does not seem to be open or wrong open_ip!")
            if not self.clientTimer.isActive():
                print("The following error occurred: %s." %
                      self.tcpSocket.errorString())
                self.clientTimer.timeout.connect(self.clientReconnectTimer)
                self.clientTimer.start(2000)

    def applyOneState(self, state):
        # only for single message
        res = []
        for i in state:
            res.append(ast.literal_eval(i))

        try:
            player_idx, my_card, shifting, nu_shift_cards, on_table_cards, endround, gameOver = int(
                res[0]), self.convertCardString2Card(res[1]), str(res[2]), int(
                    res[3]), int(res[4]), res[6], res[7]
        except:
            print("Could not parse ERRROR")
            return

        print("apply Board state:", res, self.gotCards)

        #Do not play if card is already deleted or in the mid
        item = self.findGraphicsCardItem_(my_card)
        if item is None or item.isPlayed:
            return

        if "False" in shifting:
            shifting = False
        else:
            shifting = True

        if not shifting:
            on_table_cards = len(self.midCards)

        if "True" in str(gameOver):
            self.GameOver = True

        # If cards are dealt again do not apply shifted states again (they still might be contained in board state)
        if shifting and self.gotCards >= 2:
            return
        self.playCardClient(item, player_idx, on_table_cards, player_idx,
                            shifting, nu_shift_cards)

    def applyBoardState(self, msg):
        if len(msg) == 0:
            return
        for i in msg:
            self.applyOneState(i)

    @pyqtSlot(str)
    def parseClient(self, inMsg):
        self.nuReceived += 1
        #self.clientTimer.stop()
        print("\nReceived::", inMsg)

        name, command, msg, tmp, outMsg = "", "", "", "", ""
        try:
            tmp = inMsg.split(";")
        except Exception as e:
            print(e)
            outMsg = name + ";" + "Error;" + "Server could not parse Message split fails"

        if len(tmp) == 3:
            name, command, msg = tmp[0], tmp[1], tmp[2]
        else:
            print("Not enough ;")
            outMsg = name + ";" + "Error;" + "Server could not parse Message not enough args found" + str(
                len(tmp)) + " should be 3"

        #### TODO
        #### Achtung wenn gleiche Nachricht 2 mal kommt soll nichts gemacht werden
        #### Warte bis timer fertig bevor neuen starten!!!

        if command == "InitClientSuccess" or command == "WaitUntilConnected":
            self.changePlayerName(self.mode_label,
                                  "Mode: Shift, WAIT FOR OTHERS")
            self.send2Server("GetCards",
                             "Server give me my cards and the game state",
                             once=False)
        elif command == "GetCardsSuccess":
            self.gotCards += 1
            # Wende nur zwei mal an!!!
            if self.gotCards <= 2:
                try:
                    ttmp = msg.split("--")
                    names, typee, cards, deck = ttmp[0], ttmp[1], ttmp[
                        2:6], ttmp[6]
                except:
                    print("Could not parse ERRROR")
                    return

                self.options["names"] = ast.literal_eval(names)
                self.options["type"] = ast.literal_eval(typee)
                self.setNames()

                for i, c in enumerate(cards):
                    if self.options["names"][i] == self.clientName:
                        self.clientCards = self.convertCardsArray(c)
                        self.deal_cards(self.convertCardsArray(c),
                                        i,
                                        fdown=False)
                    else:
                        self.deal_cards(self.convertCardsArray(c),
                                        i,
                                        fdown=True)
                self.deckBackSVG = str(ttmp[6])

            self.send2Server("WantPlay", str(self.wantPlay), once=False)
        elif command == "WrongCard":
            self.applyBoardState(ast.literal_eval(msg))
            if self.dealAgain:
                self.send2Server("GetCards", str(self.wantPlay), once=False)
                self.dealAgain = False
            elif self.GameOver:
                self.send2Server("GameOver", "game is over", once=False)
                self.GameOver = False
            else:
                ########### random card for testing:
                # item = None
                # if len(self.clientCards)>0:
                #     while item is None:
                #         number = random.randrange(len(self.clientCards))
                #         my_card = self.clientCards[number]
                #         item = self.findGraphicsCardItem_(my_card)
                #     self.wantPlay = my_card
                #########
                self.send2Server("WantPlay", str(self.wantPlay), once=False)
        elif command == "PlayedCard":
            self.wantPlay = ""
            try:
                ttmp = msg.split("--")
                player_idx, card, shifting, nu_shift_cards, on_table_cards, endround, gameover = int(
                    ttmp[0]), self.convertCardString2Card(
                        ttmp[1]), ast.literal_eval(ttmp[2]), int(ttmp[3]), int(
                            ttmp[4]), ttmp[6], ttmp[7]
            except:
                print("Could not parse ERRROR")
                return

            #Do not play if card is already deleted or in the mid
            item = self.findGraphicsCardItem_(card)
            if item is None or item.isPlayed:
                print("ERROR CARD NOT FOUND!!!! \n\n")
                self.send2Server("WantPlay", str(self.wantPlay), once=False)
                return

            if not shifting:
                on_table_cards = len(self.midCards)

            try:
                self.playCardClient(item, player_idx, on_table_cards,
                                    player_idx, shifting, nu_shift_cards)
            except:
                self.send2Server("WantPlay", str(self.wantPlay), once=False)
                return

            if self.dealAgain:
                self.send2Server("GetCards", str(self.wantPlay), once=False)
                self.dealAgain = False
            elif "True" in gameover:
                self.send2Server("GameOver", "game is over", once=False)
            else:
                self.send2Server("WantPlay", str(self.wantPlay), once=False)
        elif command == "GameOver":
            # do this only once:
            if not self.dealAgain:
                self.removeAll()
                self.dealAgain = True
                try:
                    ttmp = msg.split("--")
                    offhandCards, rewards, total_rewards = ttmp[0], ttmp[
                        1], ttmp[2]
                except Exception as e:
                    print("Could not parse ERRROR", e)
                    return

                offhandCards = ast.literal_eval(offhandCards)
                rewards = ast.literal_eval(rewards)
                total_rewards = ast.literal_eval(total_rewards)

                for i in range(len(offhandCards)):
                    self.showResultClient(
                        i, str(rewards[i]), str(total_rewards[i]),
                        self.convertCardsArray(str(offhandCards[i])))

                print("CLIENT GAME OVERRRRR")
            self.send2Server("Restart", "Server Please Restart me", once=False)
        elif command == "Restart":
            print("Inside client restart and reset now")
            self.reset_client()
            #about to restart.....
            time.sleep(self.options["sleepTime"] *
                       4)  # wait some time before starting new!
            self.send2Server("GetCards",
                             "Server give me my cards for the new game",
                             once=False)

    def receivedMsgClient(self):
        inMsg = str(self.tcpSocket.readAll(), encoding='utf8')
        if ";Ende" in inMsg:
            a = (inMsg.split(";Ende"))
            self.corrString += a[0]

            self.server_receivedSig.emit(self.corrString)
            self.corrString = ""
        else:
            self.corrString += inMsg

    def sendServer(self, msg):
        # wait for answer here: https://stackoverflow.com/questions/23265609/persistent-connection-in-twisted
        # see also this https://stackoverflow.com/questions/23265609/persistent-connection-in-twisted (send to multiple....)
        print(">>>Client sends:", msg)
        msg = msg.encode("utf8")
        self.tcpSocket.write(msg)
        self.nuSend += 1
        self.tcpSocket.waitForBytesWritten()

    def send2Server(self, cmd, msg, once=True, delimiter=";"):
        msg = self.clientName + delimiter + cmd + delimiter + msg + delimiter + "Ende"
        if once:
            self.sendServer(msg)
        else:
            # Send after a while to minimize the traffic
            QTimer.singleShot(100, lambda: self.sendServer(msg))

    def openClient(self):
        self.tcpSocket = QTcpSocket(self)
        print("I client connect now with:", self.options["open_ip"])
        self.changePlayerName(
            self.mode_label,
            "Client Connect with: " + str(self.options["open_ip"]))
        self.tcpSocket.connectToHost(self.options["open_ip"], 8000,
                                     QIODevice.ReadWrite)
        self.tcpSocket.readyRead.connect(self.receivedMsgClient)
        self.tcpSocket.error.connect(self.displayErrorClient)

        # send start message:
        connected = self.tcpSocket.waitForConnected(1000)
        if connected:
            self.clientTimer.stop()
            self.send2Server("InitClient",
                             "Server please init me with my name")
        else:
            print(
                "Not connected, Server not open?, open_ip wrong? Try to reconnect in 2sec"
            )

    def is_valid_ipv4(self, ip):
        """Validates IPv4 addresses.
        """
        pattern = re.compile(
            r"""
            ^
            (?:
              # Dotted variants:
              (?:
                # Decimal 1-255 (no leading 0's)
                [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
              |
                0x0*[0-9a-f]{1,2}  # Hexadecimal 0x0 - 0xFF (possible leading 0's)
              |
                0+[1-3]?[0-7]{0,2} # Octal 0 - 0377 (possible leading 0's)
              )
              (?:                  # Repeat 0-3 times, separated by a dot
                \.
                (?:
                  [3-9]\d?|2(?:5[0-5]|[0-4]?\d)?|1\d{0,2}
                |
                  0x0*[0-9a-f]{1,2}
                |
                  0+[1-3]?[0-7]{0,2}
                )
              ){0,3}
            |
              0x0*[0-9a-f]{1,8}    # Hexadecimal notation, 0x0 - 0xffffffff
            |
              0+[0-3]?[0-7]{0,10}  # Octal notation, 0 - 037777777777
            |
              # Decimal notation, 1-4294967295:
              429496729[0-5]|42949672[0-8]\d|4294967[01]\d\d|429496[0-6]\d{3}|
              42949[0-5]\d{4}|4294[0-8]\d{5}|429[0-3]\d{6}|42[0-8]\d{7}|
              4[01]\d{8}|[1-3]\d{0,9}|[4-9]\d{0,8}
            )
            $
        """, re.VERBOSE | re.IGNORECASE)
        return pattern.match(ip) is not None

#########################CLIENT #################################
#########################CLIENT #################################
#########################CLIENT #################################

#########################SERVER #################################
#########################SERVER #################################
#########################SERVER #################################

    def start_server(self):
        import server

    def getIP(self):
        hostname = socket.gethostname()
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip_address = s.getsockname()[0]
        return ip_address, hostname

    def getNuClients(self, list):
        u = 0
        for i in list:
            if "Client" in i:
                u += 1
        return u

    def findFirstClient(self, list):
        for j, i in enumerate(list):
            if "Client" in i:
                return j
        return 0


#########################SERVER #################################
#########################SERVER #################################
#########################SERVER #################################

    def start_clicked(self):
        #1. Load Options
        with open(self.options_file_path) as json_file:
            self.options = json.load(json_file)

        #2. Create Game:
        print("Online_type:", self.options["online_type"])
        if "Client" in self.options["online_type"]:
            self.changePlayerName(self.mode_label, "Mode: Client")
            valid_ip = self.is_valid_ipv4(self.options["open_ip"])
            if len(self.options["names"]) > 1 or len(
                    self.options["type"]) > 1 or (not valid_ip) or (
                        "Client" not in self.options["type"]):
                print(
                    "Error use only one unique name in options.  names: ['YourName']"
                )
                print(
                    "Error use only one type in options.         type: ['Client']"
                )
                print(
                    "Error use only IPV4 as open_ip in options.  open_ip: 172.20.80.10"
                )
                return
            self.clientName = self.options["names"][0]
            self.openClient()
        elif "Server" in self.options["online_type"]:
            self.changePlayerName(self.mode_label, "Mode: Server")
            #1. Open Server in seperate Thread
            page = str(
                urllib.request.urlopen("http://checkip.dyndns.org/").read())
            print(">>>THIS IS SERVER OPEN IP ADDRESS:",
                  re.search(r'.*?<body>(.*).*?</body>', page).group(1))
            print(">>>LOCAL IP OF THIS PC IN LAN    :", self.getIP())
            self.server_thread = threading.Thread(target=self.start_server, )
            self.server_thread.start()

            #2. Open Client
            self.options["online_type"] = "Client"
            # give it the name of the first found Client
            self.clientName = self.options["names"][self.findFirstClient(
                self.options["type"])]
            self.openClient()
        elif "Local" in self.options["online_type"]:
            clients = self.getNuClients(self.options["type"])
            if clients != 1:
                self.changePlayerName(
                    self.mode_label,
                    "Error use only 1 client \"type\": [\"Client\", \"RL0\", \"RL0\", \"RL1\"],\" "
                )
                time.sleep(1)
                self.changePlayerName(self.mode_label,
                                      "Please close app and restart it!")
            self.changePlayerName(self.mode_label,
                                  "Mode: LocalHost - Play against other ai's")
            self.view.viewport().repaint()
            time.sleep(1)
            ip, host = self.getIP()
            self.changePlayerName(self.mode_label,
                                  str(host) + " " + " IP:" + str(ip))
            #1. Open Server in seperate Thread
            self.options["open_ip"] = ip
            self.server_thread = threading.Thread(target=self.start_server, )
            self.server_thread.start()

            # #2. Open Client
            self.options["online_type"] = "Client"
            # give it the name of the first found Client
            self.clientName = self.options["names"][self.findFirstClient(
                self.options["type"])]
            self.openClient()
        else:
            self.changePlayerName(
                self.mode_label,
                "Error: choose Local, Server or Client as online type")

    def clientReconnectTimer(self):
        self.openClient()

    def getHighlight(self, playeridx):
        try:
            if playeridx == self.my_game.active_player:
                return 1
            else:
                return 0
        except:
            return 0

    def setNames(self):
        self.changePlayerName(self.player1_label,
                              self.options["names"][0] + " (" +
                              self.options["type"][0] + ")",
                              highlight=self.getHighlight(0))
        self.changePlayerName(self.player2_label,
                              self.options["names"][1] + " (" +
                              self.options["type"][1] + ")",
                              highlight=self.getHighlight(1))
        self.changePlayerName(self.player3_label,
                              self.options["names"][2] + " (" +
                              self.options["type"][2] + ")",
                              highlight=self.getHighlight(2))
        self.changePlayerName(self.player4_label,
                              self.options["names"][3] + " (" +
                              self.options["type"][3] + ")",
                              highlight=self.getHighlight(3))

    def showResultClient(self, i, reward, total_reward, offhandCards):
        labels1 = [
            self.card1_label, self.card2_label, self.card3_label,
            self.card4_label
        ]
        labels2 = [
            self.play_1_state, self.play_2_state, self.play_3_state,
            self.play_4_state
        ]
        label1 = labels1[i]
        label2 = labels2[i]
        self.changePlayerName(label1,
                              self.options["names"][i] + " (" +
                              self.options["type"][i] + ")",
                              highlight=0)
        self.changePlayerName(label2,
                              reward + " [" + total_reward + "]",
                              highlight=0)
        self.deal_cards(offhandCards, i)
        self.view.viewport().repaint()

    def getNextPlayer(self, currPlayer):
        if currPlayer < len(self.options["names"]) - 1:
            return currPlayer + 1
        else:
            return 0

    def getPreviousPlay(self, input_number, nuPlayers=4):
        if input_number == 0:
            prev_player = nuPlayers - 1
        else:
            prev_player = input_number - 1
        return prev_player

    def getInColorOfCards(self, cards):
        # returns the leading color of the on_table_cards
        # if only joker are played None is returned
        for i, card in enumerate(cards):
            if card is not None:
                if card.value < 15:
                    return card.color
        return None

    def getWinnerForCards(self, cards, active_player, nu_players=4):
        # Not this function is used at the client side!
        highest_value = 0
        winning_card = cards[0]
        incolor = self.getInColorOfCards(cards)
        on_table_win_idx = 0
        if incolor is not None:
            for i, card in enumerate(cards):
                # Note 15 is a Jocker
                if card is not None and (card.value > highest_value
                                         and card.color == incolor
                                         and card.value < 15):
                    highest_value = card.value
                    winning_card = card
                    on_table_win_idx = i

        player_win_idx = active_player
        for i in range(nu_players - on_table_win_idx - 1):
            player_win_idx = self.getPreviousPlay(player_win_idx,
                                                  nuPlayers=nu_players)
        return winning_card, on_table_win_idx, player_win_idx

    def playCardClient(self, graphic_card_item, current_player, label_idx,
                       player_name, shifting, shifted_cards):
        print(graphic_card_item, current_player, label_idx, player_name,
              shifting, shifted_cards)
        self.setNames()
        if shifting:
            card_label = self.card_label_l[graphic_card_item.player]
            self.changePlayerName(
                card_label,
                self.options["names"][graphic_card_item.player],
                highlight=0)
            self.view.viewport().repaint()
            shift_round = int(shifted_cards / 4)
            graphic_card_item.setPos(
                card_label.pos().x(),
                card_label.pos().y() + 20 + shift_round * 50)
        else:
            card_label = self.card_label_l[label_idx]
            self.changePlayerName(
                card_label,
                self.options["names"][graphic_card_item.player],
                highlight=0)
            self.view.viewport().repaint()
            graphic_card_item = self.changeCard(graphic_card_item,
                                                faceDown=False)
            graphic_card_item.setPos(card_label.pos().x(),
                                     card_label.pos().y() + 20)
        self.midCards.append(graphic_card_item)
        self.view.viewport().repaint()
        graphic_card_item.isPlayed = True

        if len(self.midCards) == 8:
            # remove all Client Cards (are dealt again!)
            print("Remove all cards now")
            self.removeAll()
            self.removeMidNames()
            self.midCards = []
            self.dealAgain = True
            self.changePlayerName(self.mode_label, "Mode: Play")
        if len(self.midCards) == 4 and shifted_cards > 10:
            print("Remove Mid Cards now")
            ttmp = self.midCards
            time.sleep(self.options["sleepTime"])
            for i in self.midCards:
                self.removeCard(i)
            self.midCards = []
            self.removeMidNames()
            # TODO mark next player (may set trick winner etc.)
            lll = []
            for i in ttmp:
                lll.append(i.card)
            winning_card, on_table_win_idx, player_win_idx = self.getWinnerForCards(
                lll, int(current_player), nu_players=4)
            self.changePlayerName(self.card_label_pla[player_win_idx],
                                  self.options["names"][player_win_idx],
                                  highlight=1)
            self.changePlayerName(
                self.game_indicator, "Game: " + str(self.games_played) +
                " Round: " + str(self.rounds_played))
            self.rounds_played += 1
            self.view.viewport().repaint()
        else:
            # mark next player:
            self.changePlayerName(
                self.card_label_pla[self.getNextPlayer(current_player)],
                self.options["names"][self.getNextPlayer(current_player)],
                highlight=1)
            self.view.viewport().repaint()

        # TODO Game indicator round etc.

        return 1  # card played!

    def getGraphicCard(self, label_idx, player_name, graphic_card_item):
        self.setNames()
        if self.my_game.shifting_phase:
            card_label = self.card_label_l[self.my_game.active_player]
            self.changePlayerName(card_label, player_name, highlight=0)
            self.view.viewport().repaint()
            shift_round = int(self.my_game.shifted_cards /
                              self.my_game.nu_players)
            graphic_card_item.setPos(
                card_label.pos().x(),
                card_label.pos().y() + 20 + shift_round * 50)
        else:
            card_label = self.card_label_l[label_idx]
            self.changePlayerName(card_label, player_name, highlight=0)
            self.view.viewport().repaint()
            graphic_card_item = self.changeCard(graphic_card_item,
                                                faceDown=False)
            graphic_card_item.setPos(card_label.pos().x(),
                                     card_label.pos().y() + 20)
        return graphic_card_item

    def findGraphicsCardItem_(self, my_card):
        for i in self.getCardsList():
            try:
                if (i.card == my_card) or ((i.card.value == my_card.value) and
                                           (i.card.color == my_card.color)):
                    return i
            except:
                pass
        return None

    def findGraphicsCardItem(self, action_idx, player_idx):
        try:
            card_to_play = self.my_game.players[player_idx].hand[action_idx]
        except:
            print("Error no card left anymore!")
            return None
        for i in self.getCardsList():
            if i.card == card_to_play:
                return i

    def removeMidNames(self):
        self.card1_label.setPlainText("")
        self.card2_label.setPlainText("")
        self.card3_label.setPlainText("")
        self.card4_label.setPlainText("")

    def addPlayerLabel(self, x_pos, y_pos, name, highlight=0, font=QFont.Bold):
        item = self.scene.addText(name, QFont('Arial Black', 11, font))
        if highlight:
            item.setDefaultTextColor(Qt.yellow)
        item.setPos(x_pos, y_pos)
        return item

    def changePlayerName(self, text_item, name, highlight=0):
        text_item.setPlainText(name)
        if highlight:
            text_item.setDefaultTextColor(Qt.yellow)
        else:
            text_item.setDefaultTextColor(Qt.black)

    def mousePressEvent(self, event):
        try:
            # check if item is a CardGraphicsItem
            p = event.pos()
            p -= QPoint(
                10, 10)  #correction to mouse click. not sure why this happen
            itemAt = self.view.itemAt(p)
            if isinstance(itemAt, CardGraphicsItem):
                self.cardPressed(itemAt)
        except Exception as e:
            print(e)

    def checkCard(self, cardStr):
        for i in self.clientCards:
            if str(cardStr) in str(i):
                return True
        return False

    def cardPressed(self, card):
        #remove these lines if Problems.... core dumped occurs...
        for i in self.clientCards:
            item = self.findGraphicsCardItem_(i)
            if item is not None and not item.isPlayed:
                item.setScale(self.defScale)

        card.setScale(self.defScale + 0.08)

        if "Client" in self.options["online_type"]:
            # check if it is your card!
            if (self.checkCard(card.card)):
                self.wantPlay = str(card.card)
            else:
                print(self.clientName + " This is not your card!")
                self.changePlayerName(self.mode_label, "Not your card!")
            if self.gotCards <= 1:
                self.changePlayerName(
                    self.mode_label,
                    "Mode: Shift " + str(self.wantPlay).replace("of", ""))
            else:
                self.changePlayerName(
                    self.mode_label,
                    "Mode: Play " + str(self.wantPlay).replace("of", ""))
        else:
            print("other not allowed currently!!!")
            print(eeee)

    def setBackgroundColor(self, color):
        """ add background color """
        brush = QBrush(color)
        self.scene.setBackgroundBrush(brush)
        self.scene.backgroundBrush()

    def cardSvgFile(self, name):
        """ get card svg file from card name
        name = 'c_4','d_Q',...
        for jokers name = 'j_r' or 'j_b'
        for back name = 'back_1', 'back_2', ...
        """
        fn = os.path.join(self.svgCardsPath,
                          name + ".svg")  # TODO change to SVG
        return fn

    def addCard(self, my_card, player=0, faceDown=False):
        """ adds CardGraphicsItem graphics to board.
        also updates the total cards list
        """
        # svg file of the card graphics
        if faceDown:
            svgFile = self.cardSvgFile(self.deckBackSVG)
        else:
            svgFile = self.cardSvgFile(str(my_card.color) + str(my_card.value))

        # create CardGraphicsItem instance
        ind = len(self.getCardsList()) + 1
        tmp = CardGraphicsItem(my_card, ind, svgFile, player, faceDown)
        tmp.setScale(self.defScale)
        tmp.setZValue(ind)  # set ZValue as index (last in is up)
        #        self.cardsGraphItems.append(tmp)
        self.scene.addItem(tmp)
        # sanity check

        #print("num of cards=" + str(len(self.cardsList)))

    def removeAll(self):
        try:
            for i in (self.getCardsList()):
                self.scene.removeItem(i)
        except Exception as e:
            print("Exception:", e)

    def removeCard(self, card):
        """
        removes CardGraphicsItem graphics from board
        """
        self.scene.removeItem(card)

    # TODO - UPDATE THIS FUNCTION
    def changeCard(self, graphicsCardElement, faceDown=False):
        """ replace CardGraphicsItem
        keeps same index and ZValue !
        """
        nameToAdd = str(graphicsCardElement.card.color) + str(
            graphicsCardElement.card.value)
        zValueTmp = graphicsCardElement.zValue()
        position = graphicsCardElement.pos()
        angle = graphicsCardElement.rotation()
        scale = graphicsCardElement.scale()
        player = graphicsCardElement.player
        self.scene.removeItem(graphicsCardElement)

        # svg file of the card graphics
        if faceDown:
            svgFile = self.cardSvgFile(self.deckBackSVG)
        else:
            svgFile = self.cardSvgFile(nameToAdd)

        ind = int(zValueTmp)
        tmp = CardGraphicsItem(
            card(graphicsCardElement.card.color,
                 graphicsCardElement.card.value), ind, svgFile, player,
            faceDown)
        tmp.setScale(self.defScale)
        tmp.setZValue(ind)  # set ZValue as index (last in is up)

        self.scene.addItem(tmp)
        return tmp

    def getCardsList(self):
        """ returns and prints all CardGraphicsItem in scene (disregard other graphics items) """
        itemsOut = []
        #print("Cards List:")
        for item in self.scene.items():
            if isinstance(item, CardGraphicsItem):
                itemsOut.append(item)
                #print("Ind=%3d | Name=%4s | Player=%d | faceDown=%r " % \
                #     (item.ind, item.name, item.player, item.faceDown) )
        #print("Total cards num = " + str(len(itemsOut)))
        return itemsOut

    def deal_cards(self, cards, playerNum, fdown=False):
        n = 1
        c2 = 0
        dx = [0, self.defHandSpacing, 0, self.defHandSpacing]
        dy = [self.defHandSpacing, 0, self.defHandSpacing, 0]
        x, y, ang = self.playersHandsPos[playerNum - 1]
        for card in cards:
            self.addCard(card, player=playerNum,
                         faceDown=fdown)  #add the item to the scene
            self.getCardsList()[0].setPos(
                x + dx[playerNum - 1] * c2,
                y + dy[playerNum - 1] * c2)  #change the position
            n += 1
            c2 += 1