Poszukiwanie skarbów na bezludnej wyspie

13

Wprowadzenie

Utknąłeś na bezludnej wyspie z kilkoma sługami i poszukujesz skarbów. Im dłużej ktoś szuka, tym więcej znajduje skarbu. Im mniej osób szuka, tym więcej znajdzie każda osoba.

Ze względu na ograniczone zapasy przywódca zdecydował, że kilka osób, do jednej czwartej grupy, pozostanie na śmierć każdej nocy. Postanowił nie mówić nikomu dokładnie, ilu ludzi umrze w danym dniu przed czasem.

Masz kontrolę nad niewielką grupą 5 osób, które wyruszą z obozu, aby znaleźć dla ciebie skarb.

Cel

Celem tego konkursu jest zgromadzenie jak największej ilości skarbów. Za każdym razem, gdy twoi słudzy nie podejmą próby powrotu do obozu, znajdą określoną liczbę skarbów. Twoi słudzy mogą wrócić do obozu o różnych porach.

Za każdym razem, gdy robotnik przebywa w poszukiwaniu skarbu, robotnik znajduje 1+Rskarby, w których Rjest liczba robotników (spośród wszystkich botów), którzy są już w obozie. Martwe boty nie uwzględniają tego obliczenia.

Na początku każdego dnia zostanie wybrana losowa liczba ( n) od 2do max(3, floor(num_live_players/4)). (W przypadku 10 graczy w dniu 1 jest 2to możliwemax(3,50/4)=12 . Przez 20 graczy na dzień 1, byłoby to 2do max(3,100/4)=25). Ta liczba oznacza liczbę graczy, którzy będą pozostawione na śmierć w tym dniu, a nie zostaną podane do programu .

Jeśli sługa jest jednym z ostatnich n osób, które powrócą, umrze i nie będzie w stanie przenieść znalezionego skarbu na twój własność. Ponadto sługa nie będzie mógł uczestniczyć w poszukiwaniu skarbów przez resztę przygody.

Twój końcowy wynik to średnia ilość skarbu, którą zdobyłeś na przygodę (przebieg kontrolera).

Jeśli więcej osób spróbuje wrócić do obozu w tej samej turze, niż jest dostępnych wolnych miejsc, losowe liczby określą, kto wchodzi i kto umiera.

Dzień na tej wyspie od wschodu do zachodu słońca trwa 30 tur. Ponieważ w nocy jest wiele niebezpiecznych zwierząt, brak powrotu przed zachodem słońca oznacza, że ​​nie zostaniesz wpuszczony do obozu.

Wejście wyjście

Twój program powinien działać przez całą symulację.

Na początku symulacji INDEX Izostanie wprowadzony, gdzie Ijest indeks twojego bota (ten indeks jest liczony od 1 w górę).

Na początku każdego dnia START_DAY D/Nzostanie wprowadzony do twojego programu, gdzie Djest numer dnia (począwszy od 1), i Njest równy max(3, floor(num_live_players/4)), co jest maksymalną liczbą osób, które mogą umrzeć w tym konkretnym dniu.

Na początku każdej tury START_TURN Tzostanie wprowadzony do twojego programu, gdzie Tjest numer tury (od1 ).

Gdy twój program to otrzyma, powinien odpowiedzieć listą ruchów twoich sług, oddzielonymi przecinkami.

Prawidłowe ruchy to:

  • R: Spróbuj wrócić do obozu.
  • S: Szukaj skarbu.
  • N: Sługa już nie żyje lub jest w obozie.

Wprowadzenie nieprawidłowego ruchu będzie interpretowane tak, Sjakby bot żył, a nie w obozie, i Ninaczej.

Na koniec każdej tury ciąg zostanie przekazany do twojego programu:

