Exemplo n.º 1
0
    def solve(cls, game):
        "Solve the board"

        oldhash = hash(str(game.rows))

        # Step 1: individual lines
        columns = game.cols
        yinfo = game.yinfo
        for i in range(game.width):
            debug(Rule(f"Solve column #{i}"))
            game.replacecol(
                i, NonogramLineSolver.solve(columns[i], yinfo[i]))

        rows = game.rows
        xinfo = game.xinfo
        for i in range(game.height):
            debug(Rule(f"Solve row #{i}"))
            game.replacerow(
                i, NonogramLineSolver.solve(rows[i], xinfo[i]))

        if cls.issolved(game):
            debug(game, Rule(title="Solving completed"))
            return True

        newhash = hash(str(game.rows))

        if oldhash != newhash:
            debug(game, Rule(title="Next solving cycle"))
            return cls.solve(game)

        debug(game, Rule(title="Solving failed"))
        return False
Exemplo n.º 2
0
    def solve_singlerangemultireq(cls, values, requirements):
        "Solving method: More than 1 requirement in 1 range"
        debug("[red][Solving singlerange] Start[/]")
        debug({"values": values, "requirements": requirements})

        debug("[red][Solving singlerange] End[/]")
        return values
Exemplo n.º 3
0
    def solve_multirange(cls, values, requirements):
        "Solving method: Multirange"
        ranges = cls.getfreeranges(values)
        debug("[red][Solving multirange] Start[/]")
        debug({"values": values, "ranges": ranges, "requirements": requirements})

        debug("[red][Solving multirange] End[/]")
        return values
Exemplo n.º 4
0
 def solve_fullline(cls, values, requirements):
     "Solving method: Requirements use full space"
     reqwidth = cls.getfullwidth(requirements)
     valwidth = len(values)
     debug("[yellow][Solving fullline] Start[/]")
     debug({"reqwidth": reqwidth, "valwidth": valwidth})
     if reqwidth > valwidth:
         raise UnsolvableLine("Requirements use more space than possible!")
     if valwidth == reqwidth:
         index = 0
         for req in requirements:
             values[index:index+req] = [True]*req
             index += req+1
         debug("[yellow][Solving fullline] Succeeded[/]")
         return values
     debug("[yellow][Solving fullline] Failed[/]")
     return values
Exemplo n.º 5
0
    def solve(cls, values, requirements):
        "Try to solve a line"

        oldhash = hash(str(values))
        debug({"values": values, "requirements": requirements})

        # START) Skip if line is already full
        if cls.iscompleted(values, requirements):
            if not cls.isfull(values):
                values = cls.fillline(values)
                debug(values)
            return values

        # 1a) Trim from ends
        offset = cls.getoffset(values)

        trim_start = 0
        i_first = offset[1]
        if values[i_first] is True:
            i_end = i_first+requirements[0]
            values[i_first:i_end] = [True]*requirements[0]
            if not i_end < len(values):
                cls.fillline(values)
                debug("[cyan][Return] Solved in 1a) start:[/]", values)
                return values
            values[i_end] = False
            trim_start = i_end+1

        offset = cls.getoffset(values)

        trim_end = 0
        i_last = -1-offset[2]
        if values[i_last] is True:
            i_start = i_last-requirements[-1]+1
            values[i_start:i_last+1 or None] = [True]*requirements[-1]
            if not (len(values) + i_start) > 0:
                values = cls.fillline(values)
                debug("[cyan][Return] Solved in 1a) end:[/]", values)
                return values
            values[i_start-1] = False
            trim_end = i_start-1

        # 1b) End if requirements are met

        if cls.iscompleted(values, requirements):
            values = cls.fillline(values)
            debug("[cyan][Return] Solved in 1a):[/]", values)
            return values

        # 1c) Run for sublist if ends can be trimmed
        if trim_start or trim_end or offset[0]:
            debug("[blue][Recursive] Trimming line[/]",
                  {"t_start": trim_start, "t_end": trim_end, "offset": offset})
            if trim_start and trim_end:
                values[trim_start:trim_end] = cls.solve(
                    values[trim_start:trim_end], requirements[1:-1])
            elif trim_start:
                values[trim_start:-offset[2] or None] = cls.solve(
                    values[trim_start:-offset[2] or None], requirements[1:]
                )
            elif trim_end:
                values[offset[1]:trim_end] = cls.solve(
                    values[offset[1]:trim_end], requirements[:-1]
                )
            else:
                values[offset[1]:-offset[2] or None] = cls.solve(
                    values[offset[1]:-offset[2] or None], requirements
                )
            debug(values)
            return values

        # 2a) Solve fullline

        values = cls.solve_fullline(values, requirements)

        # 2b) End if requirements are met

        if cls.iscompleted(values, requirements):
            values = cls.fillline(values)
            debug("[cyan][Return] Solved in 2) Fullline:[/]", values)
            return values

        # 3a) Solve ranges

        values = cls.solve_ranges(values, requirements)

        # 3b) End if requirements are met

        if cls.iscompleted(values, requirements):
            values = cls.fillline(values)
            debug("[cyan][Return] Solved in 3) Ranges:[/]", values)
            return values

        # END) Solve again if something has changed
        newhash = hash(str(values))
        if oldhash != newhash:
            debug("[blue][Recursive] Line changed - solve again[/]")
            return cls.solve(values, requirements)
        debug("[cyan][Return] Line still unsolved:[/]", values)
        return values
