1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
//-----------------------------------------------------------------------------
/** @file libpentobi_base/PieceInfo.cpp
@author Markus Enzenberger
@copyright GNU General Public License version 3 or later */
//-----------------------------------------------------------------------------
#include "PieceInfo.h"
#include <algorithm>
#include "libboardgame_base/GeometryUtil.h"
#include "libboardgame_base/Log.h"
namespace libpentobi_base {
//-----------------------------------------------------------------------------
namespace {
const bool log_piece_creation = false;
struct NormalizedPoints
{
/** The normalized points of the transformed piece.
The points were shifted using GeometryUtil::normalize_offset(). */
PiecePoints points;
/** The point type of (0,0) in the normalized points. */
unsigned point_type;
bool operator==(const NormalizedPoints& n) const
{
return points == n.points && point_type == n.point_type;
}
};
#ifdef LIBBOARDGAME_DEBUG
/** Check consistency of transformations.
Checks that the point list (which must be already sorted) has no
duplicates. */
bool check_consistency(const PiecePoints& points)
{
for (unsigned i = 0; i < points.size(); ++i)
if (i > 0 && points[i] == points[i - 1])
return false;
return true;
}
#endif // LIBBOARDGAME_DEBUG
/** Bring piece points into a normal form that is constant under translation. */
NormalizedPoints normalize(const PiecePoints& points, unsigned point_type,
const Geometry& geo)
{
if (log_piece_creation)
LIBBOARDGAME_LOG("Points ", points);
NormalizedPoints normalized;
normalized.points = points;
type_match_shift(geo, normalized.points.begin(),
normalized.points.end(), point_type);
if (log_piece_creation)
LIBBOARDGAME_LOG("Point type ", point_type, ", type match shift ",
normalized.points);
// Make the coordinates positive and minimal
unsigned width; // unused
unsigned height; // unused
CoordPoint offset;
normalize_offset(normalized.points.begin(), normalized.points.end(),
width, height, offset);
normalized.point_type = geo.get_point_type(offset);
// Sort the coordinates
sort(normalized.points.begin(), normalized.points.end());
return normalized;
}
} // namespace
//-----------------------------------------------------------------------------
PieceInfo::PieceInfo(const string& name, const PiecePoints& points,
const Geometry& geo, const PieceTransforms& transforms,
GeometryType geometry_type, CoordPoint label_pos,
unsigned nu_instances)
: m_nu_instances(nu_instances),
m_points(points),
m_label_pos(label_pos),
m_name(name)
{
LIBBOARDGAME_ASSERT(nu_instances > 0);
LIBBOARDGAME_ASSERT(nu_instances <= PieceInfo::max_instances);
if (log_piece_creation)
LIBBOARDGAME_LOG("Creating transformations for piece ", name, ' ',
points);
auto& all_transforms = transforms.get_all();
vector<NormalizedPoints> all_transformed_points;
all_transformed_points.reserve(all_transforms.size());
m_transforms.reserve(all_transforms.size()); // Upper limit
PiecePoints transformed_points;
for (auto transform : all_transforms)
{
if (log_piece_creation)
LIBBOARDGAME_LOG("Transformation ", get_type_name(*transform));
transformed_points = points;
transform->transform(transformed_points.begin(),
transformed_points.end());
NormalizedPoints normalized = normalize(transformed_points,
transform->get_point_type(),
geo);
if (log_piece_creation)
LIBBOARDGAME_LOG("Normalized ", normalized.points, " point type ",
normalized.point_type);
LIBBOARDGAME_ASSERT(check_consistency(normalized.points));
auto begin = all_transformed_points.begin();
auto end = all_transformed_points.end();
auto pos = find(begin, end, normalized);
if (pos != end)
{
if (log_piece_creation)
LIBBOARDGAME_LOG("Equivalent to ", pos - begin);
m_equivalent_transform[transform]
= transforms.get_all()[pos - begin];
}
else
{
if (log_piece_creation)
LIBBOARDGAME_LOG("New (", m_transforms.size(), ")");
m_equivalent_transform[transform] = transform;
m_transforms.push_back(transform);
}
all_transformed_points.push_back(normalized);
}
if (geometry_type == GeometryType::nexos)
{
m_score_points = 0;
for (auto& p : points)
{
auto point_type = geo.get_point_type(p);
LIBBOARDGAME_ASSERT(point_type <= 2);
if (point_type == 1 || point_type == 2) // Line segment
++m_score_points;
}
}
else if (geometry_type == GeometryType::gembloq)
m_score_points = 0.25f * static_cast<ScoreType>(points.size());
else if (points.size() == 1 && geometry_type == GeometryType::callisto)
m_score_points = 0;
else
m_score_points = static_cast<ScoreType>(points.size());
}
const Transform* PieceInfo::find_transform(const Geometry& geo,
const Points& points) const
{
NormalizedPoints normalized =
normalize(points, geo.get_point_type(0, 0), geo);
for (const Transform* transform : get_transforms())
{
Points piece_points = get_points();
transform->transform(piece_points.begin(), piece_points.end());
NormalizedPoints normalized_piece =
normalize(piece_points, transform->get_point_type(), geo);
if (normalized_piece == normalized)
return transform;
}
return nullptr;
}
const Transform* PieceInfo::get_equivalent_transform(
const Transform* transform) const
{
auto pos = m_equivalent_transform.find(transform);
LIBBOARDGAME_ASSERT(pos != m_equivalent_transform.end());
return pos->second;
}
const Transform* PieceInfo::get_next_transform(const Transform* transform) const
{
transform = get_equivalent_transform(transform);
auto begin = m_transforms.begin();
auto end = m_transforms.end();
auto pos = find(begin, end, transform);
LIBBOARDGAME_ASSERT(pos != end);
if (pos + 1 == end)
return *begin;
return *(pos + 1);
}
const Transform* PieceInfo::get_previous_transform(
const Transform* transform) const
{
transform = get_equivalent_transform(transform);
auto begin = m_transforms.begin();
auto end = m_transforms.end();
auto pos = find(begin, end, transform);
LIBBOARDGAME_ASSERT(pos != end);
if (pos == begin)
return *(end - 1);
return *(pos - 1);
}
//-----------------------------------------------------------------------------
} // namespace libpentobi_base
|