Gra w Statki - Rozmieszczenie okrętów

Gra w Statki - Rozmieszczenie okrętów
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Postanowiłem dla treningu jako początkujący programista napisać grę w statki. Nie mam jednak pomysłu jak rozwiązać problem z losowym rozmieszczaniem okrętów na planszy przez komputer. Plansza do gry to tablica [10][10] początkowo wypełniona zerami. Początkowo myślałem, żeby poszczególne komórki wypełniać jedynkami - tam gdzie jest statek, ale w tej grze statki nie mogą się stykać burtami, więc statek oznaczyłbym jako 2, a jedynkami otoczył każdy z okrętów. Jednak punkt byłby przyznawany tylko przy trafieniu w pole z 2. Okręty mają wymiary [5][1], [4][1], [3][1], [3][1], [2][1].
Nie mam zbyt logicznego pomysłu jak to rozmieścić losowo. Myślałem o standardowym losowaniu jednego punktu i potem na jego podstawie wylosować jeden z kierunków w którym dodać kolejne punkty, ale to raczej mało praktycznie, bo okręt mógłby wyjść za planszę, lub wejść jeden na drugi.
Zastanawiałem się też czy ręcznie nie napisać np. 20 przykładowych rozmieszczeń i komputer wybierałby tylko jedną z nich.

Czekam na wasze sugestie i pomysły.

EDIT: Sorry, za poprzednie posty, był jakiś błąd na serwerze i pisało, że post nie został wrzucony.

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
3

upychasz statki od największego do najmniejszego.
losujesz pozycję i orientację bieżącego statku
sprawdzasz poprawność i jeśli się nie da to losujesz pozycję orientację statku na nowo aż do skutku.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
dzek69
Moderator
  • Rejestracja:ponad 18 lat
  • Ostatnio:5 dni
  • Lokalizacja:Rzeszów
0

Myślałem o standardowym losowaniu jednego punktu i potem na jego podstawie wylosować jeden z kierunków w którym dodać kolejne punkty, ale to raczej mało praktycznie, bo okręt mógłby wyjść za planszę, lub wejść jeden na drugi.

Dla mnie to dobre rozwiązanie. Losujesz punkt, losujesz kierunek - sprawdzasz czy na kolejnych polach nie byłoby to już poza planszą, lub czy nie ma tam innego statku - jak jest - to sprawdzasz inny losowy kierunek - jak w żadnym kierunku się nie da to losujesz inny punkt i sprawdzasz to wszystko jeszcze raz.

Nie jest to najwydajniejszy algorytm zapewne, ale - różnica pomiędzy najlepszym z możliwych algorytmów a czymś takim będzie i tak niezauważalna - plansza ma 100 pól, a nawet Nokia 3310 poradzi sobie z takim algorytmem w ułamku sekundy - więc na etapie nauki i pisania gry w statki - bym go zaimplementował. Potem ew. bedziesz mogł go ulepszyć.

edit: tak jak @MarekR22 napisał - losując od największego do najmniejszego masz mniejszą szansę na trafianie w niedozwolone pola = wydajniejszy algorytm.


edytowany 1x, ostatnio: dzek69
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

No tak, na to, żeby losować od największego już wpadłem, ale jak rozwiązać to losowanie kierunku ułożenia statku? Bo mamy jedną z 4 możliwości.

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
0

masz tylko 2 możliwości kierunku, poziomo lub pionowo. A możliwości pozycji masz rozmiarPlanszy*(rozmiarPlanszy-rozmiarStatku+1) (nie licząc kolizji).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
dzek69
Moderator
  • Rejestracja:ponad 18 lat
  • Ostatnio:5 dni
  • Lokalizacja:Rzeszów
0

@MarekR22: Jemu chodzi o to, że po wylosowaniu punktu losuje kierunek w którym stawiać kolejne punkty, nie, że od razu stawia statek w całości (a więc nie robi tak, że np. mając statek na 4 pola losuje pozycje X = <0,5>). To jest chyba lepsze rozwiązanie niż stawiać w całości - bo i tak musi przelecieć po punktach w poszukiwaniu kolizji.


