1 /*
2 	SPDX-FileCopyrightText: 2009-2014 Graeme Gott <graeme@gottcode.org>
3 
4 	SPDX-License-Identifier: GPL-3.0-or-later
5 */
6 
7 #ifndef PEGE_PUZZLE_H
8 #define PEGE_PUZZLE_H
9 
10 #include <QHash>
11 #include <QPoint>
12 #include <QSize>
13 
14 #include <random>
15 
16 /**
17  * Contains the layout of holes and pegs.
18  *
19  * This class generates and contains a board layout. When it generates a
20  * layout it tracks which holes are the furthest left and up, right and down
21  * so that the size of the layout can be quickly retrieved.
22  */
23 class Puzzle
24 {
25 public:
26 	/** Constructs an empty layout. */
27 	explicit Puzzle();
28 
29 	/** Destroys the layout. */
30 	virtual ~Puzzle();
31 
32 	/** Returns the layout as a hash of points describing the holes. */
33 	QHash<QPoint, bool> holes() const;
34 
35 	/** Returns the top left corner of the layout. */
36 	QPoint position() const;
37 
38 	/** Returns the size of the layout. */
39 	QSize size() const;
40 
41 	/**
42 	 * Creates a layout.
43 	 *
44 	 * @param seed the seed passed to the random number generator
45 	 * @param difficulty how hard of a layout to create
46 	 */
47 	void generate(int seed, int difficulty);
48 
49 protected:
50 	/**
51 	 * Creates a layout with a single group of pegs.
52 	 *
53 	 * @param pegs how many pegs to create
54 	 */
55 	virtual void generate(int pegs);
56 
57 	/**
58 	 * Returns @c true if @p hole has no peg.
59 	 *
60 	 * @param hole the hole to check
61 	 */
62 	virtual bool isAvailable(const QPoint& hole) const;
63 
64 	/**
65 	 * Randomly shuffles a list of pegs.
66 	 *
67 	 * @param pegs the pegs to shuffle
68 	 */
69 	virtual void shuffle(QList<QPoint>& pegs);
70 
71 	/**
72 	 * Determines where to move next.
73 	 *
74 	 * @param start_hole the hole that is moved from
75 	 * @param jumped_hole the hole between the start and end holes
76 	 * @param end_hole the hole that is moved to
77 	 */
78 	bool findNextMove(const QPoint& start_hole, QPoint& jumped_hole, QPoint& end_hole);
79 
80 	/**
81 	 * Creates a group of pegs.
82 	 *
83 	 * @param start initial peg
84 	 * @param loops how many pegs to create
85 	 */
86 	QPoint findMoves(const QPoint& start, int loops);
87 
88 	/**
89 	 * Returns whether or not the @p hole has a peg.
90 	 *
91 	 * @param hole the hole to check
92 	 * @return @li @c 0 if the hole is empty
93 	 *         @li @c 1 if the hole has a peg
94 	 *         @li @c -1 if the hole doesn't exist
95 	 */
96 	int hasPeg(const QPoint& hole) const;
97 
98 	/**
99 	 * Sets if the @p hole has a peg.
100 	 *
101 	 * @param hole the hole to specify
102 	 * @param value what to put at the hole
103 	 */
104 	void setHasPeg(const QPoint& hole, bool value);
105 
106 private:
107 	QHash<QPoint, bool> m_holes; /**< hash of holes */
108 	QList<QPoint> m_directions; /**< list of directions to check */
109 	QPoint m_top_left; /**< top left hole */
110 	QPoint m_bottom_right; /**< bottom right hole */
111 	std::mt19937 m_random; /**< random number generator */
112 };
113 
114 /** Puzzle that has branches between groups of pegs. */
115 class PuzzleBranch : public Puzzle
116 {
117 protected:
118 	/**
119 	 * Creates a layout with branches between the groups.
120 	 *
121 	 * @param pegs how many pegs to create
122 	 */
123 	void generate(int pegs) override;
124 };
125 
126 /** Puzzle that doesn't reuse or shuffle any holes. */
127 class PuzzleLine : public Puzzle
128 {
129 protected:
130 	/**
131 	 * Returns true if @p hole does not exist yet.
132 	 *
133 	 * @param hole the hole to check
134 	 */
135 	bool isAvailable(const QPoint& hole) const override;
136 
137 	/**
138 	 * Override parent function to prevent shuffling the pegs.
139 	 *
140 	 * @param pegs the pegs to shuffle
141 	 */
142 	void shuffle(QList<QPoint>& pegs) override;
143 };
144 
145 #endif // PEGE_PUZZLE_H
146