Exemplo n.º 6
0
    def solve_ranges(cls, values, requirements):
        "Solving method: Use free ranges"
        ranges = cls.getfreeranges(values)
        debug("[yellow][Solving ranges] Start[/]")
        debug({"ranges": ranges})

        # Remove all ranges which aren't usable
        smallestreq = min(requirements)

        fillempty = len(ranges) > 1 and countin(
            map(lambda x: True in x[2], ranges), True) == len(requirements)

        for ran in ranges:
            if ran[0] < smallestreq or (fillempty and not True in ran[2]):
                values[ran[1][0]:ran[1][1]+1] = [False]*ran[0]

        # Update ranges var
        ranges = cls.getfreeranges(values)

        # Modify ranges at the end and start

        for ran in ranges:
            if ran[0] < requirements[0]:
                values[ran[1][0]:ran[1][1]+1] = [False]*ran[0]
                continue
            if ran[2][0] is True or (ran[0] == requirements[0] and True in ran[2]):
                values[ran[1][0]:ran[1][0]+requirements[0]
                       ] = [True]*requirements[0]
                if ran[1][0]+requirements[0] < len(values):
                    values[ran[1][0]+requirements[0]] = False
            break
        for ran in ranges[::-1]:
            if ran[0] < requirements[-1]:
                values[ran[1][0]:ran[1][1]+1] = [False]*ran[0]
                continue
            if ran[2][-1] is True or (ran[0] == requirements[-1] and True in ran[2]):
                values[ran[1][1]-requirements[-1]+1:ran[1]
                       [1]+1] = [True]*requirements[-1]
                if ran[1][1]-requirements[-1] >= 0:
                    values[ran[1][1]-requirements[-1]] = False
            break

        # Update ranges var
        ranges = cls.getfreeranges(values)

        # Case "Exact match"
        if list(map(lambda x: x[0], ranges)) == requirements:
            for ran in ranges:
                values[ran[1][0]:ran[1][1]+1] = [True]*ran[0]
            debug("[yellow][Solving ranges] Succeeded with exact match[/]")
            return values

        elif countin(map(lambda x: True in x[2], ranges), True) == len(requirements):
            for i, ran in enumerate(ranges):
                req = requirements[i]
                values[ran[1][0]:ran[1][1]+1] = cls.solve_singlerangesinglereq(ran[2], req)
            return values

        # Case "Only one requirement in one range"
        if len(requirements) == 1 and len(ranges) == 1:
            req = requirements[0]
            ran = ranges[0]

            values[ran[1][0]:ran[1][1] +
                   1] = cls.solve_singlerangesinglereq(ran[2], req)

        # Case "More than one requirement in one range"
        elif len(ranges) == 1:
            ran = ranges[0]
            values[ran[1][0]:ran[1][1] +
                   1] = cls.solve_singlerangemultireq(ran[2], requirements)

        # Case "More than one requirement in more than one range"
        elif len(ranges) > 1 and len(requirements) > 1:
            s = slice(ranges[0][1][0], ranges[-1][1][1]+1)
            values[s] = cls.solve_multirange(values[s], requirements)

        debug("[yellow][Solving ranges] Ended[/]")
        return values