Board adj_enemy_le(const GameState& gs, const uint8_t for_color, const unsigned int direction)
{
  Board adj_le, enemy_le, these_pieces;
  const Board& color_board = gs.get_color_board(for_color);
  const Board& enemy_color = gs.get_color_board(other_color(for_color));
  for(int p = R; p < nPieces; ++p) {
    enemy_le |= gs.get_piece_board(p) & enemy_color;
    these_pieces = gs.get_piece_board(p) & color_board;
    adj_le |= is_adjacent(these_pieces, enemy_le, direction);
  }
  return adj_le;
}
Board adj_enemy_gt(const GameState& gs, const uint8_t for_color, const unsigned int direction)
{
  Board adj_gt, enemy_gt, these_pieces;
  const Board& color_board = gs.get_color_board(for_color);
  const Board& enemy_color = gs.get_color_board(other_color(for_color));
  for(int p = E; p >= R; --p) {
    these_pieces = gs.get_piece_board(p) & color_board;
    adj_gt |= is_adjacent(these_pieces, enemy_gt, direction);
    enemy_gt |= gs.get_piece_board(p) & enemy_color;
  }
  return adj_gt;
}
void generate_pushes(const GameState& gs, std::vector<Delta> *pushes)
{
  const uint8_t pushing_color = gs.get_color();
  const uint8_t pushed_color = other_color(gs.get_color());
  const Board& pushing_mobile = ~frozen_pieces(gs, gs.get_color());

  Board pushed_with_adj_empty[4];

  // The body of generate_pushes() takes the perspective of the pushed piece.  
  // dir_pushed_from is the direction from which the pushing piece comes from.
  // dir_pushed is the direction the pushed piece is pushed to.

  for (unsigned int dir = NORTH; dir < num_directions(); ++dir) {
    pushed_with_adj_empty[dir] = adj_empty(gs, pushed_color, dir);
  }

  for (unsigned int dir_pushed_from = NORTH; dir_pushed_from < num_directions(); ++dir_pushed_from) {

    // the mobile pushing pieces with an adjacent weaker piece.
    // We use the opp_dir(dir_pushed_from) here since we are talking about the pushing piece.
    const Board& pushing_pieces_with_adj_lt = 
      adj_enemy_lt(gs, pushing_color, opp_dir(dir_pushed_from)) & pushing_mobile;

    for (unsigned int dir_pushed = NORTH; dir_pushed < num_directions(); ++dir_pushed) {
      if (dir_pushed_from == dir_pushed) continue;

      // TODO: Try and make symmetric with generate_pulls() -- simplify inner loop here...
      Board pushing_pieces = 
        is_adjacent(pushing_pieces_with_adj_lt, pushed_with_adj_empty[dir_pushed],
            opp_dir(dir_pushed_from));

      Board pushed_pieces = 
        is_adjacent(pushed_with_adj_empty[dir_pushed], pushing_pieces_with_adj_lt, dir_pushed_from);

      while(!pushed_pieces.is_empty()) {
        assert(!pushing_pieces.is_empty());
        uint8_t pushed_idx = pushed_pieces.idx_and_reset();
        uint8_t pusher_idx = pushing_pieces.idx_and_reset();
        assert(gs.get_all_const().contains(pushed_idx));
        assert(gs.get_all_const().contains(pusher_idx));
        pushes->push_back(Delta(step_from_gs(gs, pushed_idx, dir_pushed),
              step_from_gs(gs, pusher_idx, opp_dir(dir_pushed_from))));
      }
    }
  }
}
TEST_F(avl_tree, DISABLED_generate_index_data)
{
	recreate_dirs();

	isolution_tree_base_ptr db(new bin_index_solution_base_t(index_dir));
	solution_tree_t tr(db);
	tr.init(index_dir);

	std::string str("(-1,0:O);(-1,1:X);(-1,2:X);(0,0:X);(0,1:X);(0,2:O);(1,1:O);(1,2:X);(2,2:O)");
    steps_t steps;
    hex_or_str2points(str,steps);
//	tr.create_init_tree(steps);

	WsPlayer::stored_deep=1;
	WsPlayer::def_lookup_deep=0;
	WsPlayer::treat_deep=0;
	WsPlayer::ant_count=0;

	size_t key_size=0;

	std::string file_name;
	file_access_ptr fi;
	file_access_ptr fd;

	ObjectProgress::log_generator lg(true);
	ObjectProgress::perfomance perf;

	for(int i=0;i<1000000;i++)
	{
		steps_t key;
        if(!tr.get_job(key))
		{
			printf("no job anymore\n");
			break;
		}

		reorder_state_to_game_order(key);

		game_t gm;
		gm.field().set_steps(key);

		WsPlayer::wsplayer_t pl;

		pl.init(gm,other_color(key.back().step));
		pl.solve();

		const WsPlayer::wide_item_t& r=static_cast<const WsPlayer::wide_item_t&>(*pl.root);

		points_t neitrals;
		items2points(r.get_neitrals(),neitrals);

		npoints_t wins;
		items2depth_npoints(r.get_wins().get_vals(),wins);

		npoints_t fails;
		items2depth_npoints(r.get_fails().get_vals(),fails);

		tr.save_job(key,neitrals,wins,fails);


		if(key_size!=key.size())
		{
			file_name=std::string(index_dir)+"/"+boost::lexical_cast<std::string>(key.size());
			fi=file_access_ptr(new paged_file_t(file_name+".idx") );
			fd=file_access_ptr(new paged_file_t(file_name+".data") );
			key_size=key.size();
			lg<<i<<": key_size="<<key.size();
		}

		sol_state_t st;
		st.key=key;
		st.neitrals=neitrals;
		st.solved_wins=wins;
		st.solved_fails=fails;
		
		steps_t sorted_key=key;
		sort_steps(sorted_key);
		data_t bin_key;
		Gomoku::points2bin(sorted_key,bin_key);
		
		data_t st_bin;
		st.pack(st_bin);

		fi->append(bin_key);

		data_t st_bin_size(sizeof(size_t));
		*reinterpret_cast<size_t*>(&st_bin_size.front())=st_bin.size();
		fd->append(st_bin_size);
		fd->append(st_bin);

		static const int perf_mod=10000;
		if((i!=0)&&(i%perf_mod)==0)
		{
			ObjectProgress::perfomance::val_t v=perf.delay();
			lg<<i<<": perf="<<(v/1000.0)<<"ms   rate="<<(1.0*perf_mod/v*1000000.0)<<" kps";
			perf.reset();
		}
	}

}