示例#1
0
    def ckan_tiles(self, draw):
        hand = Tiles()
        hand.tiles = self.hand.tiles[:]
        hand.add_tiles(draw)
        search = []
        quad = [tile for tile in hand.tiles if hand.tiles.count(tile) == 4]
        while len(quad) > 0:
            first_quad = [tile for tile in quad if tile == quad[0]]
            search.append(first_quad)
            for tile in first_quad:
                quad.remove(tile)

        pon = [
            meld for meld in self.melds.melds
            if meld.tiles.count(meld.tiles[0]) == 3
        ]
        if pon:
            for meld in pon:
                if meld.tiles[0] in hand.tiles:
                    search.append([
                        meld,
                        [tile for tile in hand.tiles
                         if tile == meld.tiles[0]][0]
                    ])
        if search:
            return search
        return False
示例#2
0
    async def riichi(self, draw, game):

        #this *should* check the hand to make sure its closed
        opened = [meld for meld in self.melds.melds if meld.opened]

        if opened:
            return False

        #determine what tiles are discardable to be in tenpai

        shanten = shanten_calculator(str(self.hand) + str(draw))
        if (shanten == 0 or shanten
                == -1) and self.points >= 1000 and not self.in_riichi:
            riichi_tiles = []
            temp_hand = Tiles()
            temp_hand.tiles = self.hand.tiles[:]
            temp_hand.add_tiles(draw)
            for tile in temp_hand.tiles:
                temp = Tiles()
                temp.tiles = temp_hand.tiles[:]
                temp.remove_tiles(tile)
                if winning_tiles(str(temp)) and tile not in riichi_tiles:
                    riichi_tiles.append(tile)

            if riichi_tiles:
                try:
                    reach = await self.user_input('Would you like to riichi?')
                except asyncio.exceptions.TimeoutError:
                    reach = 'n'
                if reach != 'y' and reach != 'yes':
                    return False
            else:
                return False

            discard = Tile('8', 'z')
            while discard not in self.hand.tiles and discard != draw:
                try:
                    query = "Which tile would you like to riichi on? Type cancel to cancel riichi.\n" + ' '.join(
                        map(str, riichi_tiles))
                    discard = await self.user_input(query)
                    discard = Tile(discard[0], discard[1])
                except asyncio.exceptions.TimeoutError:
                    return False
                except ValueError:
                    discard = Tile('8', 'z')
                except IndexError:
                    discard = Tile('8', 'z')

            #self.discard_tile(choice)
            if game.tenhou and game.wall.remaining > 65:
                self.double_riichi = True
            self.in_riichi = True
            self.ippatsu = True
            self.points -= 1000
            game.riichi += 1
            return discard
        else:
            return False
        '''
示例#3
0
def winning_tiles(tiles):
    if isinstance(tiles, str):
        tiles = tiles.replace(' ', '')
        test_tiles = OneOfEach()
        return [
            tile for tile in test_tiles.tiles
            if shanten_calculator(tiles + str(tile)) == -1
        ]
    elif issubclass(type(tiles), Tiles):
        return winning_tiles(str(tiles))
    elif isinstance(tiles, list):
        temp = Tiles()
        temp.add_tiles(tiles)
        return winning_tiles(str(temp))
示例#4
0
def ukeire(tiles):
    if isinstance(tiles, str):
        tiles = tiles.replace(' ', '')
        test_tiles = OneOfEach()
        shanten = [
            shanten_calculator(str(tiles) + str(tile))
            for tile in test_tiles.tiles
        ]
        return [
            tile for index, tile in enumerate(test_tiles.tiles)
            if shanten[index] == min(shanten)
        ]
    elif issubclass(type(tiles), Tiles):
        return ukeire(str(tiles))
    elif isinstance(tiles, list):
        temp = Tiles()
        temp.add_tiles(tiles)
        return ukeire(str(temp))
示例#5
0
def efficient_discard(tiles, pool=None):
    base_shanten = shanten_calculator(tiles)
    improvements = {}
    if pool is None:
        pool = Wall()
        pool.remove_tiles(tiles)
    for tile in tiles.tiles:
        count = 0
        temp = Tiles()
        temp.tiles = tiles.tiles[:]
        temp.remove_tiles(tile)
        for sample in pool.tiles:
            temp.add_tiles(sample)
            shanten = shanten_calculator(temp)
            if shanten < base_shanten:
                count += 1
            temp.remove_tiles(sample)
        if count > 0:
            improvements[str(tile)] = count
    return improvements
示例#6
0
def efficiency_discard(tiles, pool=None):
    if isinstance(tiles, str):
        tiles = tiles.replace(' ', '')
        temp = Tiles()
        temp.add_tiles(tiles)
        return winning_tiles(temp)
    elif issubclass(type(tiles), Tiles):
        if pool is None:
            discards = efficient_discard(tiles)
        else:
            discards = efficient_discard(tiles, pool)
        most_efficient = [
            tile for tile in discards.keys()
            if discards[tile] == max(discards.values())
        ]
        #return the entire list, and a choice can be made later
        return most_efficient
    elif isinstance(tiles, list):
        temp = Tiles()
        temp.add_tiles(tiles)
        return winning_tiles(str(temp))
示例#7
0
    def chii_tiles(self, discard):
        if discard.suit == 'z':
            return False
        else:
            combinations = []

            tiles = [
                tile for tile in self.hand.tiles if tile.suit == discard.suit
            ]
            prev1 = [
                tile for tile in tiles
                if tile.true_value == discard.true_value - 1
            ]
            next1 = [
                tile for tile in tiles
                if tile.true_value == discard.true_value + 1
            ]

            if prev1 and prev1[0].true_value != 5:
                prev1 = [prev1[0]]

            if prev1:
                prev2 = [
                    tile for tile in tiles
                    if tile.true_value == discard.true_value - 2
                ]
                if prev2:
                    if prev2[0].true_value != 5:
                        prev2 = [prev2[0]]
                    for tile1 in prev1:
                        for tile2 in prev2:
                            chii = Tiles()
                            chii.add_tiles([tile2, tile1, discard])
                            combinations.append(chii)

            if prev1 and next1:
                for tile1 in prev1:
                    for tile2 in next1:
                        chii = Tiles()
                        chii.add_tiles([tile1, discard, tile2])
                        combinations.append(chii)

            if next1 and next1[0].true_value != 5:
                next1 = [next1[0]]

            if next1:
                next2 = [
                    tile for tile in tiles
                    if tile.true_value == discard.true_value + 2
                ]
                if next2:
                    if next2[0].true_value != 5:
                        next2 = [next2[0]]
                    for tile1 in next1:
                        for tile2 in next2:
                            chii = Tiles()
                            chii.add_tiles([discard, tile1, tile2])
                            combinations.append(chii)
            return combinations
示例#8
0
 def visible_tiles(self, game):
     visible = Tiles()
     for player in game.players:
         for meld in player.melds.melds:
             visible.add_tiles(meld)
         visible.add_tiles(player.discards)
     visible.add_tiles(self.hand)
     visible.add_tiles(game.dora)
     return visible
示例#9
0
def player_image(player, hidden, tsumogiri, *args):
#    if not isinstance(player, Player):
#        return False
    
    #if there are melds, do some specific stuff to display the meld accordingly
    #this includes rotating the tile and placing the rotated tile based on who
    #the tile was called from
    
    if player.melds.melds:
        image_list = []
        
        #if the hand is another players', hide the hand by displaying a tileback image
        #distinguish a tsumogiri discard from a tedashi discard by creating a
        #randomly placed break in the undisplayed hand
        #to do this, split up the hand into two chunks, each of which is a series of
        #tileback images
        
        if hidden:
            if tsumogiri:
                parts = ['x' * len(player.hand) + 'z']
            else:
                location = random.randint(1,len(player.hand))
                parts = ['x' * location + 'z']
                parts.append('x' * (len(player.hand) - location) + 'z')
        else:
            parts = [str(player.hand)]
            
        #this creates an array that corresponds with the individual tiles
        #and determines whether or not to display the tile rotated
        #0 indicates upright, while 1 indicates rotated
        #2 is used to indicate an added kan, which is rotated but placed above
        #a previously rotated tile
        #if there is a 2 without a corresponding 1 in this array, it'll probably
        #bug out and have the tiles clip into one another
            
        rotated = []
        
        #the tiles in hand are obviously not rotated
        
        rotated.append([0 for tile in player.hand.tiles])
        
        #and neither are the arguments (which are basically just the discard,
        #but this is flexible enough to allow for other displays)
        
        for arg in args:
            if isinstance(arg, Tiles):
                rotated.append([0 for tile in arg.tiles])
                parts.append(str(arg))
            elif isinstance(arg, Tile):
                rotated.append([0])
                parts.append(str(arg))
            else:
                parts.append(arg)
                tiles = Tiles()
                tiles.add_tiles(arg)
                rotated.append([0 for tile in tiles.tiles])
                
        #figure out who the tile was called from, for all open melds
                
        for meld in player.melds.melds:
            rotation = {'L': [1, 0, 0], 'M': [0, 1, 0], 'R': [0, 0, 1]}
            if meld.who:
                
                rotate = rotation[meld.who][:]
                if meld.shominkan:
                    rotate[rotate.index(1):rotate.index(1)+1] = [1,2]
                elif len(meld) == 4:
                    rotate.insert(2, 0)
                    
                tiles = sorted(meld.tiles, key=lambda tile:tile.true_value)
                remove = [index for index, tile in enumerate(tiles) if tile.suit == meld.called.suit and tile.value == meld.called.value]
                del tiles[remove[0]]                
                string = ''
                zero_counter = 0
                
                for ref in rotate:
                    if ref == 0:
                        string += tiles[zero_counter].value
                        zero_counter += 1
                    elif ref == 1:
                        string += meld.called.value
                    elif ref == 2:
                        string += meld.shominkan_tile.value
                string += meld.called.suit
                    
            #if its a closed kan, then display the tiles without rotation
            #but with flipping
            #the logic exists to display the red 5 in the kan at all times if applicable
            #but realistically this doesn't need to be present
                
            else:
                rotate = [0 for tile in meld.tiles]
                string = str(meld)
                if string[0] == string[3]:
                    string = 'x'.join(string.rsplit(meld.tiles[0].value, 1))
                    string = string.replace(meld.tiles[0].value, 'x', 1)
                elif string[0] == string[1]:
                    string = 'x'.join(string.rsplit(meld.tiles[0].value, 2))
                else:
                    string = string.replace(meld.tiles[-1].value, 'x', 2)
                    
            rotated.append(rotate)
            parts.append(string)
        
        #converts the tile string (11123456789999m) into a list of image links
        #to be pasted together into one long image
        #any breaks (tedashi discarding hands, the discard, and meld blocks)
        #are separated by a short upright transparent rectangle image
        
        image_list = []
        for part in parts:
            results = re.findall(r'([0-9x]+[mpsz])', part)
            if part == parts[0]:
                results = list(
                    reduce(list.__add__,
                           [['{}{}'.format(x, result[-1]) for x in result[:-1]]
                            for result in results]))
            for result in results:
                image_list += [
                    './ui/{}{}.png'.format(x, result[-1]) for x in result[:-1]
                ]
            image_list.append('./ui/0.png')
        
        refs = []
        for block in rotated:
            refs.extend(block)
            refs.append(0)
        del refs[-1]
        
        imagefile = [Image.open(x) for x in image_list]
        
        dim_x = imagefile[0].size[0]
        dim_y = imagefile[0].size[1]
        
        image_length = refs.count(0) * dim_x + refs.count(1) * dim_y
        if refs.count(2): image_height = 2 * dim_x
        else: image_height = dim_y
        
        #create a new image, based on how many images need to be displayed
        #the image generated will always be longer than the space required, due
        #to the transparent separator image being thinner than a normal tile
        #but this issue doesn't seem like a big deal
        
        target = Image.new('RGBA', (image_length, image_height))
        left = 0
        for image, ref in zip(imagefile, refs):
            
            bottom = 0 + image_height - dim_y
            
            if ref:
                image = image.rotate(90, expand = True)
                bottom += dim_y - dim_x
            if ref == 2:
                bottom -= dim_x
                left -= dim_y
                
            target.paste(image, (left, bottom))
            
            left += image.size[0]
            
#        target.save('{}-{}.png'.format(player.disc, player.disc_id), quality=100)
        
        image = io.BytesIO()
        target.save(image, format = 'PNG')
        image.seek(0)
        return image
        
    else:
        tiles = str(player.hand)
        if args:
            args = [str(arg) for arg in args]
            return makeImage(tiles, hidden, tsumogiri, args)
        return makeImage(tiles, hidden, tsumogiri)