-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpizza_cutter.cpp
154 lines (126 loc) · 4.48 KB
/
pizza_cutter.cpp
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
#include "pizza_cutter.h"
#include <iostream>
std::ostream& operator<<(std::ostream& os, pizza_slice ps) noexcept
{
os << ps.row1 << ' ' << ps.col1 << ' ' << ps.row2 << ' ' << ps.col2;
return os;
}
std::vector<pizza_slice> pizza_cutter::solve() noexcept
{
try_to_create_slices_for_each_point();
for (int i = 0; i < 4; ++i)
try_to_extend_all_slices();
return std::move(slices_);
}
void pizza_cutter::try_to_create_slices_for_each_point() noexcept
{
for (int row = 0; row < pizza_.size(); row++) {
for (int col = 0; col < pizza_[0].size(); col++) {
auto slice = create_slice_for(row, col);
if (!slice) continue;
int next_slice_id = slices_.size();
mark_slice(slice.value(), next_slice_id);
slices_.push_back(slice.value());
}
}
}
std::optional<pizza_slice> pizza_cutter::extend_slice(pizza_slice ps, direction dir) const noexcept
{
switch(dir) {
case direction::right:
if (is_new_part_valid(pizza_slice{ps.row1, ps.col2 + 1, ps.row2, ps.col2 + 1}))
return pizza_slice{ps.row1, ps.col1, ps.row2, ps.col2 + 1};
break;
case direction::down:
if (is_new_part_valid(pizza_slice{ps.row2 + 1, ps.col1, ps.row2 + 1, ps.col2}))
return pizza_slice{ps.row1, ps.col1, ps.row2 + 1, ps.col2};
break;
case direction::left:
if (is_new_part_valid(pizza_slice{ps.row1, ps.col1 - 1, ps.row2, ps.col1 - 1}))
return pizza_slice{ps.row1, ps.col1 - 1, ps.row2, ps.col2};
break;
case direction::up:
if (is_new_part_valid(pizza_slice{ps.row1 - 1, ps.col1, ps.row1 - 1, ps.col2}))
return pizza_slice{ps.row1 - 1, ps.col1, ps.row2, ps.col2};
break;
}
return std::nullopt;
}
bool pizza_cutter::is_new_part_valid(pizza_slice new_part) const noexcept
{
if (new_part.col1 < 0 || new_part.col2 >= pizza_[0].size() ||
new_part.row1 < 0 || new_part.row2 >= pizza_.size()) {
return false;
}
for (int row = new_part.row1; row <= new_part.row2; ++row) {
for (int col = new_part.col1; col <= new_part.col2; ++col) {
if (pizza_[row][col].owner != -1)
return false;
}
}
return true;
}
std::optional<pizza_slice> pizza_cutter::create_slice_for(int row, int col) const noexcept
{
if (pizza_[row][col].owner != -1) return std::nullopt;
pizza_slice slice{row, col, row, col};
bool look_for_next = true;
while (look_for_next) {
bool could_be_extended = false;
bool all_is_too_large = true;
pizza_slice candidate;
for (auto d : directions) {
auto new_slice = extend_slice(slice, d);
if (new_slice) {
could_be_extended = true;
auto [mushrooms, tomatoes] = count_ingredients(new_slice.value());
if (is_too_large(mushrooms, tomatoes))
continue;
all_is_too_large = false;
if (is_minimum_ingredients(mushrooms, tomatoes))
return new_slice;
candidate = new_slice.value();
}
}
slice = candidate;
look_for_next = could_be_extended && !all_is_too_large;
}
return std::nullopt;
}
void pizza_cutter::mark_slice(pizza_slice ps, int slice_id) noexcept
{
for (int row = ps.row1; row <= ps.row2; ++row) {
for (int col = ps.col1; col <= ps.col2; ++col) {
pizza_[row][col].owner = slice_id;
}
}
}
std::tuple<int,int> pizza_cutter::count_ingredients(pizza_slice ps) const noexcept
{
int mushrooms = 0;
int tomatoes = 0;
for (int row = ps.row1; row <= ps.row2; ++row) {
for (int col = ps.col1; col <= ps.col2; ++col) {
if (pizza_[row][col].ingr == 'M') {
++mushrooms;
} else {
++tomatoes;
}
}
}
return std::tie(mushrooms, tomatoes);
}
void pizza_cutter::try_to_extend_all_slices() noexcept
{
for (int i = 0; i < slices_.size(); ++i) {
for (auto d : directions) {
auto new_slice = extend_slice(slices_[i], d);
if (!new_slice) continue;
auto [mushrooms, tomatoes] = count_ingredients(new_slice.value());
if (is_too_large(mushrooms, tomatoes))
continue;
mark_slice(new_slice.value(), i);
slices_[i] = new_slice.value();
}
}
}