#include "jsmn.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <set>
#include <vector>
#include <cassert>

using std::vector;

// Parsování JSONu

static int jsoneq(const char *json, jsmntok_t *tok, const char *s) {
  if (tok->type == JSMN_STRING && (int)strlen(s) == tok->end - tok->start &&
      strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
    return 0;
  }
  return -1;
}

// Třídy reprezentující hru

enum Direction
{
	STAY = -1,
	UP = 0,
	LEFT = 1,
	DOWN = 2,
	RIGHT = 3,
};

struct Team;
struct Member;
struct Field;

struct Team
{
	int id;
	bool is_me;
	Field* home;
	vector<Field*> occupied;
	vector<Field*> protected_fields;
	vector<Member*> members;
	Team(int _id, bool _is_me)
	{
		id = id;
		is_me = _is_me;
	}
};

struct Member
{
	Field * field;
	Team * team;
	int id;
	Direction action = STAY;
	Member(Field *_field)
	{
		field = _field;
	}
};

struct Field
{
	int i,j;
	bool hill;
	Team* home_for_team = NULL;
	Team* occupied_by_team = NULL;
	Team* protected_for_team = NULL;
	vector<Member*> members;
	Field(int _i, int _j)
	{
		i = _i;
		j = _j;
	}
};

// Celý stav hry včetně parsování a vypisování
struct State
{
	// Dealokace paměti není implementována, protože předpokládáme, že program
	// poběží jen krátce a po ukončení všechna paměť automaticky zanikne.
	vector<Team*> teams;
	vector<vector<Field*>> world;
	Team * my_team;
	int round_number;
	int time_to_response;

	int js_skip(jsmntok_t* t, int i)
	{
		int s = t[i].size;
		i++;
		for(int j=0; j<s; j++)
			i = js_skip(t, i);
		return i;
	}

	State(char * input_str)
	{
		// Ano, vím, že je to ošklivé, ale prostě parsovat JSON v C/C++ je za trest
		int r;
		jsmn_parser p;
		int t_len = 100000000;
		jsmntok_t * t = new jsmntok_t[t_len]; /* We expect no more than this count of tokens (jsmn limitation)*/

		jsmn_init(&p);
		r = jsmn_parse(&p, input_str, strlen(input_str), t, t_len);
		assert(!(r < 0));

		assert(!(r < 1 || t[0].type != JSMN_OBJECT));

		int teams_count, team_id;
		int state_tok, world_tok;
		for (int i = 1, c=0; c < t[0].size;i = js_skip(t, i), c++)
		{
			//printf("- %.*s %d\n", t[i].end - t[i].start, input_str + t[i].start, t[i].size);

			if (jsoneq(input_str, &t[i], "teams_count") == 0)
				teams_count = atoi(input_str + t[i+1].start);
			if (jsoneq(input_str, &t[i], "team_id") == 0)
				team_id = atoi(input_str + t[i+1].start);
			if (jsoneq(input_str, &t[i], "time_to_response") == 0)
				time_to_response = atoi(input_str + t[i+1].start);
			if (jsoneq(input_str, &t[i], "round_number") == 0)
				round_number = atoi(input_str + t[i+1].start);
			if (jsoneq(input_str, &t[i], "state") == 0)
				state_tok = i+1;
			;
		}
		assert(state_tok);
		for(int i=0; i<teams_count; i++)
			teams.push_back(new Team(i, i==team_id));
		my_team = teams[team_id];
		for (int i = state_tok+1, c=0; c < t[state_tok].size;i = js_skip(t, i), c++)
		{
			if (jsoneq(input_str, &t[i], "world") == 0)
				world_tok = i+1;
			;
		}
		assert(world_tok);
		for (int i = world_tok+1, x=0; x < t[world_tok].size;i = js_skip(t, i), x++)
		{
			vector<Field *> current_row;
			for (int j = i+1, y=0; y < t[i].size;j = js_skip(t, j), y++)
			{
				Field *current_field = new Field(x,y);
				int members_tok;
				for (int k = j+1, c=0; c < t[j].size;k = js_skip(t, k), c++)
				{
					if (jsoneq(input_str, &t[k], "hill") == 0)
						current_field->hill = input_str[t[k+1].start] == 't';
					if (jsoneq(input_str, &t[k], "home_for_team") == 0)
						if(input_str[t[k+1].start] != 'n')
						{
							current_field->home_for_team = teams[atoi(input_str+t[k+1].start)];
							current_field->home_for_team->home = current_field;
						}
					if (jsoneq(input_str, &t[k], "occupied_by_team") == 0)
						if(input_str[t[k+1].start] != 'n')
						{
							current_field->occupied_by_team = teams[atoi(input_str+t[k+1].start)];
							current_field->occupied_by_team->occupied.push_back(current_field);
						}

					if (jsoneq(input_str, &t[k], "protected_for_team") == 0)
						if(input_str[t[k+1].start] != 'n')
						{
							current_field->protected_for_team = teams[atoi(input_str+t[k+1].start)];
							current_field->protected_for_team->protected_fields.push_back(current_field);
						}
					if (jsoneq(input_str, &t[k], "members") == 0)
						members_tok = k+1;
				}
				for (int k = members_tok+1, c=0; c < t[members_tok].size;k = js_skip(t, k), c++)
				{
					auto m = new Member(current_field);
					for (int l = k+1, d=0; d < t[k].size;l = js_skip(t, l), d++)
					{
						// printf("%d %d: %.*s %d\n", x,y, t[l].end - t[l].start, input_str + t[l].start, t[l].size);
						if (jsoneq(input_str, &t[l], "id") == 0)
							m->id = atoi(input_str + t[l+1].start);
						if (jsoneq(input_str, &t[l], "team") == 0)
							m->team = teams[atoi(input_str+t[l+1].start)];
					}
					m->team->members.push_back(m);
					current_field->members.push_back(m);
				}
				current_row.push_back(current_field);
			}
			world.push_back(current_row);
		}
	}

