До того как встретил эту статью, не знал что есть форыч через YSI.
Вид для печати
Мне кажется или этот код не совсем рабочий? По крайней мере в том виде, в котором он имеется сейчас.
Возможно, в первоисточнике, откуда взят этот пример, формула в MAX_PLAYERS_IN_TEAM не такая странная для макроса, что указывается в качестве размера итератора, но сейчас она немножко бредовая
Да и вообще смысла от этого макроса нет, ибо нормально итератор будет работать только в таком виде:
PHP код:
new
Iterator:Team[MAX_TEAMS]<MAX_PLAYERS>;
Ну представим, что MAX_PLAYERS не изменялось и равно 1000. Следовательно, в макросе MAX_PLAYERS_IN_TEAM будет записано "1000/255", что равно, примерно, 4, хотя компилятор округлит до 3-х, скорее всего (разницы особой нет). Следовательно, размер итератора тоже будет равен трём:
Что означает, что в него нельзя будет записать число больше двух (ибо алгоритм таков).PHP код:
new
Iterator:Team[MAX_TEAMS]<3>;
То бишь, в этих итераторах будут записаны исключительно игроки с 0 по 2-ой ID и никто более.
Не думаю, что изначально именно такая была задумка.PHP код:
Iter_Add(Team[0], 4);//Уже не запишет
Сам когда-то погорел на этом, долго не понимая почему не записывает в итератор мои значения :) Пока наконец не переборол упрямство вперемешку с желанием разобраться самостоятельно и не нашёл статью на sa-mp.com об итераторах, которую выше кидал.
Если кто не понял почему так происходит, то вот объяснение:
Совсем забыл изначальную цель, ради которой я заглядывал в тему пару дней назад :D
Я бы ещё отдельно акцентировал внимание на том, что итераторы станут хорошей заменой всех массивов, значение которых впоследствии проверяется в цикле (особенно массивов, значение которых бывает равно только нулю и единице и массивов MAX_PLAYERS). У итераторов в этом плане сразу несколько плюсов, при том, что и возможности массива не теряются: и возможность "пробежаться" по нужным данными без дополнительных проверок, и узнать количество данных без дополнительных переменных или подсчёта в цикле (Iter_Count), не говоря уже о возможности получения случайного члена этих данных (Iter_Random).
А то для многих интеграция foreach в SA-MP заканчивается чем-то подобным:
хотя разумнее создать итераторPHP код:
foreach(new i: Player)
{
if(IsPlayerAdmin)
//...
}
Кстати говоря, вот это ограничение:
можно обойти. Правда, в некоторых случаях, придётся потратить немного больше памяти. Суть вот в чём.
Нужно создать обыкновенный массив с нужным нам количеством ячеек и итератор с таким же количеством.
Итератор не будет хранить каких-либо значений, кроме занятых индексов в основном массиве.
Проще показать на примере кода:
PHP код:
new test_array[MAX_PLAYERS],// Наш массив, который будет хранить нужные нам значения (ограничено лишь cellmin/cellmax)
Iterator:TestIter<sizeof(test_array)>; // Итератор с тем же числом ячеек, который будет хранить ID занятых ячеек в основном массиве (меньше 0 или больше MAX_PLAYERS-1 не записать)
public OnGameModeInit()
{
new idx,
i,
rand;
for(i = 0; i < 30; i++)// В этом цикле мы заносим данные в первые 30 ячеек массива
{
idx = Iter_Free(TestIter);// Для наглядности показываю как можно легко найти свободную ячейку в массиве
test_array[idx] = INVALID_PLAYER_ID;// Собственно, сама запись значения
Iter_Add(TestIter, idx);// И указание того, что ячейка занята
}
for(i = 0; i < 10; i++)// Теперь "удалим" 10 рандомных значений из массива
{
rand = random(30);
test_array[rand] = 0;// Обнулили ячейку (хотя на самом деле это не обязательно делать. Важно лишь удалить ячейку из итератора. Я прописал обнуление, дабы в последнем цикле наглядно показать какие ячейки будут выбраны великим псевдорандомом)
Iter_Remove(TestIter, rand);// И удалили ячейку из итератора, указав, что она освободилась (ВАЖНО!)
}
print("\n\nforeach:");// Теперь выведем в консоль значения массива при помощи foreach И обычного цикла, дабы сравнить данные
foreach(new t: TestIter)
{
printf("%i) %i", t, test_array[t]);
}
print("\nfor:");
for(i = 0; i < 30; i++)
{
printf("%i) %i", i, test_array[i]);
}
print("\n\n");
return 1;
}
Так, собственно, можно реализовать систему, что дана в примере
PHP код:
#define MAX_TEAMS 255
#define MAX_PLAYERS_IN_TEAM MAX_PLAYERS / MAX_TEAMS
new players_in_team[MAX_TEAMS][MAX_PLAYERS_IN_TEAM],
Iterator:Team[sizeof(players_in_team)]<sizeof(players_in_team[])>;
public OnGameModeInit()
{
Iter_Init(Team);
#if defined Team_OnGameModeInit
return Team_OnGameModeInit();
#else
return 1;
#endif
}
#if defined _ALS_OnGameModeInit
#undef OnGameModeInit
#else
#define _ALS_OnGameModeInit
#endif
#define OnGameModeInit Team_OnGameModeInit
#if defined Team_OnGameModeInit
forward Team_OnGameModeInit();
#endif
stock Team_SetPlayerTeam(playerid, teamid)
{
new
current_team = GetPlayerTeam(playerid),
idx = ITER_NONE;
if(current_team != NO_TEAM)
{
foreach(new i: Team[current_team])
{
if(players_in_team[current_team][idx] == playerid)
{
idx = i;
break;
}
}
Iter_Remove(Team[current_team], idx);
}
if(teamid != NO_TEAM)
{
idx = Iter_Free(Team[current_team]);
if(idx == ITER_NONE)// Если в команде нет места - возвращаем 0.
return 0;
players_in_team[current_team][idx] = playerid;
Iter_Add(Team[teamid], idx);
}
return SetPlayerTeam(playerid, teamid), 1;// Иначе - 1
}
#if defined _ALS_SetPlayerTeam
#undef SetPlayerTeam
#else
#define _ALS_SetPlayerTeam
#endif
#define SetPlayerTeam Team_SetPlayerTeam
Собственно и остальные преимущества foreach сохраняются: при помощи Iter_Count можно узнать количество значений, занесённых в основной массив, при помощи Iter_Contains можно узнать, занята ли определённая ячейка и т.п.PHP код:
new scores[MAX_TEAMS];
for (new teamid; teamid < MAX_TEAMS; teamid++)
{
foreach(new idx : Team[teamid])
{
scores[teamid] += GetPlayerScore(players_in_team[teamid][idx]);
}
}
for(new teamid; teamid < MAX_TEAMS; teamid++)
{
printf("Team %d: %d", teamid, scores[teamid]);
}
P.S. Писал в браузере и на работоспособность не проверял. Но общий алгоритм прописан