Browse Source

Passed: Whac-a-Mole

main^2
palmkeep 4 years ago
parent
commit
cb24f8f8fe
  1. 18
      whac-a-mole/Makefile
  2. 2
      whac-a-mole/a0
  3. 12
      whac-a-mole/d0
  4. 385
      whac-a-mole/main.cpp

18
whac-a-mole/Makefile

@ -0,0 +1,18 @@
EXE=whac-a-moler
CC=g++
CFLAGS=-g -O2 -std=gnu++17
LFLAGS=-lm
WFLAGS=-Wall -Wextra -Weffc++ -Wpedantic
OBJ=main.cpp
.PHONY: clean test
test: $(EXE)
./$(EXE)<d0 | diff --color=always a0 -
$(EXE): $(OBJ)
$(CC) $(CFLAGS) -o $@ -static $(OBJ) $(LFLAGS) $(WFLAGS)
clean:
rm -rf $(EXE)

2
whac-a-mole/a0

@ -0,0 +1,2 @@
4
2

12
whac-a-mole/d0

@ -0,0 +1,12 @@
4 2 6
0 0 1
3 1 3
0 1 2
0 2 2
1 0 2
2 0 2
5 4 3
0 0 1
1 2 1
2 4 1
0 0 0

385
whac-a-mole/main.cpp

