PDA

Visualizza versione completa : [C] Battaglia Navale (versione client server) in Linux


Nanri
05-06-2005, 12.13.08
potreste aiutarmi? non so da dove partire..

Realizzazione di una versione elettronica del famoso gioco "Battaglia
Navale". In questa versione due processi client sono l'interfaccia tra i
giocatori e il server. Un client, una volta abilitato dal server,
accetta come input una mossa, la trasmette al server, e riceve la
risposta dal server. Il server a sua volta quando riceve una mossa,
comunica ai due client la posizione del colpo, se una nave e' stata
colpita/affondata, e se uno dei due giocatori e' il vincitore,
altrimenti abilita il secondo client a spedire una mossa.
Il canale di comunicazione tra client e server e' a discrezione
dello studente.

Sergio Neddi
05-06-2005, 21.32.06
Mi ricorda questo:
http://www.wintricks.it/forum/showthread.php?s=&threadid=69699
prova a darci un'occhiata.

Nanri
05-06-2005, 23.05.26
In effetti è lo stesso prof.. ho pensato un po come farlo.. aiutatemi magari a migliorarlo..

SPECIFICHE TECNICHE

Scacchiere 10x10,

le righe: A, B, C, D, E, F, G, H, I, J (INTERF GIOC, CORRISPONDENTE MACCHINA 0, 9)
le colonne da 1 a 10 (corrispondente macchina 0,9)

Si hanno a disposizione le seguenti navi 4,3,2,1.

i client interfacciano giocatori e server.

ogni client ha in memoria la matrice con le proprie navi, la matrice i tiri effettuati.

il server ha due array, uno per ogni giocatore, conteneti posizione elemento iniziale delle navi (l'elemento più in alto in caso di nave verticale, elemento più a sinistra in caso di nave orizzontale).


La matrice per ogni client è di interi,
0 non c'è nave,
1 c'è nave in orizzontale
2 c'è nave in verticale
3 nave colpita
4 c'è nave in caselle adiacenti.
5 colpo dell'avversario in acqua

Il client è fornito di un metodo stampa che stampa la matrice con le seguenti sostituzioni:
0 = •
1 = -
2 = |
3 = +
4 = non visualizzata in stampa
5 = o

Per il server la matrice ha solo 0 per non c’è nave, 1 per c’è nave. La matrice per gli attacchi all’avversario è analoga (con il 3 ed il 4).




POSIZIONAMENTO NAVI

client crea array (pos) di dimesione 4 temporaneo. In ogni cella c’è un array di dimensione 4 con:
condizione (1 per integra, 0 per affondata), coordinata orizzontale, coordinata verticale, orientamento.

Crea matrice di interi 10x10 inizializzata con tutti 0 e che verrà aggiornata secondo le seguenti specifiche:
0 non c'è nave,
1 c'è nave in orizzontale
2 c'è nave in verticale
3 nave colpita
4 c'è nave in caselle adiacenti.
5 colpo dell'avversario in acqua

Per tutte le navi (a partire da 4 fino ad 1):
domande del client:
inserire posizione nave x (esempio A1):
specificare la nave x è in orizzontale o in verticale (O/V):

verifica:
rispetto vincoli di limiti tastiera.
esistenta di 4 in caselle che dovrebbero essere occupate dalla nave

se le verifiche sono andate a buon fine:
aggiorna matrice.
pulisci schermo
stampa la matrice parziale

se le verifiche non sono andate a buon fine stampare: "Posizione non valida" e tornare all'inizio.

Comunica matrice al server matrice finale sostituendo a 1 e 2 un 1.

INIZIO PARTITA

Il server decide random (c’è sicuramente un comando che genera un numero da 0 a 1) chi deve iniziare e passa il comando al giocatore sorteggiato. Comunica (tramite messaggi) ai due client l’esito del sorteggio.

Il client non sorteggiato comunica al giocatore:
“E’ stato sorteggiato l’altro giocatore” entra in fase di attesa

Il client sorteggiato comunica al giocatore:
“Sei stato sorteggiato” entra in fase di lancio


FASE DI LANCIO
Il server abilita il client a lanciare.

Il client:
1. comunica al giocatore “Scegli dove colpire”
verifica:
che le coordinate del colpo sono all’interno dei bordi del campo di battaglia. (in caso contrario scrive: “Colpo esterno al campo di battaglia.” e torna al punto 1)
che le coordinate del colpo non siano gia state immesse precedentemente (in caso contrario scrive su schermo “posizione gia colpita” e torna al punto 1)

comunica al server la posizione del colpo.

Il server verifica contenuto coordinata ed agisce di conseguenza:

0 – comunica all’attaccante che non c’è nessuna nave, comunica al difensore le coordinate.

1 – comunica al difensore le coordinate. Verifica se la nave è stata affondata (se si comunica ai client l’affondamento della nave). Se la nave è stata affondata verifica se ci sono altre navi superstiti, in caso di esito negativo comunica ai due client che l’attaccante ha vinto.

Il client:
attende comunicazione server, aggiorna matrice. Se la nave è stata affondata aggiorna a 4 tutte le caselle adiacenti alla nave. Se ha vinto comunica al giocatore. In caso di affondamento di una nave la comunica al giocatore

Il server abilita l’altro giocatore all’attacco.

Nanri
05-06-2005, 23.06.00
FASE DI DIFESA
Il client attende la comunicazione del server.
Arrivato il messaggio aggiorna la matrice. In caso di affondamento aggiorna tutte le caselle adiacenti alla nave con un 4.
In caso di vittoria dell’avversario comunica al giocatore l’esito. Scrive un messaggio in caso di affondamento della nave.

Dav82
08-06-2005, 03.23.36
Una cosa, anzi due (se se ne era già discusso nell'altro 3D linkato da Sergio chiedo scusa).


Parlando della matrice delle navi e dei colpi lato client, a cosa ti serve sapere se c'è una nave in una casella vicina, oppure differenziare se la casella fa parte di una nave posta in orizzontale o in verticale?
A mio modo di vedere una codifica necessaria e sufficiente potrebbe essere:

0 -> niente navi, nessun colpo avversario
1 -> nave presente, nessun colpo avversario
2 -> nave presente, colpita dall'avversario
3 -> niente navi, colpo avversario (ergo in acqua)

Se il discorso della nave adiacente era per capire se una nave è affondata o semplicemente colpita... beh, io lo farei proprio in un altro modo; ho in mente due soluzioni, una gestita solo lato server, l'altra sia lato client che lato server, ma prima vediamo che cosa proponi tu :p
NB: sempre che serva differenziare lato client fra una nave affondata e una colpita solo parzialmente ;)

O la tua codifica aveva una motivazione che mi sfugge? :)