MarekR22
nie rozumiem o co ci chodzi, wyznacza x, y kierunek sprawdza kolizje i jeśli jest ok to wstawia statek, jeśli nie to znowu losuje x, y kierunek. Tu nie ma żadnej filozofii.
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

dzek69, dokładnie. Losujemy punkt i od niego idziemy, albo do góry, albo w dół, albo w lewo, albo w prawo. Tylko nie wiem jak zrobić losowanie tego ułożenia. No i jest jeszcze problem z tą kolizją. Bo dajmy na to mam 2 statki ustawione równolegle i między nimi 2 kolumny przerwy. Wylosuje mi między nimi punkt i zacznie ustawiać w poprzek. Postawi 2 punkty i co dalej? Jakiś warunek jest potrzebny, żeby wtedy losowało od nowa punkt, tylko nie wiem jak to rozwiązać kodowo.

dzek69
Moderator
  • Rejestracja:ponad 18 lat
  • Ostatnio:5 dni
  • Lokalizacja:Rzeszów
0

pętla while i przede wszystkim rozbicie tego na funkcje realizujące konkretne zadania.


Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

@dzek69, Ogólniki, ogólniki... Problem w tym, że nie mam pomysłu na jakie zadania mam to rozbić. Liczyłem na pomoc w wykombinowniu algorytmu.

MarekR22
przecież to co napisałem powinno wystarczyć
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
0
Kopiuj
for(statek in statki) {
    int x,y,orientacja;
    do {
        orientacja = rand()%2;
        x = rand()%(orientacja==0?RozmiarPlanszy:(RozmiarPlanszy-statek.rozmiar+1));
        y = rand()%(orientacja!=0?RozmiarPlanszy:(RozmiarPlanszy-statek.rozmiar+1));
    } while (jestKolizjaDla(x, y, orientacja, statek.rozmiar));
    dodajStatek(x, y, orientacja, statek.rozmiar);
}

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 3x, ostatnio: MarekR22
bogdans
Imho nie powinno się losować orientacji (jednej z dwóch), ale zwrot (jeden z czterech). Kolizja będzie sprawdzana w jakiejś kolejności, jeśli np. sprawdzanie w prawo będzie przed sprawdzaniem w lewo, to dla statków 1x5 prawdopodobieństwo, że lewy koniec będzie w zerze jest dwa razy mniejsze niż, że prawy koniec jest w dziewiątce.
MarekR22
@bogdans Gra w statki jest symetryczna, ani lewa ani prawa strona nie jest szczególnie wyróżniona, więc niby czemu te prawdopodobieństwa dla lewego i prawego końca wychodzą ci różne?
_13th_Dragon
Deklarujesz odmienną orientacje? To znaczy w deklaracji masz inaczej nazwaną zmienną ;>
bogdans
@Marek22, wcześniej napisałeś możliwości pozycji masz rozmiarPlanszy*(rozmiarPlanszy-rozmiarStatku+1) więc (raczej niesłusznie) zakładałem, że x losujesz z zakresu [0,rozmiar planszy-1], tzn. x może być zarówno lewym jak i prawym końcem statku, żeby niepotrzebnie nie "stracić" losowania zakładałem, że sprawdzane będą obie możliwości. W zależności od tego, która możliwość będzie sprawdzana wcześniej jedna ze stron planszy będzie preferowana.
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

co to jest "or"?

VI
losowa liczba całkowita od 0 do 1
MarekR22
poprawiłem na orientacja by wszystko było jasne
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Mógłbyś mi jeszcze wytłumaczyć te linijki?

Kopiuj
 while (jestKolizjaDla(x, y, or, statek.rozmiar));
    dodajStatek(x, y, or, statek.rozmiar); 

Poza tym, nie za bardzo rozumiem roli or... On ustawia pionowo, albo poziomo?