@ -0,0 +1,385 @@
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <string>
using std::string;
#include <iostream>
using std::cout;
#include <vector>
using std::vector;
#include <algorithm>
void debug_indent(int lvl) {for (int i{0}; i < lvl; ++i) {cout << " ";}}
struct Mole
{
int x;
int y;
int t;
bool operator<(const Mole& other) {
return this->t > other.t;
}
};
struct Move
{
int x;
int y;
bool operator<(const Move& other) {
if ( (this->x < other.x) ||
(this->x == other.x && this->y < other.y)
) {
return true;
} else {
return false;
}
}
};
vector<Move> generate_moves(const int d)
{
vector<Move> moves;
for (int i{-d}; i <= d; ++i) {
for (int j{-d}; j <= d; ++j) {
if ( (i*i + j*j) <= d*d) {
moves.push_back( {i,j} );
}}}
return moves;
}
struct Matrix
{
bool *m;
size_t width;
int max_movement;
Matrix(
size_t _width,
int _max_movement) :
m(nullptr),
width(_width),
max_movement(_max_movement)
{
m = (bool*) malloc( (width*width) * sizeof(bool) );
for (size_t i{0}; i < width*width; ++i) {
*(m+i) = false;
}
};
~Matrix() {
delete m;
}
void set(int x, int y, bool val) {
size_t index = (x+max_movement)*width + (y+max_movement);
m[index] = val;
}
bool get(int x, int y) const {
size_t index = (x+max_movement)*width + (y+max_movement);
return m[index];
}
void reinit(
const int t,
vector<Mole>::const_iterator new_moles,
const vector<Mole>::const_iterator end_iter)
{
// Zero existing matrix
for (size_t i{0}; i < width*width; ++i) {
*(m+i) = false;
}
if (t != new_moles->t) { return; } // Exit after board clear if no moles are on board
int current_time = new_moles->t;
while (new_moles != end_iter && new_moles->t == current_time)
{
this->set(new_moles->x, new_moles->y, true);
++new_moles;
}
}
void print()
{
for (size_t j{0}; j < width; ++j) {
for (size_t i{0}; i < width; ++i) {
printf("(%2lu,%2lu)=%d ", i, j, *((m+i*width)+j));
}
puts("");
}
}
};
const int MAX_T = 10;
const int MAX_W = 20;
const int MAX_MV = 5;
struct Memo
{
int max_hits[MAX_T][MAX_W + 2*MAX_MV][MAX_W + 2*MAX_MV];
const int max_time;
const int board_width;
const int max_movement;
Memo(
int _max_time,
int _board_width,
int _max_movement) :
max_time(_max_time),
board_width(_board_width),
max_movement(_max_movement)
{
for (int i{0}; i < max_time; ++i) {
for (int j{0}; j < board_width+2*max_movement; ++j) {
for (int k{0}; k < board_width+2*max_movement; ++k) {
max_hits[i][j][k] = 0;
}
}
}
}
bool is_inside(int t, int x, int y) const {
bool inside = (1 <= t && t <= max_time);
inside &= (-max_movement <= x && x < board_width+max_movement);
inside &= (-max_movement <= y && y < board_width+max_movement);
return inside;
}
void set(int t, int x, int y, int val) {
assert( this->is_inside(t, x, y) );
max_hits[t-1][x+max_movement][y+max_movement] = val;
}
int get(int t, int x, int y) const {
assert( this->is_inside(t, x, y) );
return max_hits[t-1][x+max_movement][y+max_movement];
}
void print()
{
for (int i{0}; i < max_time; ++i) {
printf("T-%d:\n", i+1);
printf(" : ");
for(int k{0}; k < board_width+2*max_movement; ++k) {
printf("%3d|", k-max_movement);
}
puts("");
for (int j{0}; j < board_width+2*max_movement; ++j) {
printf("%3d: ", j-max_movement);
for (int k{0}; k < board_width+2*max_movement; ++k) {
printf("%3d ", max_hits[i][j][k]);
}
puts("\n");
}
puts("");
}
}
};
int max(int a, int b) {
return (a < b) ? b : a;
}
int max_hits_from_position(
const int t,
const int max_t,
const int x,
const int y,
const Memo& max_hits,
const Matrix& active_moles,
const vector<Move>& moves)
{
int current_max = 0;
for (const auto& move : moves)
{
int hits = 0;
const int new_x = x + move.x;
const int new_y = y + move.y;
if ( !max_hits.is_inside(t, new_x, new_y) ) {
continue; // Check new move if current moves whac way off board
}
// Check current pos
if ( active_moles.get(x, y) ) {
++hits;
}
if ( !(move.x == 0 && move.y == 0) )
{
// Yes I know, it is lazy
if ( (move.x%4 == 0 && move.y == 0) ||
(move.y%4 == 0 && move.x == 0))
{
const int it_x = (move.x/4);
const int it_y = (move.y/4);
if ( active_moles.get( (x + 1*it_x), (y + 1*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 2*it_x), (y + 2*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 3*it_x), (y + 3*it_y) ) ) {
++hits;
}
}
else if (move.x%2 == 0 && move.y%2 == 0)
{
const int it_x = (move.x/2);
const int it_y = (move.y/2);
if ( active_moles.get( (x + 1*it_x), (y + 1*it_y) ) ) {
++hits;
}
}
else if (move.x%3 == 0 && move.y%3 == 0)
{
const int it_x = (move.x/3);
const int it_y = (move.y/3);
if ( active_moles.get( (x + 1*it_x), (y + 1*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 2*it_x), (y + 2*it_y) ) ) {
++hits;
}
}
else if ( (move.x%5 == 0 && move.y == 0) ||
(move.y%5 == 0 && move.x == 0))
{
const int it_x = (move.x/5);
const int it_y = (move.y/5);
if ( active_moles.get( (x + 1*it_x), (y + 1*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 2*it_x), (y + 2*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 3*it_x), (y + 3*it_y) ) ) {
++hits;
}
if ( active_moles.get( (x + 4*it_x), (y + 4*it_y) ) ) {
++hits;
}
}
// Check pos at end of line: new_x and new_y
if ( active_moles.get(new_x, new_y) ) {
++hits;
}
}
// Add destination if not at last timestep
if (t < max_t) {
hits += max_hits.get(t+1, new_x, new_y);
}
current_max = max(hits, current_max);
}
return current_max;
}
void test_case(
const int n, // Width of board
const int d, // Max distance of a move
const int n_moles)
{
int b_width = n + 2*d;
Matrix active_moles(b_width, d);
vector<Mole> moles;
{
int x, y, t;
for (int i{0}; i < n_moles; ++i) {
scanf("%d %d %d\n", &x, &y, &t);
moles.push_back( {x, y, t} );
}
}
std::sort(moles.begin(), moles.end());
int timestamp_last_mole = moles.begin()->t;
Memo max_hits(timestamp_last_mole, n, d);
// Generate all valid moves for this test case
vector<Move> moves = generate_moves(d);
// Iterator to beginning of sequence of moles for the current timestamp
vector<Mole>::const_iterator current_moles = moles.begin();
int first_t = 1;
for (int t{timestamp_last_mole}; 1 <= t; --t)
{
// Iterate to moles on this timestep or earlier one (backwards iteration through time)
while ( (current_moles != moles.end()) &&
(current_moles->t) > t)
{
++current_moles;
}
// Break out early if mole list is emptied
if (current_moles == moles.end())
{
first_t = t+1;
break;
}
// Re-initialize active_moles: zero and set new moles
active_moles.reinit(t, current_moles, moles.end());
// 2D iteration over all possible start positions in (and outside) the board
for (int i{-d}; i < n+d; ++i) {
for (int j{-d}; j < n+d; ++j) {
int max_val = max_hits_from_position(
t, timestamp_last_mole,
i, j,
max_hits,
active_moles,
moves);
max_hits.set(t, i, j, max_val);
}
}
}
int max_val = 0;
for (int i{-d}; i < n+d; ++i) {
for (int j{-d}; j < n+d; ++j) {
int val = max_hits.get(first_t, i, j);
if (max_val < val) {
max_val = val;
}
}
}
printf("%d\n", max_val);
}
int main()
{
int n, d, m;
while(1)
{
scanf("%d %d %d\n", &n, &d, &m);
if (n+d+m == 0) { break; } // All zeroes (no negative values in file)
test_case(n, d, m);
}
}
Loading…
Cancel
Save