END_TURN [Turn #] [Bot 1 Moves] [Bot 2 Moves] ...

gdzie ruchy każdego bota są oddzielone przecinkami.

Te ruchy będą jednym z następujących:

  • R: Pomyślnie wrócił do obozu w tej turze.
  • r: Nie udało się wrócić do obozu w tej turze.
  • S: Wciąż szukam skarbu.
  • D: Zmarł we wcześniejszej turze.
  • N: Już wróciłem do obozu.

Boty i słudzy pozostają w tej samej kolejności przez całą symulację.

Na przykład:

INDEX 2
....
END_TURN 8 N,N,N,N,N r,r,r,r,D D,D,D,N,R S,D,D,N,D

Jesteś drugim botem ( r,r,r,r,r), który próbował zwrócić wszystkich czterech służących, którzy wciąż żyją (i niestety nie udało im się wszystkich czterech). Słudzy Bota 1 wszyscy wrócili do obozu. Bot 3 ma trzech martwych sług, jeszcze jednego z powrotem w obozie i piątego służącego, któremu udało się powrócić. Bot 4 ma jednego sługę, który został (i umrze, ponieważ jest to ostatnia kolejka dnia), jednego sługę w obozie i trzech martwych sług.

Po każdym z tych ciągów, o ile nie zostanie również wypisany ciąg znaków sygnalizujący koniec dnia (patrz poniżej), twój program ma wypisywać kolejne ruchy twoich sług, oddzielone przecinkami. Wszyscy słudzy muszą zostać rozliczeni ( Njeśli jest już w obozie, a Djeśli już nie żyje). Nieprawidłowe ruchy będą traktowane tak, Sjakby sługa nie był jeszcze w obozie / martwy. Przykład:

N,N,S,S,R

co znaczy:

Servant # | Action
     1    | Do nothing.
     2    | Do nothing.
     3    | Stay put (keep looking for treasure).
     4    | Stay put (keep looking for treasure).
     5    | Try to return to camp.

Pod koniec dnia po sznurku ostatniej tury zostanie przekazany następujący ciąg ENDinformujący wszystkich o tym, kto żyje:

END_DAY [Day #] [Bot 1 Status] [Bot 2 Status] 

gdzie status to oddzielona przecinkami lista A(żywych) lub D(martwych). Następny dzień zaczyna się natychmiast po.

Symulacja kończy się, gdy jest mniej niż 6 żywych sług. Twój program otrzyma następujące dane wejściowe na końcu symulacji:

EXIT

Zasady / Szczegóły

  • Tylko na turach, w których jest twoja akcja S, znajdziesz skarb.
  • Liczba uruchomionych symulacji: 1000 razy
  • Twój program nie powinien zająć więcej niż 1 sekundę na określenie ruchów.
  • Twój program nie powinien wyjść wcześniej; rozpocznie się dokładnie raz.
  • Upewnij się, że bufor wyjściowy (jeśli dotyczy) jest opróżniany po każdym wyjściu.
  • Pliki mogą być zapisywane w folderze twojego bota ( ./players/BotName/). Nazwa twojego bota to jakkolwiek nazwiesz swojego bota, ze wszystkimi niealfanumerycznymi znakami usuniętymi i zapisanymi w CamelCase. Wpisy mogą zapisywać dane między przebiegami sterownika, ponieważ przebiegi są wykonywane sekwencyjnie.
  • Twój program musi wyjść po otrzymaniu EXIT.
  • Programy, które nie skompilują się lub nie wyrzucą błędów lub nie wyświetlą niepoprawnego tekstu (nie w formacie 5 znaków oddzielonych przecinkami) mogą zostać wykluczone z konkursu. Nowa linia musi następować po każdym wyjściu.
  • Kontroler można znaleźć na GitHub .

Podaj nazwę bota, język + wersję, kod i polecenie, aby skompilować (jeśli dotyczy) i uruchomić bota.

Przykład

Tekst wyprowadzany przez program jest tu poprzedzony znakiem >. Twój program nie powinien wypisywać tego znaku.

INDEX 2
START_DAY 1/3
START_TURN 1
>S,S,S,S,S
END_TURN 1 S,R,S,S,S S,S,S,S,S
START_TURN 2
>S,S,S,S,S
END_TURN 2 S,N,S,R,S S,S,S,S,S
START_TURN 3
>R,R,S,S,S
END_TURN 3 R,N,R,N,R R,R,S,S,S
START_TURN 4
>N,N,S,S,S
END_TURN 4 N,N,N,N,N N,N,S,S,S
START_TURN 5
>N,N,R,R,R
END_TURN 5 N,N,N,N,N N,N,r,r,R
END_DAY 1 A,A,A,A,A A,A,D,D,A
START_DAY 2/3
START_TURN 1
>S,S,N,S,N
END_TURN 1 R,R,R,R,R S,S,D,D,N
END_DAY 2 A,A,A,A,A D,D,D,D,D
EXIT

Wyniki dla powyższego przykładu są następujące:

Bot#    Day 1   Day 2   Total
1       10      0       10
  S1    1+2     0       3
  S2    0       0       0
  S3    1+2     0       3
  S4    1       0       1
  S5    1+2     0       3

2       20      0       20
  S1    1+2     0       3
  S2    1+2     0       3
  S3    0       0       0
  S4    0       0       0
  S5    1+2+3+8 0       14

Zwycięzcą zostaje więc gracz, bot 2. Pamiętaj, że zwycięzca nie musi przeżyć do absolutnego końca. (Pamiętaj również, że gracz mógł pozostać do 30 rundy pierwszego dnia, ponieważ obóz nie byłby pełny, dopóki gracz nie odeśle jeszcze jednego bota).

Wyniki

Bot               Score
Bob               2939.422
Statisticians     2905.833
Morning Birds     1652.325
Evolved           1578.285
Slow Returners    1224.318
Wandering Fools   1065.908
Randomizers       735.313
Drunkards         0     
Plague            0

Dzienniki są dostępne na GitHub . Wyniki poszczególnych prób są dostępne w tym arkuszu kalkulacyjnym Google .

es1024
źródło
Jeśli sługa nie powróci, to czy jest on wliczany do liczby ludzi, którzy umierają dziś?
EagleV_Attnam
@EagleV_Attnam Dzień kończy się albo, gdy będzie wystarczająco dużo sług, którzy powrócili lub minęło 30 tur, w których wszyscy, którzy nie powrócili, umrą, niezależnie od wcześniej ustalonej liczby zgonów.
es1024
Racja, to było głupie, przepraszam.
EagleV_Attnam
Jeśli sługa wróci do obozu, czy może dostarczyć znaleziony dotąd skarb, a potem jeszcze tego samego dnia udać się na poszukiwanie?
Logic Knight
1
@MikeSweeney Nie. Kiedy sługa wróci, zostaje.
es1024

Odpowiedzi:

5

Bob - C ++

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <algorithm>

using namespace std;

int compare(int i, int j)
  {
  if (i < j)
    return (-1);
  if (i == j)
    return (0);
  if (i > j)
    return (1);
  }

int main()
  {
  int index;
  int day;
  int turn;
  int slash_index;
  int to_die;
  int num_alive;
  int mine_alive;
  int turn_to_return;
  bool returned;
  string line;
  vector<int> last_returns;
  vector<int> today_returns;

  getline(cin, line);

  if (line.compare(0, 6, "INDEX ") != 0)
    {
    cerr << "INVALID INDEX LINE \"" << line << "\"" << endl;

    return (-1);
    }

  index = atoi(line.substr(6).c_str()) - 1;

  while (1) // Day loop
    {
    getline(cin, line);
    if (line.compare(0, 4, "EXIT") == 0)
      {
      return (0);
      }
    else if (line.compare(0, 9, "START_DAY") != 0 || (slash_index = line.find('/')) == string::npos)
      {
      cerr << "INVALID START_DAY \"" << line << "\"" << endl;
      return (-1);
      }

    day = atoi(line.substr(10, slash_index - 10).c_str());
    to_die = atoi(line.substr(slash_index + 1, line.length() - slash_index - 1).c_str());

    if (day != 1)
      {
      if (to_die > num_alive)
        {
        turn_to_return = 30;
        }
      else
        {
        turn_to_return = last_returns[last_returns.size() - to_die] - 1;
        }
      }

    returned = false;

    for (turn = 1; turn <= 30; ++turn)
      {
      getline(cin, line);

      if (line.compare(0, 4, "EXIT") == 0)
        {
        return (0);
        }
      if (line.compare(0, 7, "END_DAY") == 0)
        {
        goto end_day;
        }
      if (line.compare(0, 10, "START_TURN") != 0)
        {
        cerr << "INVALID START_TURN \"" << line << "\"" << endl;
        }

      if (day == 1)
        {
        switch (compare(turn, 30))
          {
            case -1:
              cout << "S,S,S,S,S" << endl;
              break;

            case 0:
              cout << "R,R,R,R,R" << endl;
              break;

            case 1:
              cout << "N,N,N,N,N" << endl;
              break;
          }
        }
      else
        {
        if (returned)
          {
          cout << "N,N,N,N,N" << endl;
          }
        /*
        else if (num_alive - today_returns.size() < to_die)
          {
          cout << "R,R,R,R,R" << endl;
          returned = true;
          }
        */
        else if (turn >= turn_to_return)
          {
          cout << "R,R,R,R,R" << endl;
          returned = true;
          }
        else
          {
          cout << "S,S,S,S,S" << endl;
          }
        }

      getline(cin, line);

      if (line.compare(0, 4, "EXIT") == 0)
        {
        return (0);
        }
      if (line.compare(0, 8, "END_TURN") != 0)
        {
        cerr << "INVALID END_TURN \"" << line << "\"" << endl;
        }

      stringstream ss(line);
      string item;
      int i = 0;
      while (getline(ss, item, ' '))
        {
        i++;
        if (i > 2 && i - 3 != index)
          {
          int num_to_add = count(item.begin(), item.end(), 'R'); // Add turn to today_returns for each servant that returned
          for (int j = 0; j < num_to_add; j++)
            {
            today_returns.push_back(turn);
            }
          }
        }

      }

    getline(cin, line);

  end_day:

    if (line.compare(0, 4, "EXIT") == 0)
      {
      return (0);
      }
    else if (line.compare(0, 7, "END_DAY") != 0)
      {
      cerr << "INVALID END_DAY \"" << line << "\"" << endl;
      return (-1);
      }

    stringstream ss(line);
    string item;
    int i = 0;
    num_alive = 0;
    while (getline(ss, item, ' '))
      {
      i++;
      if (i > 2 && i - 3 != index)
        {
        num_alive += count(item.begin(), item.end(), 'A');
        }
      else if (i - 3 == index)
        {
        mine_alive = count(item.begin(), item.end(), 'A');
        }
      }

    last_returns = today_returns;
    today_returns.clear();

    }

  return (0);
  }

Kompilować:

g++ -o Bob.exe Bob.cpp

Biegać:

./players/Bob/Bob.exe

źródło
6

Statystyka, Python 3

Statystyki zawsze pracują razem. W pierwszej turze wracają do obozu, gdy zrobiły to dwie trzecie przeciwników. W kolejnych turach polegają na danych zebranych w poprzednich turach, aby przewidzieć nawyki innych służących i spróbować wrócić do obozu w ostatniej bezpiecznej chwili.

Program

# Team of treasure-hunting statisticians
# Run with:
# python3 statisticians.py

num_others = None
running = True
while running:
    msg = input().split()
    msg_type = msg.pop(0)
    if msg_type == "INDEX":
        my_index = int(msg[0])-1
    elif msg_type == "START_DAY":
        day, max_deaths = tuple(map(int, msg[0].split('/')))
    elif msg_type == "START_TURN":
        turn = int(msg[0])
        if day == 1:
            if turn == 1:
                print("S,S,S,S,S")
            elif turn == 30 or num_active <= max_deaths * 4/5:
                print("R,R,R,R,R") # On first day, return when 4/5 of  maximum number of dying servants remain
            else:
                print("S,S,S,S,S")
        elif turn >= 29 or len(expected_servants[turn+1]) <= max(2, max_deaths * 3/4) or len(expected_servants[turn]) <= max(2, max_deaths * 1/4):
            print("R,R,R,R,R") # If many servants are expected to return next turn or someone is sure to die, return to camp
        else:
            print("S,S,S,S,S") # Otherwise, keep going
    elif msg_type == "END_TURN":
        turn = int(msg.pop(0))
        others_moves = [tuple(s.split(',')) for s in msg[:my_index] + msg[my_index+1:]]
        if num_others is None: # End of first turn, initialize variables that depend on number of servants
            num_others = len(others_moves)
            others_history = [{} for i in range(num_others)]
        if day == 1:
            num_active = sum([move.count('S') for move in others_moves])
        for i, moves in enumerate(others_moves): # Log the return habits of other bots
            if turn == 1:
                others_history[i][day] = [0]*5
            for j, move in enumerate(moves):
                if move == "R": # Only safely returned servants are taken into account
                    others_history[i][day][j] = turn
                    if day > 1:
                        for future_turn in range(turn, 30):
                            expected_servants[future_turn].discard((i,j))
    elif msg_type == "END_DAY":
        day = int(msg.pop(0))
        my_statuses = tuple(msg[my_index].split(','))
        others_statuses = [tuple(s.split(',')) for s in msg[:my_index] + msg[my_index+1:]]
        expected_servants = [set() for i in range(30)] # Compute the sets of expected servants for each turn
        for i in range(num_others):
            for j in range(5):
                if others_statuses[i][j] == 'A':
                    turn_sum = 0
                    for day_num in others_history[i]:
                        turn_sum += others_history[i][day_num][j]
                    for turn in range(turn_sum//day):
                        expected_servants[turn].add((i,j))
    elif msg_type == "EXIT":
        running = False

Jak widać bezwstydnie ukradłem strukturę programu @Mike Sweeney.

Komenda

python3 statisticians.py

EDYCJA: Naprawiono błąd w czeku na powrót do domu. Powinny teraz działać nieco lepiej.

EDYCJA 2: Statystyki są teraz mądrzejsze niż wcześniej: śledzą, którzy słudzy wrócili do obozu w bieżącym dniu i odpowiednio dostosowują swoje prognozy. Ponadto podejmują większe ryzyko, wracając do obozu, gdy pozostanie 3/4 maksymalnej liczby umierających sług. To popycha ich z powrotem na szczyt (ledwo; Bob stał się bardzo niebezpieczny).

Zgarb
źródło
5

Pijacy, Perl 5

Trochę za dużo alkoholu i nigdy nie znajdą drogi do obozu.

Ten wpis jest przede wszystkim przykładem, ale będzie brać udział.

Program

#!/usr/bin/perl
use 5.10.1;
$| = 1; # disable buffering
@actions = qw(S S S S S);

$_ = <>; ~/^INDEX (\d+)/;
$index = $1;

while(<>){
    if(index($_, 'START_TURN') == 0){
        say join(',', @actions);
    }elsif(index($_, 'END_DAY') == 0){ 
        # update actions based on who is alive
        # index 1-indexed; first bot at position 2.
        # this is not actually necessary for Drunkards, as all of Drunkards'
        #  servants will die on day 1 in any case.
        # This check is here simply as an example.
        my @status = split(',',(split(' '))[$index + 1]);
        my $i;
        for($i = 0; $i < 5; ++$i){
            # action is S if alive, N if dead. Servants will never be in camp.
            $actions[$i] = $status[$i] eq 'A' ? 'S' : 'N';
        }
    }elsif(index($_, 'EXIT') == 0){
        exit 0;
    }
}

Komenda

perl ./players/Drunkards/Drunkards.pl
es1024
źródło
Czy twój kod $status[$i] eq 'A' ? 'S' : 'D';powinien $status[$i] eq 'A' ? 'S' : 'N';spełniać specyfikację?
Logic Knight
@MikeSweeney Dobry połów. Zapomniałem to naprawić, kiedy zmieniłem specyfikację, gdy to wyzwanie było jeszcze w piaskownicy.
es1024
4

Poranne Ptaki

Kto rano wstaje temu Pan Bóg daje!!!

package players.MorningBirds;

import java.io.*;
import java.util.*;

/*
 * Java 7
 * 
 * Compile with "javac ./players/MorningBirds/MorningBirds.java"
 * Run with "java players.MorningBirds.MorningBirds"
 * 
 * Servants find treasure from morning until noon.
 * At noon they go to bed to prepare for next day.
 * 
 * According to Benjamin Franklin, "Early to bed, early to rise, keeps a 
 *      man healthy, WEALTHY, and wise."
 * 
 * 
 */
public class MorningBirds {

    protected final static String STARTDAY = "START_DAY";

    protected final static String STARTTURN = "START_TURN";

    protected final static String ENDTURN = "END_TURN";

    protected final static String ENDDAY = "END_DAY";

    protected final static String MOVERETURN = "R";

    protected final static String MOVESEARCH = "S";

    protected final static String MOVENOTHING = "N";

    protected final static String RETURNED = "R";

    protected final static String FAILEDRETURN = "r";

    protected final static String SEARCHING = "S";

    protected final static String DEAD = "D";

    protected final static String SLEEPING = "N";

    protected final static String EXIT = "EXIT";

    protected final static String ALIVE = "A";

    protected enum Status{SEARCHING, DEAD, RETURNED}

    protected enum Move{RETURN, SEARCH, NOTHING}

    protected int index;

    protected int day;

    protected int turnNum;

    protected int howManyTeams;

    protected int howManyWillDieTodayAtMost;

    protected int howManyHaveDiedToday;

    protected int howManyEnemyPlayers;

    protected int howManyAliveEnemyPlayers;

    protected int howManyEnemyTeams;

    protected int howManyDeadEnemyPlayers;

    protected int howManyReturnedEnemyPlayers;

    protected int howManySearchingEnemyPlayers;

    protected int howManyTotalPlayers;

    protected int howManyTotalAlivePlayers;

    protected int howManyTotalDeadPlayers;

    protected int howManyTotalReturnedPlayers;

    protected int howManyTotalSearchingPlayers;

    protected int howManyOwnAlivePlayers;

    protected int howManyOwnDeadPlayers;

    protected int howManyOwnReturnedPlayers;

    protected int howManyOwnSearchingPlayers;

    protected Status[] statuses = new Status[5];

    protected Status[][] allStatuses = null;

    protected List<Status[][]> allDayStatuses = null;

    protected List<List<Status[][]>> allTimeStatuses = new ArrayList<>();

    protected BufferedReader in = new BufferedReader(
            new InputStreamReader(System.in));

    public static void main (String args[]) throws Exception{
        new MorningBirds().start();
    }

    public void start() throws Exception{

        index = Integer.parseInt(in.readLine().split("\\s")[1]);
        Arrays.fill(statuses, Status.SEARCHING);

        while(true){
            String[] input = in.readLine().split("\\s");
            if (input[0].equals(ENDTURN) || input[0].equals(ENDDAY)){
                updateStatus(input);
            } else if (input[0].equals(EXIT)){
                return;
            } else if (input[0].equals(STARTDAY)){
                updateDay(input);
            } else if (input[0].equals(STARTTURN)){
                updateTurn(input);
                doTurn(input);
            }

        }

    }

    protected void updateStatus(String[] input){
        if (allStatuses == null && input[0].equals(ENDTURN)){
            allStatuses = new Status[input.length - 2][5];
            for (Status[] enemyStatus : allStatuses){
                Arrays.fill(enemyStatus, Status.SEARCHING);
            }
            howManyTeams = input.length - 2;
            howManyEnemyTeams = input.length - 3;
            howManyTotalPlayers = howManyTeams * 5;
            howManyTotalAlivePlayers = howManyTotalPlayers;
            howManyTotalSearchingPlayers = howManyTotalAlivePlayers;
            howManyAliveEnemyPlayers = howManyTotalPlayers - 5;
            howManyEnemyPlayers = howManyEnemyTeams * 5;
            howManyOwnAlivePlayers = 5;
            howManyOwnSearchingPlayers = 5;
            howManySearchingEnemyPlayers = howManyAliveEnemyPlayers;
        }
        for ( int j = 0; j < howManyTeams; j++){
            String[] stats = input[j + 2].split(",");
            for(int i = 0; i < 5; i++){
                switch (stats[i]){
                    case "R":
                    case "N":
                        if (allStatuses[j][i] != Status.RETURNED){
                            howManyTotalReturnedPlayers++;
                            howManyTotalSearchingPlayers--;
                            if (j == index - 1) {
                                howManyOwnReturnedPlayers++;
                                howManyOwnSearchingPlayers--;
                            } else {
                                howManyReturnedEnemyPlayers++;
                                howManySearchingEnemyPlayers--;
                            }
                        }
                        allStatuses[j][i] = Status.RETURNED;
                        break;
                    case "A":
                    case "S":
                        if (allStatuses[j][i] != Status.SEARCHING){
                            howManyTotalReturnedPlayers--;
                            howManyTotalSearchingPlayers++;
                            if (j == index - 1) {
                                howManyOwnReturnedPlayers--;
                                howManyOwnSearchingPlayers++;
                            } else {
                                howManyReturnedEnemyPlayers--;
                                howManySearchingEnemyPlayers++;
                            }
                        }
                        allStatuses[j][i] = Status.SEARCHING;
                        break;
                    case "r":
                    case "D":
                        if (allStatuses[j][i] != Status.DEAD){
                            howManyTotalAlivePlayers--;
                            howManyTotalDeadPlayers++;
                            howManyHaveDiedToday++;
                            howManyTotalSearchingPlayers--;
                            if (j == index - 1){
                                howManyOwnAlivePlayers--;
                                howManyOwnDeadPlayers++;
                                howManyOwnSearchingPlayers--;
                            } else {
                                howManyAliveEnemyPlayers--;
                                howManyDeadEnemyPlayers++;
                                howManySearchingEnemyPlayers--;
                            }
                        }
                        allStatuses[j][i] = Status.DEAD;
                        break;
                    default:
                        break;
                }
            }
        }
        statuses = allStatuses[index - 1];
        if (input[0].equals(ENDTURN)){
            allDayStatuses.add(allStatuses.clone());
        }
        if (input[0].equals(ENDDAY)){
            Status[][] statusesToAdd = new Status[howManyTeams][5];
            for (int i = 0; i < statusesToAdd.length; i++){
                for (int j = 0; j < statusesToAdd[i].length; j++){
                    if (allStatuses[i][j] == Status.SEARCHING){
                        statusesToAdd[i][j] = Status.RETURNED;
                    } else {
                        statusesToAdd[i][j] = Status.DEAD;
                    }
                }
            }
            while (turnNum <= 30){
                allDayStatuses.add(statusesToAdd.clone());
                turnNum++;
            }
            allTimeStatuses.add(allDayStatuses);
        }
    }

    protected void updateDay(String[] input) throws Exception{
        day = Integer.parseInt(input[1].split("/")[0]);
        howManyWillDieTodayAtMost = Integer.parseInt(input[1].split("/")[1]);
        howManyHaveDiedToday = 0;
        allDayStatuses = new ArrayList<>();
        if (day == 1){
            Arrays.fill(statuses, Status.SEARCHING);
            howManyOwnAlivePlayers = 5;
            howManyOwnSearchingPlayers = 5;
        }
    }

    protected void updateTurn(String[] input){
        turnNum = Integer.parseInt(input[1]);
    }

    protected void doTurn(String[] input){
        Move[] moves = new Move[5];
        for (int i = 0; i < 5; i++){
            if (statuses[i] == Status.DEAD ||
                        statuses[i] == Status.RETURNED) {
                moves[i] = Move.NOTHING;
                continue;
            } else {
                moves[i] = doMove(i);
            }
        }
        String[] outputs = new String[5];
        for (int i = 0; i < 5; i++){
            switch (moves[i]){
                case SEARCH:
                    outputs[i] = MOVESEARCH;
                    break;
                case RETURN:
                    outputs[i] = MOVERETURN;
                    break;
                case NOTHING:
                    outputs[i] = MOVENOTHING;
            }
        }
        String totalOutput = "";
        for(String output : outputs){
            if (totalOutput != ""){
                totalOutput += ",";
            }
            totalOutput += output;
        }
         System.out.println(totalOutput);
    }

    //Implement this method differently for different 
    //strategies. 
    public Move doMove(int playerNumber){
        if (turnNum >= 15){
            return Move.RETURN;
        }
        return Move.SEARCH;
    }

    /**
     * Returns the status of one of your players. 
     * Your players have numbers 1 to 5 inclusive.
     * Throws exception if number is outside range.
     * 
     */
    protected Status getStatus(int player){
        if (player > 5 || player < 1){
            throw new IllegalArgumentException(
                    "getStatus(" + player +") failed.");
        }
        return statuses[player - 1];
    }

    /**
     * Returns the status of a player in a team.
     * Team numbers start with 1 inclusive.
     * Players have numbers 1 to 5 inclusive.
     * Throws exception if argument player is outside range.
     * Throws exception if argument team is less than 1 or is greater
     * than the number of teams.
     * Returns Status.SEARCHING if day == 1 and turnNum == 1 and argument 
     * team >= 1.
     */
    protected Status getStatus(int team, int player){
        if (team < 1 || player < 1 || player > 1 || 
                (team > howManyTeams && day == 1 && turnNum == 1)){
            throw new IllegalArgumentException(
                    "getStatus(" + team + ", " + player + ") failed.");
        }
        if (day == 1 && turnNum == 1 && team >= 1){
            return Status.SEARCHING;
        }
        return allStatuses[team - 1][player - 1];
    }

    /**
     * Returns the status of a player in a team at the end of argument
     * turn.
     * Team numbers start with 1 inclusive.
     * Players have numbers 1 to 5 inclusive.
     * Turns have numbers 0 to 30 inclusive.
     * Status at turn 0 is equal to status at start of turn 1.
     * Throws exception if argument turn hasn't happened yet.
     * Throws exception if argument player is outside range.
     * Throws exception if argument team is less than 1 or is greater
     * than the number of teams.
     */
    protected Status getStatus(int turn, int team, int player){
        if (turn == 0){
            if (day == 1){
                return Status.SEARCHING;
            } else {
                return getStatus(day - 1, 30, team, player);
            }
        }
        if (turnNum <= turn || turn < 0|| player > 5 || player < 1 ||
                team < 1 || team > howManyTeams){
            throw new IllegalArgumentException("getStatus(" + turn + 
                    ", " + team + ", " + player + ") failed.");
        }
        return allDayStatuses.get(turn - 1)[team - 1][player - 1];
    }

    /**
     * Returns the status of a player in a team at the end of argument
     * turn on the day of argument day.
     * Team numbers start with 1 inclusive.
     * Players have numbers 1 to 5 inclusive.
     * Turns have numbers 0 to 30 inclusive.
     * Days have numbers 1 inclusive and up.
     * Status at turn 0 is equal to status at start of turn 1.
     * Throws exception if argument day hasn't ended yet or is less 
     * than one.
     * Throws exception if argument turn is out of range.
     * Throws exception if argument player is outside range.
     * Throws exception if argument team is less than 1 or is greater
     * than the number of teams.
     */
    protected Status getStatus(int day, int turn, int team, int player){
        if (turn == 0){
            if (day == 1){
                return Status.SEARCHING;
            } else {
                return getStatus(day - 1, 30, team, player);
            }
        }
        if (this.day <= day || day < 1 || turn > 30 || turn < 0 || 
                player > 5 || player < 1 ||
                team < 1 || team > howManyTeams){
            throw new IllegalArgumentException("getStatus(" + day + ", "
                    + turn + ", " + team + ", " + player + ") failed.");
        }
        return allTimeStatuses.get(day - 1).get(turn - 1)[team - 1][player - 1];
    }

}

Edycja: Stworzono go, aby każdy mógł go łatwo podklasować. Po prostu przedefiniuj doMove(int playerNumber)swojego bota. Dodałem kilka pomocnych pól i metod. Dokładnie go przetestowałem. To nie nie zapisywać stany z poprzednich symulacji. Powiedz mi, czy są jakieś problemy.

Połącz z: javac ./players/MorningBirds/MorningBirds.java

Biegnij z: java players.MorningBirds.MorningBirds

Numer jeden
źródło
Czy byłoby w porządku, gdybym zabezpieczył metody i zmienne, a później podklasę tego dla wyzwania?
TheNumberOne
W razie potrzeby możesz użyć wielu plików źródłowych lub ponownie użyć kodu z innych wpisów, o ile wpisy nie będą ze sobą współpracować.
es1024
@ es1024 Podczas eksperymentów zauważyłem, że bot umiera, jeśli nic nie robi przez cały dzień od pierwszej tury. Czy to jest zamierzone?
TheNumberOne
Bot, który nigdy nie powraca ( R) w danym dniu, zawsze umiera tego dnia.
es1024,
Kontroler przestaje odpowiadać, jeśli dodam odtwarzacze SlowReturners i Randomizers. Uwaga: przepraszam, zamieszczam tutaj komentarze. Nie mam reputacji potrzebnej do publikowania w innych miejscach.
TheNumberOne
3

Randomizery - Ruby

Aby zepsuć boty oparte na statystykach, randomizatory są dość nieprzewidywalne. Wszyscy wracają od razu, losowo, próbując osierocić innych.

(Nie ma wpływu na innych graczy.)

def min(a,b);(a<b)?a:b;end
x=""
r=0
while x != "EXIT"
  x=gets.chomp
  if x =~ /^START_DAY/
    r = min(rand(30),rand(30))
  end
  if x =~ /^START_TURN (\d*)/
    puts ($1.to_i>r)?'R,R,R,R,R':'S,S,S,S,S'
  end
end
MegaTom
źródło
2

Wędrujący głupcy, Python 2

Jest to prosty bot Pythona, który wysyła służących, aż do osiągnięcia ustawionego czasu „gobacka”, a następnie próbują wejść do obozu i zostać do następnego dnia.

Jest to również podstawowa platforma dla bardziej złożonych botów, z których inni mogą chcieć korzystać. Nie jest to jednak testowane w silniku sędziego, więc daj mi znać, jeśli popełniłem błąd.

Program

import sys
from random import randint, choice
team = range(5)

while True:
    inp = sys.stdin.readline().split()
    cmd = inp.pop(0)
    if cmd == 'INDEX':
        teamnum = int(inp[0]) - 1   # using zero based indexing
    elif cmd == 'START_DAY':
        daynum, deadnum = [int(v) for v in inp[0].split('/')]
        # Set up strategy for the day:
        goback = [randint(5,25) for i in team]
    elif cmd == 'START_TURN':
        turn = int(inp[0])
        # Output actions [R]eturn, [S]earch, [N]othing here:
        actions = ['S' if turn < goback[i] else 'R' for i in team]
        sys.stdout.write( (','.join(actions)) + '\n' )
        sys.stdout.flush()
    elif cmd == 'END_TURN':
        endturn = int(inp.pop(0))
        status = [v.split(',') for v in inp]  # R,r,S,D,N
        # [R]eturned, [r]ejected, [S]earching, [D]ead, [N]othing
        mystatus = status[teamnum]
    elif cmd == 'END_DAY':
        endturn = int(inp.pop(0))
        alive = [v.split(',') for v in inp]  # [A]live or [D]ead
        myalive = alive[teamnum]
    elif cmd == 'EXIT':
        sys.exit(0)

Komenda

python WanderingFools.py

Edycja: Zmieniono kod decydujący o akcji po wyjaśnieniu reguły.

Logic Knight
źródło
2

Ewoluował

Użyłem programowania genetycznego (przez JGAP), aby stworzyć tego bota. Wyszedł z prostą odpowiedzią, która bije wszystkie inne (ledwo).

package players.Evolved;

import players.MorningBirds.*;
import java.util.*;

public class Evolved extends MorningBirds{

    List<Integer> scrambled = new ArrayList<>();

    public static void main(String[] args) throws Exception{
        new Evolved().start();
    }

    public Evolved() throws Exception{
        super();
    }

    @Override
    public MorningBirds.Move doMove(int playerNum){
        if (!(howManyTotalSearchingPlayers < (turnNum - getScrambled(index)))){
            return Move.SEARCH;
        } else {
            return Move.RETURN;
        }
    }

    @Override
    protected void updateStatus(String[] input){
        super.updateStatus(input);
        if (input[0].equals(ENDTURN) && (Integer.parseInt(input[1]) == 1)){
            for (int i = 1; i <= howManyTeams; i++){
                scrambled.add(i);
            }
            Collections.shuffle(scrambled);
        }
    } 

    public int getScrambled(int in){
        if (in > scrambled.size() || in < 1 ){
            return in;
        }
        return scrambled.get(in - 1);
    }
}

Połącz z: javac players/Evolved/Evolved.java

Biegnij z: java players.Evolved.Evolved

Edycja: Grrr ... Bob pomieszał mnie !!!

Edycja: Yay !!! Bob, został zabity przez paskudną zarazę !!!

Numer jeden
źródło
1

SlowReturners - Ruby

Odsyła jednego sługę co 5 tur.

x=""
while x != "EXIT"
  x=gets.chomp
  if x =~ /^START_TURN (\d*)/
    puts (1..5).map{|i|(i<=$1.to_i/5)?"R":"S"}.join(",")
  end
end
MegaTom
źródło
1

Plaga

Dżuma jest chorobą. To nie jest racjonalne. To jest przewidywalne. Choroby nie mogą zbierać skarbów, nie dbają też o skarb. Zaraza powoduje choroby u innych graczy. Mądrzy zostają w domu i zapominają o skarbie. Głupi są zawsze głupi i nigdy nie zdobędą wiele skarbów. Ewolucja jest (na szczęście) odporna na zarazę. On też jest mądry. Idzie i zbiera skarb, i nie umiera.

package players.Plague;

import players.MorningBirds.MorningBirds;

public class Plague extends MorningBirds{

    public static void main(String[] args) throws Exception{
        new Plague().start();
    }

    public Plague() throws Exception{
        super();
    }

    @Override
    public MorningBirds.Move doMove(int playerNum){
        if (day > howManyTotalDeadPlayers){
            return Move.SEARCH;
        } else {
            return Move.RETURN;
        }
    }
}

Połącz z: javac players/Plague/Plague.java

Biegnij z: java players.Plague.Plague

Bob i statystycy są teraz odporni na zarazę.

Numer jeden
źródło
hmm ... kiedy uruchamiam tego bota, zawsze umiera pierwszego dnia ...
Użyłem do tego algorytmu genetycznego. Powinien umrzeć drugiego dnia. To popsuwa boty napędzane statystykami, dzięki czemu działają dość słabo w porównaniu do Evolved.
TheNumberOne