From f5d30c396e3c42d3d45dd3eff454803a08e9e393 Mon Sep 17 00:00:00 2001 From: paulwuertz Date: Sat, 27 Jan 2018 06:38:46 +0100 Subject: [PATCH 1/2] Added SVG Export(unsolved) and JSON import --- README.rst | 2 + contributors.txt | 1 + nonogram_solver/nonogram.py | 73 +++++++++++++++++++++++++++++++++++-- requirements.txt | 3 +- setup.py | 2 +- tests/rose_nonogram.json | 1 + tests/test.svg | 2 + tests/test_solver.py | 9 ++++- 8 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 tests/rose_nonogram.json create mode 100644 tests/test.svg diff --git a/README.rst b/README.rst index 024716a..d0026c3 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,8 @@ This project provides a general nonogram solver. It can determine if a puzzle is This solver can be used to create nonogram puzzles given a successful final solution. If the given solution is not solvable, the solver will suggest "hint" squares to be filled in when the nonogram is given to a human solver. +Input from JSON file possible, as generation of SVGs. + .. |ci-status| image:: https://travis-ci.org/mprat/nonogram-solver.svg?branch=master :target: https://travis-ci.org/mprat/nonogram-solver :alt: Build status diff --git a/contributors.txt b/contributors.txt index ce82d32..0220159 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1 +1,2 @@ Michele Pratusevich +Paul Wurtz \ No newline at end of file diff --git a/nonogram_solver/nonogram.py b/nonogram_solver/nonogram.py index 0c140b7..2d4a349 100644 --- a/nonogram_solver/nonogram.py +++ b/nonogram_solver/nonogram.py @@ -2,7 +2,8 @@ Defines the nonogram datatype. """ import numpy as np - +import svgwrite +import json class Nonogram(object): def __init__(self, ordered=True): @@ -14,6 +15,12 @@ def __init__(self, ordered=True): self.solution_state = None self.solution_list = None self.ordered = ordered + #svg constants + self.mcols,self.mrows=[None,None] #max num of constraints + self.wBox,self.margin=[30,30] #dimensions + self.numBoxX,self.numBoxY=[0,0] #constraints+fields + self.wXstroke,self.wYstroke=[0,0] #length of strokes + self.xySize=[0,0] #canvas size def _init_puzzle(self): self.puzzle_state = -1 * np.ones((self.n_rows, self.n_cols)) @@ -69,9 +76,67 @@ def init_from_matrix(self, matrix): self.solution_state = matrix self.solution_list = zip(np.where(matrix == 1)) # TODO: finish this function + def init_from_json(self, jfile): + """ + Args: + the path to a json file: + json containing the row and col constraints as arrays of arrays i.e: + { + "ver":[[1],[]], + "hor":[[1],[]] + } + dimensions are deductable by len(json["ver"])/len(json["hor"]) + """ + j=json.loads(open(jfile).read()) + self.n_rows = len(j["ver"]) + self.n_cols = len(j["hor"]) - def display_puzzle_svg(self): - pass + filled_positions = [] + self.solution_list = filled_positions + self.rows_constraints = j["ver"] + self.cols_constraints = j["hor"] + self._init_puzzle() + self.solution_state = np.zeros((self.n_rows, self.n_cols)) + def display_number(self,svg,x,y,num): + if num>9: cor=.15 + else: cor=0 + svg.add(svg.text(num, insert=(self.margin+(x-2/3-cor)*self.wBox, self.margin+(y+2/3)*self.wBox), font_size=16, fill='black')) + + def display_puzzle_svg(self,toSVG="test.svg"): + #init SVG + dwg = svgwrite.Drawing(toSVG, profile='tiny') + #get row/col constraints and max numbers of hints + rows,cols=[self.rows_constraints,self.cols_constraints] + self.mcols,self.mrows=[max([len(e) for e in cols]),max([len(e) for e in rows])] + #set constants + self.numBoxX,self.numBoxY=[self.mrows+self.n_cols,self.mcols+self.n_rows] #constraints+fields + self.wXstroke,self.wYstroke=[self.numBoxX*self.wBox,self.wBox*self.numBoxY] #length of strokes + self.xySize=[self.wXstroke+2*self.margin,self.wYstroke+2*self.margin] + #print gray raster + for i in range(self.numBoxX+1): + dwg.add(dwg.line((self.margin+i*self.wBox,self.margin), (self.margin+i*self.wBox,self.margin+self.wYstroke), stroke_width=5 ,stroke=svgwrite.rgb(70, 70, 70, '%'))) + for i in range(self.numBoxY+1): + dwg.add(dwg.line((self.margin,self.margin+i*self.wBox), (self.margin+self.wXstroke,self.margin+i*self.wBox), stroke_width=5 ,stroke=svgwrite.rgb(70, 70, 70, '%'))) + #print black raster + for i in [0,self.numBoxX]+[b for b in range(self.mrows,self.numBoxX,5)]: + dwg.add(dwg.line((self.margin+i*self.wBox,self.margin), (self.margin+i*self.wBox,self.margin+self.wYstroke), stroke_width=5 ,stroke=svgwrite.rgb(0, 0, 0, '%'))) + for i in [0,self.numBoxY]+[b for b in range(self.mcols,self.numBoxY,5)]: + dwg.add(dwg.line((self.margin,self.margin+i*self.wBox), (self.margin+self.wXstroke,self.margin+i*self.wBox), stroke_width=5 ,stroke=svgwrite.rgb(0, 0, 0, '%'))) + #print row constraints + for r in range(len(rows)): + ei=self.mrows + for e in range(1,1+len(rows[r])): + self.display_number(dwg,ei,self.mcols+r,rows[r][-e]) + ei-=1 + #print col constraints + for c in range(len(cols)): + ei=self.mcols-1 + for e in range(1,1+len(cols[c])): + self.display_number(dwg,self.mrows+c+1,ei,cols[c][-e]) + ei-=1 + #set viewbox and export + dwg.viewbox(minx=0, miny=0, width=self.xySize[0], height=self.xySize[1]) + dwg.save() def display_solution_svg(self): - pass + pass \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 296d654..2c3af04 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ -numpy \ No newline at end of file +numpy +svgwrite diff --git a/setup.py b/setup.py index b0ab485..7952832 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name='nonogram-solver', - version='0.1', + version='0.2', description='A nonogram puzzle solver.', long_description=long_description, url='https://github.com/mprat/nonogram-solver', diff --git a/tests/rose_nonogram.json b/tests/rose_nonogram.json new file mode 100644 index 0000000..a9b0564 --- /dev/null +++ b/tests/rose_nonogram.json @@ -0,0 +1 @@ +{"ver":[[4],[2,1],[1,4,2],[3,2,3,1,3],[2,1,2,3,2],[1,1,1,6,1,1],[2,2,2,2,2,1],[1,3,3,2,1],[2,6,5,2],[1,2,5,2],[3,3,5],[1,2,2,2],[8,1,1],[1,2,2],[1,4],[4,3],[5,4],[4,9],[1,2,6,1,1],[7,1],[5,5,3],[8,4,7],[1,11,5,2],[1,7,3,3,2],[7,12],[2,4,4],[2,3],[2,4],[5],[2,5],[3,4,2,1],[10,2],[4,4],[4],[2]],"hor":[[4],[2,4],[2,2,2,1],[3,2,5],[2,1,1,5],[1,2,2,1,5],[1,2,1,2,1,5,1],[1,3,1,3,3,1,1],[1,4,1,3,3,1,5],[2,2,1,5,1,9],[1,1,1,1,1,15],[1,1,1,2,2,2,10,2],[1,2,2,1,1,1,7,1,2],[1,1,1,1,2,6,2,2],[1,2,1,1,2,5,1,3],[1,2,1,4,4,2,3],[1,2,2,1,3,3,3,1,2],[1,3,1,6,5,1,2],[4,1,1,2,2,2,2,2,1],[1,2,2,1,2,1,2,2,3],[1,2,1,2,1,2,2,1],[1,2,5,1,2,1],[2,4,4],[5,1,3],[2]]} \ No newline at end of file diff --git a/tests/test.svg b/tests/test.svg new file mode 100644 index 0000000..95f320d --- /dev/null +++ b/tests/test.svg @@ -0,0 +1,2 @@ + +412241313232321211611112222212331256225215332221118221413445941162117355748251112337112744232425521243210444244212225235112512211512121113313151331419151221511111210222111217111221226211113152112132441212133312212156131122222114322121221122121211215214423152 \ No newline at end of file diff --git a/tests/test_solver.py b/tests/test_solver.py index 524d287..05a2097 100644 --- a/tests/test_solver.py +++ b/tests/test_solver.py @@ -12,7 +12,7 @@ def simple_nonogram_from_string_box(): '..oo.', '.o..o', 'o...o'] - + nonogram = Nonogram() nonogram.init_from_solution_string(string_box) return nonogram @@ -73,3 +73,10 @@ def test_nonogram_solver_manual(simple_nonogram_from_string_box): [0, 0, 1, 1, 0], [-1, -1, -1, 0, 1], [-1, -1, 0, 0, 1]])) + + +def svgGen(): + nonogram = Nonogram() + nonogram.init_from_json("rose_nonogram.json") + nonogram.display_puzzle_svg() +svgGen() \ No newline at end of file From 6d5303580b1c61e5194f75796700ad026f4a37ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20W=C3=BCrtz?= Date: Sat, 27 Jan 2018 06:43:24 +0100 Subject: [PATCH 2/2] Update README.rst --- README.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d0026c3..5e526d9 100644 --- a/README.rst +++ b/README.rst @@ -13,11 +13,16 @@ Input from JSON file possible, as generation of SVGs. :target: https://travis-ci.org/mprat/nonogram-solver :alt: Build status - Installation -------- To install, run `pip install nonogram-solver`. +Example +-------- + +.. image:: https://github.com/paulwuertz/nonogram-solver/blob/master/tests/test.svg + :height: 400px + :width: 300px Project Website ---------