Пример #1
0
 def create_atlantic_puzzle():
     """ Creates a puzzle from the Atlantic puzzle of May 15, 2020
     +-----------------+
     |D|A|B|*|*|E|F|T|S|
     |S|L|I|M|*|R|I|O|T|
     |L|O|C|A|V|O|R|E|S|
     |R|E|U|N|I|T|E|D|*|
     |*|*|R|A|P|I|D|*|*|
     |*|R|I|C|E|C|A|K|E|
     |C|O|O|L|R|A|N|C|H|
     |C|L|U|E|*|C|A|L|X|
     |R|O|S|S|*|*|E|R|E|
     +-----------------+
     """
     n = 9
     grid = Grid(n)
     for (r, c) in [
         (1, 4),
         (1, 5),
         (2, 5),
         (4, 9),
         (5, 8),
         (5, 9),
     ]:
         grid.add_black_cell(r, c)
     puzzle = Puzzle(grid)
     puzzle.title = 'My Atlantic Theme'
     return puzzle
Пример #2
0
    def test_add_black(self):
        n = 5
        grid = Grid(n)
        black_cells = [
            (1, 1),
            (1, 3),
            (2, 3),
            (2, 4),
            (3, 1),
            (3, 2),
        ]
        for (r, c) in black_cells:
            grid.add_black_cell(r, c)

        puzzle = Puzzle(grid)

        expected_cells = [
            ["*", " ", "*", " ", " "],
            [" ", " ", "*", "*", " "],
            ["*", "*", " ", "*", "*"],
            [" ", "*", "*", " ", " "],
            [" ", " ", "*", " ", "*"],
        ]
        for r in range(1, n + 1):
            for c in range(1, n + 1):
                expected = expected_cells[r - 1][c - 1]
                actual = puzzle.get_cell(r, c)
                self.assertEqual(expected, actual, f'Mismatch at ({r},{c})')
Пример #3
0
def puzzle_new():
    """ Creates a new puzzle and redirects to puzzle screen """

    # Get the chosen grid name from the query parameters
    gridname = request.args.get('gridname')

    # Open the corresponding file and read its contents as json
    # and recreate the grid from it
    userid = 1  # TODO replace hard-coded user ID
    query = DBGrid.query.filter_by(userid=userid, gridname=gridname)
    jsonstr = query.first().jsonstr
    grid = Grid.from_json(jsonstr)

    # Now pass this grid to the Puzzle() constructor
    puzzle = Puzzle(grid)

    # Save puzzle in the session
    jsonstr = puzzle.to_json()
    session['puzzle'] = jsonstr
    session['puzzle.initial.sha'] = sha256(jsonstr)

    # Remove any leftover puzzle name in the session
    session.pop('puzzlename', None)

    return redirect(url_for('uipuzzle.puzzle_screen'))
Пример #4
0
 def test_get_crossing_words(self):
     grid = TestGrid.get_good_grid()
     puzzle = Puzzle(grid)
     # 47 down is crossed by:
     # 46 across, 50 across, 54 across
     expected = [46, 50, 54]
     down_word = puzzle.get_down_word(47)
     actual = [nc.seq for nc in down_word.get_crossing_words()]
     self.assertListEqual(expected, actual)
Пример #5
0
 def test_get_crossing_words(self):
     grid = TestGrid.get_good_grid()
     puzzle = Puzzle(grid)
     # 20 across is crossed by:
     # 3 down, 14 down, 21 down, 4 down, and 5 down
     expected = [3, 14, 21, 4, 5]
     across_word = puzzle.get_across_word(20)
     actual = [word.seq for word in across_word.get_crossing_words()]
     self.assertListEqual(expected, actual)
Пример #6
0
    def __init__(self, data):

        self.data = data
        self.offset = 0

        # Get the size
        self.offset = self.OFFSET_WIDTH
        self.n = n = self.read_byte()
        self.grid = grid = Grid(n)

        # Read the solution to get the black cell locations
        self.offset = self.OFFSET_WORDS
        for r in range(1, n+1):
            line = self.read_chunk(n)
            for c in range(1, n+1):
                letter = chr(line[c-1])
                if letter == self.BLACK_CELL:
                    grid.add_black_cell(r, c)

        # Create the puzzle, then go back and read the words
        self.puzzle = puzzle = Puzzle(grid)

        self.offset = self.OFFSET_WORDS
        for r in range(1, n+1):
            line = self.read_chunk(n)
            for c in range(1, n + 1):
                letter = chr(line[c-1])
                if not grid.is_black_cell(r, c):
                    puzzle.set_cell(r, c, letter)

        # Skip over the solution work area
        self.offset += n*n

        # Read the title and set it in the puzzle

        title = self.read_string()
        if title != "":
            puzzle.title = title

        # Skip the author and copyright lines
        s = self.read_string()     # author
        s = self.read_string()     # copyright

        # Read the clues
        for nc in puzzle.numbered_cells:
            if nc.a:        # Across word
                clue = self.read_string()
                puzzle.set_clue(nc.seq, Word.ACROSS, clue)
            if nc.d:        # Down word
                clue = self.read_string()
                puzzle.set_clue(nc.seq, Word.DOWN, clue)

        # Done
        self.jsonstr = puzzle.to_json()
Пример #7
0
 def test_set_cell(self):
     n = 5
     puzzle = Puzzle(Grid(n))
     puzzle.set_cell(2, 3, 'D')
     cell = puzzle.get_cell(2, 3)
     self.assertEqual('D', cell)
     for r in range(1, n + 1):
         if r == 2:
             continue
         for c in range(1, n + 1):
             if c == 3:
                 continue
             cell = puzzle.get_cell(r, c)
             self.assertEqual(Puzzle.WHITE, cell, f'Mismatch at ({r}, {c})')
Пример #8
0
 def create_puzzle():
     """
     Creates sample puzzle as:
     +---------+
     | | |*| | |
     | | |*|*| |
     |*|*| |*|*|
     | |*|*| | |
     | | |*| | |
     +---------+
     """
     n = 5
     grid = Grid(n)
     for (r, c) in [
         (1, 3),
         (2, 3),
         (2, 4),
         (3, 1),
         (3, 2),
     ]:
         grid.add_black_cell(r, c)
     return Puzzle(grid)
Пример #9
0
 def create_nyt_puzzle():
     """
     Creates a puzzle from a real New York Times crossword of March 15, 2020
     +-----------------------------------------+
     |A|B|B|A|*| | | |*| | | | | |*| | | | | | |
     | | | | |*| | | |*| | | | | |*| | | | | | |
     | | | | | | | | | | | | | | |*| | | | | | |
     | | | | | |*| | | | | |*| | | |*| | | | | |
     | | | |*| | | | | |*|*| | | | | |*|*| | | |
     |*|*|*| | | | | | | | | | | | | | | | | | |
     | | | | | | |*|*| | | | | | |*| | | | | | |
     | | | | |*| | | |*| | | |*|*| | | | | | | |
     | | | | | | | | | | | | | | | | | | |*|*|*|
     | | | |*| | | | | |*| | | | | | |*| | | | |
     | | | | | |*| | | | |*| | | | |*| | | | | |
     | | | | |*| | | | | | |*| | | | | |*| | | |
     |*|*|*| | | | | | | | | | | | | | | | | | |
     | | | | | | | |*|*| | | |*| | | |*| | | | |
     | | | | | | |*| | | | | | |*|*| | | | | | |
     | | | | | | | | | | | | | | | | | | |*|*|*|
     | | | |*|*| | | | | |*|*| | | | | |*| | | |
     | | | | | |*| | | |*| | | | | |*| | | | | |
     | | | | | | |*| | | | | | | | | | | | | | |
     | | | | | | |*| | | | | |*| | | |*| | | | |
     | | | | | | |*| | | | | |*| | | |*| | | | |
     +-----------------------------------------+
     """
     n = 21
     grid = Grid(n)
     for (r, c) in [(1, 5), (1, 9), (1, 15), (2, 5),
                    (2, 9), (2, 15), (3, 15), (4, 6), (4, 12), (4, 16),
                    (5, 4), (5, 10), (5, 11), (5, 17), (5, 18), (6, 1),
                    (6, 2), (6, 3), (7, 7), (7, 8), (7, 15), (8, 5), (8, 9),
                    (8, 13), (8, 14), (9, 19), (9, 20), (9, 21), (10, 4),
                    (10, 10), (11, 6), (11, 11), (12, 5), (13, 1), (13, 2),
                    (13, 3), (14, 8), (15, 7), (17, 4), (17, 5)]:
         grid.add_black_cell(r, c)
     return Puzzle(grid)
Пример #10
0
    def create_puzzle(self, xmlstr):
        ns = {
            'cc': 'http://crossword.info/xml/crossword-compiler',
            'rp': 'http://crossword.info/xml/rectangular-puzzle'
        }
        root = ET.fromstring(xmlstr)
        elem_rp = root.find('rp:rectangular-puzzle', ns)
        elem_crossword = elem_rp.find('rp:crossword', ns)
        elem_grid = elem_crossword.find('rp:grid', ns)

        # Grid size
        n = int(elem_grid.get('height'))
        grid = Grid(n)

        # Black cells
        for elem_cell in elem_grid.findall('rp:cell', ns):
            celltype = elem_cell.get('type')
            if celltype == 'block':
                r = int(elem_cell.get('y'))
                c = int(elem_cell.get('x'))
                grid.add_black_cell(r, c)

        # Title
        elem_title = elem_rp.find('rp:metadata/rp:title', ns)
        title = elem_title.text
        if not title:
            title = None

        # Puzzle
        puzzle = Puzzle(grid, title)

        # Add the cells
        for elem_cell in elem_grid.findall('rp:cell', ns):
            r = int(elem_cell.get('y'))
            c = int(elem_cell.get('x'))
            if puzzle.is_black_cell(r, c):
                continue
            letter = elem_cell.get('solution')
            if letter != ' ':
                puzzle.set_cell(r, c, letter)

        # Map the word ID to numbered cells
        wordmap = {}
        for elem_word in elem_crossword.findall('rp:word', ns):
            wordid = elem_word.get('id')
            r = int(elem_word.get('y').split('-')[0])
            c = int(elem_word.get('x').split('-')[0])
            nc = puzzle.get_numbered_cell(r, c)
            wordmap[wordid] = nc

        # Add the clues
        for elem_clues in elem_crossword.findall('rp:clues', ns):
            elem_b = elem_clues.find('rp:title/rp:b', ns)
            direction = elem_b.text[0]  # A or D
            for elem_clue in elem_clues.findall('rp:clue', ns):
                wordid = elem_clue.get('word')
                nc = wordmap[wordid]
                clue = elem_clue.text
                puzzle.set_clue(nc.seq, direction, clue)

        return puzzle
Пример #11
0
 def test_title_not_set(self):
     grid = Grid(11)
     puzzle = Puzzle(grid)
     self.assertIsNone(puzzle.title)