edytowany 3x, ostatnio: Niko0
0

Ja bym zrobił dwie bliźniacze tablice: główną i pomocniczą. Losujesz dowolny punkt na tablicy pomocniczej i sprawdzasz po kolei w każdym z czterech kierunków czy zmiescisz statek. Jak stwierdzisz, że się zmiesci to nakładasz statek na obie mapy ,a na tablicy pomocniczej zaznaczasz jeszcze okolicę statku.

Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Łączne mam w programie aż 4 tablice, dla przejrzystości, ale wciąż nie o to się rozchodzi. Nie rozumiem tego fragmentu co mi @MarekR22 podesłał. Nie wiem jak mam zrobić to losowanie.

kq
std::rand() jeśli masz stary kompilator, lub #include &lt;random&gt; jak masz nowszy (i zależy Ci na poprawnej losowości). Link: http://en.cppreference.com/w/cpp/numeric/random/random_device
MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
0
Kopiuj
bool jestKolizjaDla(int x, int y, int or, int rozmiar) {
     if (or==0) {
           for (int i=y; i<y+rozmiar)
                if (plansza[x][i]!=PustePole)
                     return true;
           return false;
     } 
     for (int i=x; i<x+rozmiar)
         if (plansza[i][y]!=PustePole)
             return true;
     return false;
};

To sprawdza tylko czy dodanie nowego statku powoduje nakładanie się z innym statkiem, więc musisz to poprawić jeśli chcesz mieć inny warunek kolizji.
Dodanie statku powinno wyglądać prawie identycznie.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
NC
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 11 lat
  • Postów:11
0
Niko0 napisał(a):

Łączne mam w programie aż 4 tablice, dla przejrzystości, ale wciąż nie o to się rozchodzi. Nie rozumiem tego fragmentu co mi @MarekR22 podesłał. Nie wiem jak mam zrobić to losowanie.

Jesteśmy w dziale algorytmy [...] a nie w Newbie czy też c++. Na tym polega właśnie robienie na początku np. przez ciebie tej gry żebyś sam ją zrobił, żebyś nauczył się rozwiązywać problemy, szukać w googlu, helpie, dokumentacji itd. Jak ktoś Ci da cały kod to co ci to da?

Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

@Nitro Cee. Ja nie chciałem kodu, tylko algorytm. Może myć opisany słownie. :)

Sprawdzanie kolizji i inne rzeczy wiem jak zrobić. Jedyne czego nie umiem to losowanie ułożenia i orientacji statku.

edytowany 1x, ostatnio: Niko0
NC
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 11 lat
  • Postów:11
0

No to dostałeś odpowiedzi na temat algorytmu.

Najlepiej:

  1. losujesz od 1 do 100
  2. potem sprawdzasz czy zmiesci się 5 w góre bez kolizji jak nie to potem np. prawo, dól, lewo
  3. jak git to ustawiasz a jak nie do wróc do 1
Niko0
Od 1 do 100? Mam tablice [10][10], wiec raczej 2 cyfry od 0 do 10.
NC
No jak masz to w ten sposób to 2 cyfry od 1 do 10
TA
Liczby całkowite z przedziału <0;99> można łatwo zamienić na pożądane przez Ciebie wartości <0;10) (raz modulo 10, raz podzielić przez 10) i pamiętaj, że [10][10] to nie cyfry od 0 do 10, a od 0 do 9 ( <0;9> albo <0;10), tak czy inaczej przedział nie jest domknięty na dziesiątce).
MO
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 23 godziny
0

a może troszke inaczej? Każdy statek może mieć tylko kilka reprezentacji na planszy, każda reprezentacja ma swoją "otoczkę" - obszar na którym nie może być żadnego innego statku.
Na początku zdefinuj sobie kolekcję możliwych reprezentacji i otoczek dla każdego statku i potem próbuj rozmieszczać statki na planszy, a jak już go postawisz, "zamaluj" na planszy całą otoczkę dla tej reprezentacji statku.

