Add function to reveal square; fix incorrect index conversion - crossword.koplugin - Unnamed repository; edit this file 'description' to name the repository.
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit fc14f2b21a919f6233b4aeedbcca3ca61123362e
 (DIR) parent 84e31a3c51a71f5c774e6509a88883b5c0f3c4e7
 (HTM) Author: Scarlett <social@scarlettmcallister.com>
       Date:   Thu, 19 May 2022 21:05:22 -0300
       
       Add function to reveal square; fix incorrect index conversion
       
       A langerous soak in the tub helped me figure out the right right to
       translate row and column coordinates to a grid index. The skinny is
       that given the index number and a grid's column count, you can find
       the row and column numbers corresponding to said index number. Great!
       Now I can play asymmetrical puzzles.
       
       This commit also introduces the `revealSquare` function to the
       `Puzzle` class, which should help players ease their way into more
       challenging clues!
       
       Good luck and happy solving!
       
       Diffstat:
         M puzzle.lua                          |      59 ++++++++++++++++++++++---------
         M spec/unit/crossword_spec.lua        |      48 +++++++++++++++++++++++++++++--
       
       2 files changed, 88 insertions(+), 19 deletions(-)
       ---
 (DIR) diff --git a/puzzle.lua b/puzzle.lua
       @@ -1,5 +1,6 @@
        local md5 = require("ffi/sha2").md5
        local logger = require("logger")
       +local json = require("json")
        
        local Guess = require("guess")
        local Solve = require("solve")
       @@ -30,7 +31,7 @@ function Puzzle:initializePuzzle(path_to_file)
        
           local file_content = file:read("*all")
           file:close()
       -
       +   
           local Puzzle = require("puzzle")
           local puzzle = Puzzle:new{}
           puzzle:init(json.decode(file_content))
       @@ -185,7 +186,7 @@ function Puzzle:getGrid()
        end
        
        function Puzzle:setActiveSquare(row, col)
       -   self.active_square_index = ((row - 1) * self.size.rows) + col
       +   self.active_square_index = self:getIndexFromCoordinates(row, col)
        end
        
        function Puzzle:getActiveSquare()
       @@ -197,10 +198,21 @@ function Puzzle:resetActiveSquare()
        end
        
        function Puzzle:getSquareAtPos(row, col)
       -   local index = ((row - 1) * self.size.rows) + col
       +   local index = self:getIndexFromCoordinates(row, col) --((row - 1) * self.size.rows) + col
           return self.solves[index]
        end
        
       +function Puzzle:getIndexFromCoordinates(row, col)
       +   local index = col + ((row - 1) * self.size.cols)
       +   return index
       +end
       +
       +function Puzzle:getCoordinatesFromIndex(index)
       +   local row = math.ceil(index / self.size.cols)
       +   local col = index - (self.size.cols * (row - 1))
       +   return row, col
       +end
       +
        function Puzzle:getNextIndexForDirection(index, direction)
           index = index + 1
           local solve = self.solves[index]
       @@ -233,7 +245,8 @@ function Puzzle:getPrevIndexForDirection(index, direction)
        end
        
        function Puzzle:getSolveByIndex(index)
       -   return self.solves[index]
       +   local row, col = self:getCoordinatesFromIndex(index)
       +   return self:getSolveByPos(row, col, Solve.DOWN)
        end
        
        function Puzzle:setLetterForGuess(letter, grid_elm)
       @@ -275,10 +288,7 @@ end
        function Puzzle:getNextCluePos(row, col, direction)
           local _, index = self:getSolveByPos(row, col, direction)
           local next_solve = self:getNextIndexForDirection(index, direction)
       -   local next_position = next_solve.grid_num
       -   local next_row = math.ceil(next_position / self.size.rows)
       -   local next_col = self.size.cols - ((next_row * self.size.rows) - next_position)
       -   return next_row, next_col
       +   return self:getCoordinatesFromIndex(next_solve.grid_num) -- Returns row and col
        end
        
        -- Given a grid position (row, col) and direction (across or down), find another grid
       @@ -286,13 +296,10 @@ end
        function Puzzle:getPrevCluePos(row, col, direction)
           local _, index = self:getSolveByPos(row, col, direction)
           local prev_solve = self:getPrevIndexForDirection(index, direction)
       -   local prev_position = prev_solve.grid_num
       -   local prev_row = math.ceil(prev_position / self.size.rows)
       -   local prev_col = self.size.cols - ((prev_row * self.size.rows) - prev_position)
       -   return prev_row, prev_col
       +   return self:getCoordinatesFromIndex(prev_solve.grid_num) -- Returns row and col
        end
        
       -function Puzzle:getSolveByPos(row, col, direction)   
       +function Puzzle:getSolveByPos(row, col, direction)
           local solve
           local index
           local grid_elm = self.grid[row][col]
       @@ -321,9 +328,28 @@ function Puzzle:getClueByPos(row, col, direction)
           return solve.clue
        end
        
       +function Puzzle:revealSquare(index)
       +   local solve = self:getSolveByIndex(index)
       +   -- map grid index to the letters
       +   local letter
       +   for position, grid_index in ipairs(solve.grid_indices) do
       +      if index == grid_index then
       +         letter = string.sub(solve.word, position, position)
       +      end
       +   end
       +   if letter then
       +      self:setLetterForGuess(letter, index)
       +   end
       +   return letter
       +end
       +
        function Puzzle:isSquareCorrect(square)
           local guess = self:getLetterForSquare(square)
        
       +   if guess == nil or guess == "" then
       +      return false
       +   end
       +   
           for i, solve in ipairs(self.solves) do
              for k, grid_index in ipairs(solve.grid_indices) do
                 if square == grid_index then
       @@ -343,10 +369,10 @@ function Puzzle:checkPuzzle()
           for i, solve in ipairs(self.solves) do
              for char_pos, grid_index in ipairs(solve.grid_indices) do
                 if self.guesses[grid_index] and not grid_elm_results[grid_index] then
       -            logger.dbg("Checking " .. grid_index)
                    local letter_guess = self.guesses[grid_index].letter
       +            logger.dbg(letter_guess)
                    -- Only check the guess if it is not nil or an empty string            
       -            if letter_guess ~= "" or letter_guess ~= nil then
       +            if letter_guess ~= "" and letter_guess ~= nil then
                       local letter_solve = string.sub(solve.word, char_pos, char_pos)
                       local guess_status = (letter_guess == letter_solve) and
                          Guess.STATUS.CHECKED_CORRECT or
       @@ -375,8 +401,7 @@ function Puzzle:checkSquare(row, col)
           -- as long as we get a result.
           local solve = self:getSolveByPos(row, col, Solve.DOWN) or
              self:getSolveByPos(row, col, Solve.ACROSS)
       -   -- Get the grid index, found by some not-so-fancy math, and then get the corresponding guess.
       -   local grid_index_to_check = ((row - 1) * self.size.rows) + col
       +   local grid_index_to_check = self:getIndexFromCoordinates(row, col)
           local guess = self.guesses[grid_index_to_check]
           -- Get out of here if there's nothing to check.
           if not guess then
 (DIR) diff --git a/spec/unit/crossword_spec.lua b/spec/unit/crossword_spec.lua
       @@ -31,6 +31,50 @@ describe("Crossword plugin module", function()
                          assert.are.same(16, odd_puzzle.size.cols)
                          assert.are.same(15, even_puzzle.size.cols)
                    end)
       +            it("should return correct index from coordinates", function()
       +                  assert.are.same(1, even_puzzle:getIndexFromCoordinates(1,1))
       +                  assert.are.same(16, even_puzzle:getIndexFromCoordinates(2,1))
       +                  assert.are.same(1, odd_puzzle:getIndexFromCoordinates(1,1))
       +                  assert.are.same(17, odd_puzzle:getIndexFromCoordinates(2,1))
       +            end)
       +            it("should return correct coordinates from index", function()
       +                  local row, col = even_puzzle:getCoordinatesFromIndex(1)
       +                  assert.are.same(1, row)
       +                  assert.are.same(1, col)
       +                  row, col = even_puzzle:getCoordinatesFromIndex(16)
       +                  assert.are.same(2, row)
       +                  assert.are.same(1, col)
       +            end)
       +            it("should set guess when given letter", function()
       +                  local index = even_puzzle:getIndexFromCoordinates(1,1)
       +                  even_puzzle:setLetterForGuess("A", index)
       +                  assert.are.same("A", even_puzzle:getLetterForSquare(index))
       +            end)
       +            it("should say incorrect square if no guess present", function()
       +                  local index = even_puzzle:getIndexFromCoordinates(1,2)
       +                  assert.are.same(false, even_puzzle:isSquareCorrect(index))
       +            end)
       +            it("should say incorrect square if guess is wrong", function()
       +                  local index = even_puzzle:getIndexFromCoordinates(1,2)
       +                  even_puzzle:setLetterForGuess("E", index)
       +                  assert.is_not_true(even_puzzle:isSquareCorrect(index)) -- expects a
       +            end)
       +            it("should say correct square if guess is correct", function()
       +                  local index = even_puzzle:getIndexFromCoordinates(1,2)
       +                  even_puzzle:setLetterForGuess("A", index)
       +                  assert.are.same(true, even_puzzle:isSquareCorrect(index))
       +            end)
       +            it("should reveal correct square with correct letter", function()                  
       +                  local index = even_puzzle:getIndexFromCoordinates(1,1)
       +                  assert.are.same(false, even_puzzle:isSquareCorrect(index))
       +                  even_puzzle:revealSquare(index)
       +                  assert.are.same(true, even_puzzle:isSquareCorrect(index))
       +                  
       +                  index = even_puzzle:getIndexFromCoordinates(2,1)
       +                  assert.is_not_true(even_puzzle:isSquareCorrect(index))
       +                  even_puzzle:revealSquare(index)
       +                  assert.are.same(true, even_puzzle:isSquareCorrect(index))
       +            end)
              end)
        
              describe("GameView with even Puzzle grids", function()
       @@ -112,8 +156,8 @@ describe("Crossword plugin module", function()
                          }
                          game_view:render()
                          game_view:leftChar()
       -                  assert.are.same(16, game_view.active_col_num)
       -                  assert.are.same(12, game_view.active_row_num)
       +                  assert.are.same(1, game_view.active_col_num)
       +                  assert.are.same(13, game_view.active_row_num)
                    end)                        
                    it("should move to next clue position when pointer exceeds current clue length", function()
                          game_view = GameView:new{