	void print_turn()
	{
		for(Team *t: teams)
			if(!t->is_me)
				for(Member *m: t->members)
					if(m->action != STAY)
					{
						fprintf(stderr, "Voják cizího týmu má přiřazenou akci.");
						exit(1);
					}
		bool first = true;
		printf("{\"members\": [");
		for(Member *m: my_team->members)
		{
			if(!first) printf(", ");
			const char * action = "stay";
			if(m->action == UP) action = "up";
			if(m->action == LEFT) action = "left";
			if(m->action == DOWN) action = "down";
			if(m->action == RIGHT) action = "right";
			printf("{\"id\": %d, \"action\": \"%s\"}", m->id, action);
			first = false;
		}
		printf("]}");
	}
};

State* state;



// Algoritmy

// modulení jako v Pythonu
int py_mod(int a, int b)
{
	return (a % b + b) % b;
}

// otoč směr podle jiného otočení
Direction combine_directions(Direction a, Direction b)
{
	if (a == STAY || b == STAY)
	{
		fprintf(stderr, "Nelze kombinovat se STAY.");
		exit(1);
	}
	return (Direction) ((a + b) % 4);
}

// získej opačný směr
Direction invert_direction(Direction a)
{
	if (a == STAY) return STAY;
	return combine_directions(a, DOWN);
}

// další políčko v daném směru
Field* get_neighbour_field(Field* f, Direction direction)
{
	int neighbour_i = f->i;
	int neighbour_j = f->j;
	switch (direction)
	{
		case UP:
			neighbour_i = f->i - 1;
			break;
		case DOWN:
			neighbour_i = f->i + 1;
			break;
		case LEFT:
			neighbour_j = f->j - 1;
			break;
		case RIGHT:
			neighbour_j = f->j + 1;
			break;
	}

	// zajisti, aby souřadnice byly v rozsahu herní plochy
	neighbour_i = py_mod(neighbour_i, state->world.size());
	neighbour_j = py_mod(neighbour_j, state->world[0].size());
	return state->world[neighbour_i][neighbour_j];
}

// jestli daný tým může vstoupit na políčko
bool is_field_accessible(Field* f, Team* t)
{
	if (f->hill) return false;
	if (f->protected_for_team != NULL && f->protected_for_team != t) return false;
	return true;
}

// Najdi nejkratší cestu od vojáka k cílovému políčku.
// Vrátí první krok, který má voják udělat.
// Pokud žádná cesta neexistuje, vrátí STAY.
Direction pathfind(Member* m, Field* goal)
{
	// speciální případ: voják už je v cíli
    if (m->field == goal) return STAY;

	std::set<Field*> explored;
	std::queue<Field*> queue;
	queue.push(goal);
	auto dirs = {UP, LEFT, DOWN, RIGHT};
	while (!queue.empty())
	{
		auto field = queue.front();
		queue.pop();
		for (auto direction : dirs)
		{
			auto neighbour = get_neighbour_field(field, direction);
			if (explored.find(neighbour) != explored.end()) continue;
			if (!is_field_accessible(neighbour, m->team)) continue;
            // pokud jsme našli vojáka, vrátíme první krok
			if (neighbour == m->field) return invert_direction(direction);
			queue.push(neighbour);
			explored.insert(neighbour);
		}
	}
	return STAY;
}

// Strategie

int main()
{
	char * input_str;
	scanf("%m[^\n]", &input_str);
	state = new State(input_str);

	// TODO: zde doplňte svou herní strategii
	for(Member *m: state->my_team->members)
		m->action = UP;

	state->print_turn();
	return 0;
}