Jak chcesz ustawić statek skłądający się z 4 pkt, to wybierasz losowo jedną z jego reprezentacji. Następnie szukasz na planszy wystarczająco dużych obszarów aby w nie wstawić tą wybraną reprezentację. Po ułożeniu statku zaznaczasz na planszy jego otoczkę, aby nie można było wstawić na niej innego statku.
Ponieważ zaznaczasz na planszy otoczki, nie musisz sprawdzać kolizji, a dlatego że szukasz miejsca dla statku nie musisz martwić się że otoczka wyjdzie poza mapę/wejdzie na już istniejącą otoczkę.
I tak powtarzasz dla wszystkich statków.
Tak jakbyś rozmieszczał figury na kwadratowej planszy.

Problem pewnie się pojawi jak nie da się wstawić wybranej reprezentacji bo nie ma miejsca - wtedy np wyżucasz tą wybraną reprezentację i szukasz dla innej.

Moźliwe położenia statków możesz sobie na początku wygenerować, albo ręcznie napisać.

edytowany 1x, ostatnio: moskitek
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Mam jeszcze taki problem, że nie wiem jak przekazać tablicę dwuwymiarową jako argument funkcji, tak, aby można ją było modyfikować wewnątrz tej funkcji. To tak jakby przekazywać przez referencję, ale normalny zapis referencji się nie kompiluje. Mógłby mi ktoś coś doradzić?

Sopelek
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 8 lat
  • Lokalizacja:Kraków
  • Postów:467
0

Nie wiem czy to jest dobra praktyka, ale mógłbyś ją opakować w klasę, albo użyć vector<vector<whatever>>

Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Może jakoś prościej? Po najciekawsze jest to, że w jednej funkcji tablica przesłana bezpośrednio jest edytowalna, a w drugiej nie zapamiętuje nic. Przy próbie wpisania jej jako referencji wyskakuje mi błąd. Jest na to jakiś patent?

MarekR22
Moderator C/C++
  • Rejestracja:około 17 lat
  • Ostatnio:5 minut
0

Podstawy programowania w C++: wszystkie tablice przesyłane są zawsze PREZ WSKAŹNIK. Nie ma możliwości przesłania normalnej tablicy przez wartość!


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
Niko0
No właśnie kurde wiem, ale nie wiedziałem jak to jest z wielowymiarowymi, bo wszędzie o jednowymiarowych piszą. W jednej funkcji mogłem ją modyfikować, w innej już nie. Dzięki
rucksick
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 11 lat
0

Jakiś czas temu robiłem a'la sapera i też robiłem coś podobnego. Może wrzucę kod komuś się przyda.

Kopiuj
 
      for(int i=0; i<LiczbaMin; i++)
      {
			do
			{
              a=rand()%7;
              b=rand()%7;
			} while(tab[a][b]==mina || (a==0 && b==0)||(a==6 && b==6));
     
              tab[a][b]=mina;     
              a=0;
              b=0;
      }

Chodziło o to, żeby wylosować podaną liczbę min. Mina nie mogła pokrywać się z inną, nie mogła być na początku trasy sapera i na mecie sapera.


