Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: Pascal: Ongelma kerrankin Delphissä

Wukkopi [03.08.2007 09:15:48]

#

Miksi tässä koodissani tapahtuu seuraava virhe:

Jos kolme tai useampi pelaaja liittyy peliini, ja poistuu satunnaisessa järjestyksessä sovellus kaatuu. Uskoisin, että ongelma sijaitsenee pelaajan luonti ja/tai poisto -tapahtumissa.

Pelaaja on liittynyt:

procedure TGame.addPlayer(Player: TWSocketClient);
begin
    inc(loginCount);
    inc(playerCount); //increase playercount
    setLength(Players, PlayerCount + 1);

    Players[playercount] := TPlayer.Create;  // And then create new
    Players[playerCount].socket := Player; // create identifier to player.
    Players[playerCount].socket.OnDataAvailable := Players[playerCount].ReceiveData;
    Players[playerCount].NthLogger := loginCount;
    Players[playerCount].NickName := '';
    Players[playerCount].PassWord := '';
    Player.SendStr(SendLine('Please enter you nickname and something else seperated by space.'));
    Player.SendStr(SendLine('It may not contain whitespaces.'));
end;

Ja kun pelaaja poistuu:

procedure TGame.removePlayer(Player: TWSocketClient);
var i : integer;
begin
    // loop through players until match is found
    for i := 0 to playerCount do
    begin
        if (Player = Players[i].socket) then
        begin
            // Because we are using dynamic player handle handling,
            // we kick list's last player to currently opened place, and destroy last place.
            Players[i] := Players[playerCount];
            Players[playerCount].Free;
            inc(playerCount, -1); // decrease playercount
            if (playerCount > -1) then // if we try to set array length of zarro, exception is thrown.
            begin
                setLength(Players, playerCount + 1); // Should this be only "setLength(Players, playerCount);" ??
            end;
            exit;
        end;
    end;
end;

Metabolix [03.08.2007 19:23:18]

#

Varsinainen ongelmasi on poistumisessa. Vapautat väärän henkilön. Teet nyt näin (A pitäisi potkia ja B on taulun viimeinen, ehkä säilytettävä):

var A, B: TPelaaja;
A := B; {A:n luulet potkivasi.}
B.Free; {A = B, joten myös A.Free;}

Pitäisi tehdä näin:

var A, B: TPelaaja;
A.Free; {A potkitaan.}
A := B; {Siirretään B:stä A:han, jolloin B:tä ei tarvitse enää huomioida.}

Kyse ei siis ole taulukon paikoista vaan niistä olioista, joihin taulukon paikat osoittavat. Jos A := B, niin A.Free on sama kuin B.Free.

Kommenteistasi näkyy, ettet ole aivan varma taulukon käytöstä. Kun se kerran alkaa nollasta, kannattaisi myös tehdä koodi sen mukaan:

procedure Liity(...);
var PlayerNum: Integer;
begin
  PlayerNum := PlayerCount;
  Inc(PlayerCount); { Pelaajia on yksi enemmän. }
  SetLength(Taulu, PlayerCount); {PlayerNum + 1; [0 .. PlayerNum];}

  Taulu[PlayerNum].X = Y; { Yms. }
end;
procedure Poistu(...);
var PlayerNum, LastPlayerNum: Integer;
begin
  LastPlayerNum := PlayerCount - 1; { Edellisen perusteella viimeinen pelaaja }
  for PlayerNum := 0 to LastPlayerNum do begin
    if SamaPelaaja(Taulu[PlayerNum], Poistettava) then begin
      Taulu[PlayerNum].Free; {Poistetaan poistettava}
      Taulu[PlayerNum] := Taulu[LastPlayerNum]; {Laitetaan viimeinen tilalle}
      Dec(PlayerCount); {Taulua yhtä lyhemmäksi}
      SetLength(Taulu, PlayerCount);
    end
  end
end;

User137 [05.08.2007 13:38:53]

#

for i := 0 to playerCount do

Yleensä lista käydään läpi joko 0..n-1 tai 1..n. Selkeyttää ajatuksena mutta tuokin voi toimia jos periaatetta käyttää läpi ohjelman. Playercount 3 tarkoittaisi että pelaajia on 4 tuollaisenaan.
Jos käytät n-1 systeemiä, voit myös käyttää
setLength(Players, playerCount); // (ilman +1)

inc(playerCount, -1);
on muutekseen sama kuin
dec(playerCount);

Ja sitten pahin... looppi joka poistaa elementtejä, täytyy käydä läpi käänteisessä järjestyksessä

for i := 0 to playerCount do
muuttuu
for i := playerCount downto 0 do

jos näin ei tee, looppi saattaa käsitellä aina vanhaan playerCount asti, ja skippaa viimeisen elementin, se kun aina siirtyy nykyisen tilalle.

edit: No tuossa tapauksessa toimii kyllä noinkin kun lopetat koko aliohjelman tuon 1 poiston jälkeen :p

Metabolix [05.08.2007 16:04:21]

#

User137 kirjoitti:

No tuossa tapauksessa toimii kyllä noinkin kun lopetat koko aliohjelman tuon 1 poiston jälkeen :p

Ei tuossa kai ole tarkoitus poistaakaan kuin se yksi, joka potkitaan t. ilmoittaa palvelimelle poistumisestaan. :) Jos olisi tarkoitus kaikki potkia, niin tuskinpa kukaan siinä välissä paikkaisi listaa, kaikille vain Free ja lopuksi merkitään määräksi nolla.

Wukkopi [07.08.2007 09:26:46]

#

Kiitos vastauksista, pitääpä heti kotiin päästyä koittaa... Oliko koodissa muuta mikä ei olisi järkeenkäypää? Itse en ainakaan näe, mutta kun sitä tulee sokeaksi omalle koodille.

Wukkopi [20.08.2007 08:53:24]

#

Jep. Hienosti toimii nyt, kiitos avusta. Pitää vielä miettiä tuota taulukonkäsittely hässäkkää, että tarvitseeko toimivaa korjata. Koska se kuitenkin toimii.

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta