1
/* ipuz-symmetry.c
2
 *
3
 * Copyright 2023 Jonathan Blandford <jrb@gnome.org>
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18
 *
19
 * SPDX-License-Identifier: (LGPL-2.1-or-later OR MIT)
20
 */
21

            
22

            
23
#include "libipuz.h"
24
#include <libipuz/ipuz-symmetry.h>
25

            
26
IPuzCellCoord
27
468
ipuz_symmetry_calculate (IPuzCellCoord      coord,
28
                         guint              puzzle_width,
29
                         guint              puzzle_height,
30
                         IPuzSymmetry       symmetry,
31
                         IPuzSymmetryOffset symmetry_offset)
32
{
33
468
  IPuzCellCoord mirror_coord = coord;
34

            
35
  /* We need to be within the puzzle bounds */
36
468
  g_return_val_if_fail (coord.row < puzzle_height && coord.column < puzzle_width, mirror_coord);
37
  /* Symmetry Quarter requires a square grid */
38
468
  if (puzzle_width != puzzle_height)
39
    g_return_val_if_fail (symmetry != IPUZ_SYMMETRY_ROTATIONAL_QUARTER, mirror_coord);
40

            
41
468
  switch (symmetry)
42
    {
43
    case IPUZ_SYMMETRY_NONE:
44
      break;
45
149
    case IPUZ_SYMMETRY_ROTATIONAL_HALF:
46
149
      mirror_coord.row = puzzle_height - coord.row - 1;
47
149
      mirror_coord.column = puzzle_width - coord.column - 1;
48
149
      break;
49
307
    case IPUZ_SYMMETRY_ROTATIONAL_QUARTER:
50
      /* Nested switch statements. Fun! */
51
      switch (symmetry_offset)
52
        {
53
5
        case IPUZ_SYMMETRY_OFFSET_OPPOSITE:
54
5
          mirror_coord.row = puzzle_height - coord.row - 1;
55
5
          mirror_coord.column = puzzle_width - coord.column - 1;
56
5
          break;
57
151
        case IPUZ_SYMMETRY_OFFSET_CW_ADJACENT:
58
151
          mirror_coord.row = coord.column;
59
151
          mirror_coord.column = puzzle_width - coord.row - 1;
60
151
          break;
61
151
        case IPUZ_SYMMETRY_OFFSET_CCW_ADJACENT:
62
151
          mirror_coord.row = puzzle_height - coord.column - 1;
63
151
          mirror_coord.column = coord.row;
64
151
          break;
65
        default:
66
          g_assert_not_reached ();
67
        }
68
307
      break;
69
4
    case IPUZ_SYMMETRY_HORIZONTAL:
70
4
      mirror_coord.column = puzzle_width - coord.column - 1;
71
4
      break;
72
4
    case IPUZ_SYMMETRY_VERTICAL:
73
4
      mirror_coord.row = puzzle_height - coord.row - 1;
74
4
      break;
75
4
    case IPUZ_SYMMETRY_MIRRORED:
76
      switch (symmetry_offset)
77
        {
78
        case IPUZ_SYMMETRY_OFFSET_OPPOSITE:
79
          mirror_coord.row = puzzle_height - coord.row - 1;
80
          mirror_coord.column = puzzle_width - coord.column - 1;
81
          break;
82
2
        case IPUZ_SYMMETRY_OFFSET_CW_ADJACENT:
83
2
          mirror_coord.column = puzzle_width - coord.column - 1;
84
2
          break;
85
2
        case IPUZ_SYMMETRY_OFFSET_CCW_ADJACENT:
86
2
          mirror_coord.row = puzzle_height - coord.row - 1;
87
2
          break;
88
        default:
89
          g_assert_not_reached ();
90
        }
91
4
      break;
92
    default:
93
      g_assert_not_reached ();
94
    }
95

            
96
468
  return mirror_coord;
97
}