while(noSuccess)
{
tryAgain();
if(Dead)
break;
}
MarekR22
a ja kiedyś robiłem creme brulee, może podam przepis, będzie równie pomocne w tym wątku :P
rucksick
Słaby hejt :P Mja odpowiedź dotyczy tematu, ma dużo wspólnego z pytaniem, można się nią jakoś nakierować ;)
MarekR22
no to wyjaśnij jak mu to pomoże w układaniu statków na planszy, zwłaszcza że dostał pseudokod bardziej na temat. Może po prostu za głupi jestem i powinienem zająć się gotowaniem. Poza tym do hejta daleko, bo inwektyw nie było.
rucksick
Jak pomoże? To chyba jasne, wrzuciłem fragment kodu który działa na podobnej zasadzie. Wystarczy dodać jeszcze jedną zmienną odpowiedzialną za położenie( w pionie lub poziomie) która również będzie losowana. Wrzuca wszysko w pętlę for, która odpowiada za liczbę statków a następnie w do while generuje nowy statek tak dlugo, az tak nie bedzie kolidowal z juz istniejacymi. Jeżeli warunki są spełnione statek zostaje postawiony. Chyba lepiej dac pseudo kod zeby ktos sam pomyslał i wyciągnął jakieś wnioski (bo z nich płynie nauka), niż pisać o francuskich deserach...
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Myślałem, żeby zrobić losowanie liczby "kierunek" z przedziału od 0 do 3 i na tej podstawie wybrać kierunek. Jeśli zwróci 1 to losujemy "kierunek" od nowa. Pierwsze losowanie generowałoby współrzędne d i e. Nie wiem tylko jak zrobić kolejne losowanie tych współrzędnych, w przypadku, gdy wszystkie 4 kierunki nie dadzą pożądanego efektu.

edytowany 1x, ostatnio: Niko0
0

Nie czytalem calego tematu, ale czy naprawde nie wystarczy cos takiego:

Kopiuj
{dir, pos[2]} = rand()
if(pos[abs(dir)&1]+ship_size*dir in plansza)
	return {pos[2], dir}
else
	return {}

Wylosuje, sprawdzi i zwroci wszystkie potrzebne dane do narysowania.

Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Rozwiązałem problem, więc dodam mój pomysł. Może komuś się kiedyś przyda:

  1. Tworzę czteroelementową tablicę, gdzie na każdą pozycję losuje liczbę z zakresu <0, 3>, po czym sprawdzam, czy ona już jest na liście. Jeśli tak to dodaję, jeśli nie, to losuję do skutku.
    Mam Losowo wygenerowany ciąg liczb.
  2. Losuję współrzędne do tablicy dwuwymiarowej
  3. Biorę pierwszy element z listy, który odpowiada jednemu z 4 możliwych kierunków rozmieszczeń (dół, góra, prawo, lewo od wylosowanych współrzędnych) i przesyłam do funkcji, która sprawdza, czy mogę rozmieścić statek w pierwszym
    • Jeśli tak, to układa statek w tym kierunku
    • Jeśli nie (wychodzi za plansze, lub jest tam juz statek), to bierze następny kierunek.
  4. Jeśli wszystkie kierunki nie dadzą pożądanego efektu to losujemy współrzędne od nowa

Teraz zostaje najtrudniejsza część, czyli inteligentne strzelanie przez komputer :). Chodzi o to, żeby po trafionym strzale dalsze trafienia szły jeden po drugim, w danym kierunku. Jeśli ktoś ma jakieś sugestie to z chęcią wysłucham :)

TA
  • Rejestracja:prawie 12 lat
  • Ostatnio:prawie 10 lat
  • Postów:45
0

Uwzględnianie zwrotów nie ma sensu. Interesują nas tylko kierunki, które mamy dwa. To czy jakiś statek ustawi się od lewej, czy od prawej nie ma najmniejszego znaczenia!
Poza tym, aby oderwać się na chwilę od tego, co robię aktualnie, napisałem taki kod, korzystając z Twojego @Niko0 pomysłu

Niko0 napisał(a):

poszczególne komórki wypełniać jedynkami - tam gdzie jest statek, ale w tej grze statki nie mogą się stykać burtami, więc statek oznaczyłbym jako 2, a jedynkami otoczył każdy z okrętów.

Sam na początku myślałem o używaniu po prostu booli i sprawdzaniu czy kolejny okręt nie koliduje. ale w przypadku robienia graficznie mapy statki mogą być otoczone inna grafiką, więc przychyliłem się do tej wersji. Kod wymaga poprawek, ale niewiele da się zrobić w piętnastominutową przerwę.

Kopiuj
#include <cstdio>
#include <cstdlib>
#include <ctime>

using namespace std;