Пример #12
0
    def create_nyt_daily():
        """ from https://www.nytimes.com/crosswords/game/daily/2016/09/20 """
        grid = Grid(15)
        for r, c in [(1, 5), (1, 11), (2, 5), (2, 11), (3, 5), (3, 11),
                     (4, 14), (4, 15), (5, 7), (5, 12), (6, 1), (6, 2), (6, 3),
                     (6, 8), (6, 9), (7, 4), (8, 5), (8, 6), (8, 10), (8, 11),
                     (11, 4)]:
            grid.add_black_cell(r, c)
        puzzle = Puzzle(grid)
        for seq, text in [(1, "ACTS"), (5, "PLASM"),
                          (10, "EDGY"), (14, "SHIV"), (15, "RUCHE"),
                          (16, "VALE"), (17, "NINE"), (18, "USUAL"),
                          (19, "IRON"), (20, "ENGLISHTRIFLE"), (23, "RASTAS"),
                          (24, "EDNA"), (25, "WAS"), (28, "EMIT"),
                          (30, "DIGEST"), (32, "MAY"), (35, "BAKEDALASKA"),
                          (38, "ALOT"), (40, "ONO"), (41, "BAER"),
                          (42, "PLUMPUDDING"), (47, "YDS"), (48, "LESSON"),
                          (49, "TIOS"), (51, "EYE"), (52, "OHMS"),
                          (55, "CLUMSY"), (59, "NOPIECEOFCAKE"), (62, "UNDO"),
                          (64, "NAOMI"), (65, "KRIS"), (66, "SIMP"),
                          (67, "GLOMS"), (68, "EIRE"), (69, "EXES"),
                          (70, "ESTEE"), (71, "RATS")]:
            puzzle.get_across_word(seq).set_text(text)

        for seq, clue in [
            (1, "___ of the Apostles"),
            (5, "Ending with neo- or proto-"),
            (10, "Pushing conventional limits"),
            (14, "Blade in the pen"),
            (15, "Strip of fabric used for trimming"),
            (16, "Low ground, poetically"),
            (17, "Rock's ___ Inch Nails"),
            (18, "Habitual customer's order, with \"the\""),
            (19, "Clothes presser"),
            (20,
             "Layers of sherry-soaked torte, homemade custard and fruit served chilled in a giant stem glass"
             ),
            (23, "Dreadlocked ones, informally"),
            (24, "Comical \"Dame\""),
            (25, "\"Kilroy ___ here\""),
            (28, "Give off, as vibes"),
            (30, "Summary"),
            (32, "___-December romance"),
            (35,
             "Ice cream and sponge topped with meringue and placed in a very hot oven for a few minutes"
             ),
            (38, "Oodles"),
            (40, "Singer with the site imaginepeace.com"),
            (41, "Boxer Max"),
            (42,
             "Steamed-for-hours, aged-for-months concoction of treacle, brandy, fruit and spices, set afire and served at Christmas"
             ),
            (47, "Fabric purchase: Abbr."),
            (48, "Teacher's plan"),
            (49, "Uncles, in Acapulco"),
            (51, "___ contact"),
            (52, "Units of resistance"),
            (55, "Ham-handed"),
            (59,
             "What a chef might call each dessert featured in this puzzle, literally or figuratively"
             ),
            (62, "Command-Z command"),
            (64, "Actress Watts"),
            (65, "Kardashian matriarch"),
            (66, "Fool"),
            (67, "Latches (onto)"),
            (68, "Land of Blarney"),
            (69, "Ones who are splitsville"),
            (70, "Lauder of cosmetics"),
            (71, "\"Phooey!\""),
        ]:
            puzzle.get_across_word(seq).set_clue(clue)

        for seq, clue in [
            (1, "Ed of \"Up\""),
            (2, "Set traditionally handed down to an eldest daughter"),
            (3, "Tiny bell sounds"),
            (4, "Willowy"),
            (5, "German kingdom of old"),
            (6, "Growing luxuriantly"),
            (7, "Severe and short, as an illness"),
            (8, "Glass fragment"),
            (9, "Gates of philanthropy"),
            (10, "Voldemort-like"),
            (11, "\"Hesitating to mention it, but...\""),
            (12, "Mop & ___"),
            (13, "Itch"),
            (21, "da-DAH"),
            (22, "Pass's opposite"),
            (26, "\"___ and answered\" (courtroom objection)"),
            (27, "Constellation units"),
            (29, "Walloped to win the bout, in brief"),
            (31, "Chew the fat"),
            (32, "Sugar ___"),
            (33, "Locale for urban trash cans"),
            (34, "Sam Cooke's first #1 hit"),
            (36, "Come to a close"),
            (37, "\"I dare you!\""),
            (39, "Designs with ® symbols: Abbr."),
            (43, "Lowdown, in slang"),
            (44, "Drive mad"),
            (45, "Salade ___"),
            (46, "Club game"),
            (50, "Lollipop"),
            (53, "\"Square\" things, ideally"),
            (54, "\"Git!\""),
            (56, "\"West Side Story\" seamstress"),
            (57, "Mini, e.g."),
            (58, "Positive R.S.V.P.s"),
            (60, "Error report?"),
            (61, "J.Lo's daughter with a palindromic name"),
            (62, "Manipulate"),
            (63, "Kill, as an idea"),
        ]:
            puzzle.get_down_word(seq).set_clue(clue)
        return puzzle
Пример #13
0
 def test_title_set_back_to_none(self):
     grid = Grid(11)
     puzzle = Puzzle(grid, "First Title")
     self.assertEqual("First Title", puzzle.title)
     puzzle.title = None
     self.assertIsNone(puzzle.title)
Пример #14
0
 def test_title_changed(self):
     grid = Grid(11)
     puzzle = Puzzle(grid, "First Title")
     self.assertEqual("First Title", puzzle.title)
     puzzle.title = "Second Title"
     self.assertEqual("Second Title", puzzle.title)
Пример #15
0
 def test_title_set_later(self):
     grid = Grid(11)
     puzzle = Puzzle(grid)
     puzzle.title = "Later"
     self.assertEqual("Later", puzzle.title)
Пример #16
0
 def test_title_is_set(self):
     grid = Grid(11)
     puzzle = Puzzle(grid, "My Title")
     self.assertEqual("My Title", puzzle.title)
Пример #17
0
 def test_str(self):
     grid = Grid(3)
     puzzle = Puzzle(grid)
     puzzle_string = str(puzzle)
     self.assertTrue("+-----+" in puzzle_string)
     self.assertTrue("| | | |" in puzzle_string)