Refactoring handle_player_movements
Refactoring handle_player_movements

Globally speaking:

 - Separate your query/commands
 - Separate your input/logic/validation
 - don't use magic constants and certainly don't repeat them

Exemplary lines:

        if(key == 'w' && player.position.x > 2 && screen[player.position.below()] != game_screen::filler &&
            screen[player.position.above()] == game_screen::filler && screen[player.position.above(2)] == game_screen::filler)
                newpos.y -= 2;

    Here, input validation/interpretation (key == 'w') is mixed with
    movement logic (`newpos.y -= 2`), and with game logic (the `filler`
    check as well as... well the rest).

Extracted

 * is_free

       Could have been a member of `game_screen`, like
       `game_screen::is_valid()`; Just showing the other option is a
       free function

 * key_movement (coords, char -> coords)

       This just encodes the motion commands, no validation of the result

 * get_path (from, to)

       A helper to generate the path from [from, ..., to] position.
       Currently only handles vertical/horizontal moves.

       This path is used from inside the new `keyboard_event_loop`
       (replaces `handle_player_movements`), to find the last reachable
       field in the intended direction of movement

 * keyboard_event_loop

       This is the new thing. First it

         - early outs on `q`/`Q`
         - it blindly calculates the intended destination (regardless of
           obstacles)
         - next, it calculates the "provisional" path to that
           destination (using `get_path`)
         - lastly it loops to the last valid `step` along that path

      The separation of concerns here should remove the sources of error
      that lead to the "interesting" movement bugs that we witnessed
      during demo play.

Skorezore/Gaem,nmai/Gaem,sehe/Gaem,nmai/Gaem,sehe/Gaem,Skorezore/Gaem,Skorezore/Gaem