Sul server cosa tieni?
Da quello che hai scritto sembra solo due array (a occhio e croce di struct, ma in C non sono una lince) con il posizionamento delle navi dei due client; ma come dici poi, se vuoi evitare "colpi doppi", devi tenere memoria anche della storia dei colpi dei due client.


Il resto non l'ho guardato in maniera decente da poter commentare, è troppo tardi :D


Ciao :)

Nanri
08-06-2005, 11.30.40
La storia dei colpli doppi deve essere controllata dai client..

sapere se le navi sono in orizzontale o in verticale mi serve per una questione grafica.. voglio stampare le navi come lineette appunto orizzontali o verticali

la codifica del 4 mi serve perche non posso posizionare navi attaccate ad altre navi

Nanri
08-06-2005, 11.32.52
Ho provato a creare la parte di codice per posizionare le navi ma non funge (compila senza problemi).. ci dareste cortesemente un'occhiata?


void inizializza(int a[10][10]){
int i;
int j;
//inizializza a 0 tutti gli elementi della matrice
for(i=0; i<10; i++){
for(j = 0; j<10; j++){
a[i][j] = 0;
}
}
int x;
int k;
char *str;
int test = 1;
for(x=4;x>0;x--){


printf("Digita la posizione ed il verso (O/V) della nave di dimensione %d (es. B9O): ", x);
gets(str);

//FASE DI TEST

test = 1;

if(strlen(str)>3) test=0; //controlla lunghezza coordinate immesse

str[2] = toupper(str[2]);

if(str[0]<0 || str[0]>9 || str[1]<0 || str[1]>9 || !(str[2]== 'O' || str[2] == 'V') ) test=0;

if(str[2]='O'){ //verifica che verrà immessa in celle valide
if(str[1]+x-1<10){
for(k=0; k<x && k<10; k++){
if(a[str[0]][str[1]+k]!=0 && a[str[0]][str[1]+k]!=4) test=0;
}
}
else test=0;
}
else //str[2]='V'
if(str[0]+x-1<10){
for(k=0; k<x && k<10; k++){
if(a[str[0]+k][str[1]]!=0 && a[str[0]+k][str[1]]!=4) test=0;
}
}
else test=0;
}

if(test){
printf("Digitare posizione valida");
x++;
}
else{
//posso posizionare la nave e mettere a 4 tutte le caselle circostanti

if(str[2] = 'O'){
for(k=0;k<x;k++) a[str[0]][str[1]+k]=1; //posiziona nave
if(str[1]!= 0) a[str[0]][str[1]-1]=4; //4 a sinistra
if(str[1]+x != 10) a[str[0]][str[1]+x]=4;//4 a destra
if(str[0]!= 0){
for(k=-1;k<=x;k++) a[str[0]-1][str[1]+k]=4; //sopra (il -1 e il
//=x per prendere elementi all'angolo
}
if(str[0]!=9){
for(k=-1;k<=x;k++) a[str[0]+1][str[1]+k]=4;
}

}
else{ //str[2]=V
for(k=0;k<x;k++) a[str[0]+k][str[1]]=1; //posiziona nave
if(str[0]!= 0) a[str[0]-1][str[1]]=4; //4 su
if(str[0]+x != 10) a[str[0]+x][str[1]]=4;//4 a giu
if(str[1]!= 0){
for(k=-1;k<=x;k++) a[str[0]+k][str[1]-1]=4; //sopra (il -1 e il =x
// per prendere elementi all'angolo
}
if(str[0]!=9){
for(k=-1;k<=x;k++) a[str[0]+k][str[1]+1]=4;
}
stampa(mieNavi);
}
}
}

Nanri
08-06-2005, 11.33.41
porc... perche non si è preso l'indendazione?

Dav82
08-06-2005, 13.08.53
Originariamente inviato da Nanri
porc... perche non si è preso l'indendazione?

Devi usare il tag (code) (/code) (con le parentesi quadre al posto delle tonde)

Ora ho da fare, dopo leggo :)

Nanri
08-06-2005, 21.03.36
ho messo a posto quella parte! sono orgoglioso.. c è talmente + pignolo di java.. vojo tornare indietroooo..

ora non capisco su come fare client e server.. ^_^" chi mi fa una piccola lezione?

Elias
12-06-2005, 15.45.56
Io ho pensato a questa soluzione per la battaglia navale in linux, inserisco solamente una versione discorsiva dell'idea che ho in mente, poi se qualcuno ha altre idee per modificarla, migliorlarla, semplificarla, aiutarci, sono di certo ben viste e vi ringrazio anticipatamente anche solo per averla letta:

Inizio
I file che devono essere creati sono il file server e il file client.
l'idea è che il server sia l'avvio del gioco, quindi attraverso delle fork exec, generi due processi clienti istanze del file client.

Una volta avviato il gioco, i due client chiederanno all'utente l'inserimento delle navi nel campo di battaglia.

Il campo di battaglia viene salvato su due (o su un file unico) e non verrà più acceduto dai client.

il server sarà l'unico che accederà al file per modificare la situazione attuale con i colpi dati dai giocatori.

il server riceve quindi le coordinate dai client, verifica se ha colpito o meno la nave e darà l'output su video al giocatore, aggiornando allo stesso tempo il file (o volendo carica i due campi di battaglia interamente in memoria salvandoli solamente alla fine).

Concludendo

i Client creano un file con il campo di battaglia voluto dal giocatore.

Il server legge e carica le info passategli dai processi tramide il file.

il tutto procede con degli scambi di messaggi tra client e server sincronizzati opportunamente

(volendo possono essere usati i file per poter gestire la priorità di chi deve comunicare o meno)

Qualcuno ha un idea migliore o può darci una mano nell'ideare un modo efficiente per lo scambio di informazioni tra processi?

Nanri
06-08-2005, 14.50.27
Finalmente ho trovato tempo per imparare C e fare il progetto.. ho dei problemi però.. con le code di messaggi..

Il problema si riscontra quando si prova a far partire il server:

il tipo di messaggio in ricezione:
msgrcv(des_coda, &mail, TAGLIA, 3, 0)

dovrebbe essere bloccante: nelle mie intenzioni il processo si dovrebbe bloccare aspettando un messaggio di tipo 3 ma ciò non avviene e viene stampato molte volte il seguente "Errore nella ricezione del messaggio". Ecco la porzione di codice incriminato:

int main(int argc, char *argv[]){
int des_coda, k, ris = 0, chk1=0, chk2=0, vincitore=1, y, i, j;
long chiave = 83; //identifica la coda
char *mess, mess2[2], c;

srand(time(NULL)); //pone tempo t0=0, necessaria per rand

des_coda = msgget(chiave, IPC_CREAT|/*IPC_EXCL|*/0666); //crea la coda e salva il valore restituito in check, IPC_CREAT specifica che si vuole creare una coda di messaggi con il nome designato dal parametro chiave, IPC_EXCL fa si che il sistema operativo ritorni un errore qualora la coda esista gia. 0666 indica i permessi
if(des_coda==-1)printf("Errore nella creazione della coda\n");

//verifica connessione due processi ed invia ID
mess="1";
ris=(int)ricevi()-'0';
for(i=1;i<3;){
ris=(int)ricevi()-'0';
if(ris==4){
invia(mess, 4);
mess="2";
i++;
}

}



ed il metodo ricevi:


char* ricevi(){ //riceve messaggio dalla coda e restituisce una stringa cui il primo elemento identifica il mittente, i restanti rappresentano il messaggio inviato
int ris;
char mess[TAGLIA], *ret;
msg mail;
ris = msgrcv(des_coda, &mail, TAGLIA, 3, 0); //riceve messaggi di tipo 3 in modalità bloccante (0), salva il msg in mail
if(ris==-1) printf("Errore nella ricezione del messaggio\n");
if(mail.mitt==4 && full==1){//se sono gia connessi due client avverti il client che prova a connettersi e ritorna in ascolto
invia("0",4);
ricevi();
}
mess[0] = '0' + mail.mitt;
strcat(mess, mail.mtext);
ret = mess;
return ret;
}