class plansza //jednego gracza
 {
  static const unsigned int liczba_statkow,statki[],bok;
  short unsigned int** const pola;
  void uzupelnij(void); //uzupelnianie planszy statkami
  bool dodaj_statek(unsigned int); //dlugosc statku
  public:
   plansza(void);
   void narysuj(void);
   bool sprawdz_trafienie(unsigned int,unsigned int);
   ~plansza(void);
 };

int main(void)
 {
  srand(time(NULL));
  plansza komputera;
  komputera.narysuj();
  return 0;
 }

const unsigned int plansza::liczba_statkow = 5,plansza::statki[liczba_statkow] = {5,4,3,3,2},plansza::bok = 10;

plansza::plansza(void) : pola(new short unsigned int*[bok])
 {
  for(unsigned int i = 0;i<bok;++i)
   pola[i]=new short unsigned int[bok];
  for(unsigned int i = 0;i<bok;++i)
   for(unsigned int j=0;j<bok;++j)
    pola[i][j]=0;
  uzupelnij();
 }
void plansza::uzupelnij(void)
 {
  //tutaj mozna dodac opcje recznego uzupelniania
  for(unsigned int i=0;i<liczba_statkow;++i)
   while(!dodaj_statek(statki[i]));
 }
bool plansza::dodaj_statek(unsigned int dlugosc_statku)
 {
  bool kierunek = rand()%2; // 1 - pionowy, 0 - poziomy
  unsigned int x = rand() % (( kierunek ? bok : (1+bok-dlugosc_statku))),y=rand() % ( kierunek ?(1+bok-dlugosc_statku) : bok);
  
  for(unsigned int i=0;i<dlugosc_statku;++i)
   if(pola[x+(kierunek?0:i)][y+(kierunek?i:0)]>0)
    return false;

  if(kierunek?y:x!=0)
   pola[x-(!kierunek)][y-kierunek]=1;
  if((kierunek?y:x) + dlugosc_statku < bok)
   pola[x+(kierunek?0:dlugosc_statku)][y+(kierunek?dlugosc_statku:0)]=1;
  for(unsigned int i=0;i<dlugosc_statku;++i)
  {
   pola[x+(kierunek?0:i)][y+(kierunek?i:0)] = 2;
   if(kierunek?x:y > 0)
    pola[x-(kierunek)+(kierunek?0:i)][y-(!kierunek)+(kierunek?i:0)] = 1;
   if((kierunek?x:y)+1<bok)
    pola[x+(kierunek)+(kierunek?0:i)][y+(!kierunek)+(kierunek?i:0)] = 1;
  }
  return true;
 }
void plansza::narysuj()
 {
  for(unsigned int i = 0;i<bok;++i,printf("\n"))
   for(unsigned int j=0;j<bok;++j)
    printf("%c ",(pola[i][j])==2?'X':'-');
 }
bool plansza::sprawdz_trafienie(unsigned int x,unsigned int y)
 {
  return (pola[x][y]==2);
 }
plansza::~plansza(void)
 {
  for(unsigned int i = bok;i--;)
   delete[] pola[i];
  delete[] pola;
 }

Jak widać nie skupiałem się tutaj na wykorzystaniu za wszelką cenę wylosowanego punktu. Nie ma to większego sensu, każda pozycja (dopuszczalna przez grę) jest dobra. Jeśli nie trafiłem, losowałem ponownie, a nie przekształcałem to, co już miałem.

Niko0 napisał(a):

Teraz zostaje najtrudniejsza część, czyli inteligentne strzelanie przez komputer :). Chodzi o to, żeby po trafionym strzale dalsze trafienia szły jeden po drugim, w danym kierunku. Jeśli ktoś ma jakieś sugestie to z chęcią wysłucham :)

Nie jest to wcale takie trudne. Ogólnie to robisz planszę graczowi (komputerowi), na której zaznacza gdzie już strzelił. Na początku te strzały odbywają się w pełni losowo, ale jeśli trafią na już użyte pole, jest losowane kolejne (komputer nie zgłasza, że chce strzelać ponownie w użyte miejsce). Dodatkowo, gdy już trafisz jakiś statek to sprawdzasz (kolejnymi strzałami), w którym kierunku jest on ustawiony i strzelasz, aż go zatopisz. Możesz sprawdzać, czy zakończyłeś zadanie poprzez upewnienie się, że strzały na jedną i na drugą stronę trafiają w wodę, ale lepszym rozwiązaniem (jeśli to możliwe) jest upewnianie się na podstawie statków będących w grze. Jeśli najdłuższy grający aktualnie statek przeciwnika ma długość 4 i Ty właśnie trafiłeś 4. sektor, wiesz, że cały okręt zatonął. Ponadto, jeżeli statek zetknie się z polem, na którym statku nie ma (wiesz to już, np. strzeliłeś tam) to też nie ma sensu ciągnąć w tą stronę tego okrętu. Dodatkowo należy pamiętać, że na około statków (przed, za i obok, w sumie 2(n+1) pól wody) nie może być innych statków, więc i tam nie należy oddawać strzałów (jak już zestrzelisz statek to otaczasz go polami, w które też nie będziesz strzelał). Może jak znajdę chwilę to i to napiszę.
Komunikację "komputera z planszą" przeprowadzałbym tylko przez taką funkcję jak w moim kodzie sprawdz_trafienie.
PS
Oczywiście przeciwnik nie powinien mieć możliwości wyświetlania sobie planszy (nieswojej) ;). Po fazie testów ta opcja powinna zniknąć.

edytowany 5x, ostatnio: Tacet
Niko0
  • Rejestracja:ponad 11 lat
  • Ostatnio:prawie 8 lat
  • Postów:16
0

Zauważ jak ja to robię: Używam 4 różnych stron, gdyż losuję jeden punkt i później dopiero idę od tego punktu w jedną ze stron. Można by było zrobić tylko 2 kierunki, ale wtedy trzeba częściej losować współrzędne, bo zakładając, że na przykład wypadnie 1 rząd i 5 kolumna, a ustawiałbym począwszy od tego punktu do góry, to trzeba by było losować jeszcze raz, a tak mogę pójść jeszcze od tego w dół.

Zrobiłem to w ten sposób i rozmieszczenie działa dość sprawnie.

Co do strzałów, to opisałeś mi zasady gry. To wszysto wiem jak ma działać. Problem jest z rozwiązaniem programowym, np. z tym, żeby strzelał w tym samym kierunku, aż do zatopienia. Trochę się trzeba będzie z tym pobawić.

edytowany 1x, ostatnio: Niko0
TA
Jeśli faktycznie tak istotne jest to kilka losowań to poprawiłem (taki sam sposób opisał @szopenfx (chyba ;p), +1). A co do strzałów. To jak Ty chcesz, aby Ci ktoś to przedstawił? O.o po prostu jak trafisz to wrzucasz trafienie do jakiejś zmiennej, czekasz na następny swój ruch i w nim losujesz kierunek i sprawdzasz go, jeśli błędny, w następnych ruchach sprawdzasz pozostały.
szopenfx
  • Rejestracja:ponad 20 lat
  • Ostatnio:4 miesiące
1

Nie koniecznie rozwiązanie @Tacet'a jest mniej wydajne - najpierw dajmy na to losując 4-masztowca wybierasz kierunek (w prawo lub górę) np. prawo i zwróć uwagę, że nie musisz losować x od 0-9 tylko od 0-6 w ten sposób nie musisz sprawdzać czy statek nie wyszedł poza mapę, y dla kierunku poziomego losujesz już dla całości czyli 0-9.

Niko0
Nie mówiłem, że jest mniej wydajne, ale że moje jest całkiem wydajne :) Jakoś bardziej je widzę. Ciężko się dokładnie wdrożyć w czyjeś myślenie.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)