Esame di Fondamenti di informatica III (Professor Hmeljak) Espeleta Tomas (n°80700189) [email protected] Via Amendola 9, 31045 Motta di Livenza - TV Golden Wheel 1.0 (simulazione Java del gioco della roulette) INTRODUZIONE GoldenWheel - la ruota dorata - e' un software per l'emulazione del gioco della roulette. Sviluppato per l'esame di Fondamenti di Informatica III del corso di D.U. teledidattico in Ingegneria Informatica, consiste in un sistema interamente scritto in Java che permette di visualizzare su un browser web l'ambiente di gioco di una roulette francese. Il sistema e' funzionante, ma per una eventuale diffusione questa distribuzione dovrebbe essere considerato una "alfa"-release. IL SERVER Il server consiste in una applicazione stand-alone scritta in Java2 (gwServer.class), che va dunque avviato con l'interprete. Bisogna fare attenzione perche' questo utilizza due librerie presenti sulla cartella corrente del server, pertanto la linea di comando per avviarlo e' la seguente: java -cp %CLASSPATH%;tinySQL.jar;cup_runtime.jar gwServer oppure run.bat L'applicazione gwServer, una volta avviata, ascolta sulla porta 8001, creando ad ogni chiamata un nuovo thread (gwServerThread.class). Questo ascolta il socket, interpretando gli input tramite un protocollo proprietario, implementato a parte nell'oggetto gwProtocol. La logica del protocollo e' di fatto quella di una macchina a stati finiti: inizialmente si trova su uno stato di "attesa". Una volta ricevuto la linea di input, questa viene interpretata e viene restituita una linea di output. Ecco schematizzati gli stati del protocollo: STATO0: Da' come benvenuto una riga di output con tutti i dati sul server. STATO1: Aspetta che venga inserita una password tramite il comando: PASSWD <utente> <cryptedpasswd> STATO2: Raggiunto solo se il logon ha successo, interpreta i comandi BET, SPIN, QUIT. STATO3: Chiamato "BETRCV", viene raggiunto se e' stato trovato il comando BET. In questo stato vengono immessi i tre dati necessari a "compilare" una scommessa (SESSIONE, CODICE_PUNTATA, CREDITI_PUNTATI). I CREDITI Ho chiamato "crediti" il numero adimensionale della valuta disponibile al giocatore per le puntate. Si e' liberi di interpretarli come meglio si vuole... sarebbe pero' preferibile utilizzare una valuta "dai numeri brevi", che rispetti cioe' il valore delle chip disponibili (1, 5, 10, 25). Esempi: migliaia di lire, euro, dollari. In questa versione non ho imposto alcun limite alle puntate. LE PUNTATE Le puntate cono codificate in un modo abbastanza semplice: un solo intero individua il tipo di puntata e i numeri puntati: Se "00XX NNMM" e' la rappresentazione esadecimale dell'intero a 32 bit, queste sono le varie puntate disponibili: 0001 00XX: Numero Pieno. XX e' il numero puntato (hex). 0002 YYXX: Cavallo. XX e YY sono i numeri puntati (hex). 0003 00XX: Terzina (trasversale). XX e' il numero "di testa" puntato: la terzina e' formata cioe' da XX, XX+1, XX+2 0004 00XX: Quartina (angolo): XX e' ancora il n' di testa. Ad esempio: XX=14 - Quartina=(20,21,23,24) 0005 0000: Primi quattro. In questa roulette a un solo 0, la puntata consiste nei numeri: (0, 1, 2, 3) 0006 00XX: Sei numeri (due trasversali): XX e' il numero di testa. XX, XX+1, ... , XX+5 0010 000X: Dozzina. X e' il numero della dozzina (1, 2, 3). 0011 000X: Colonna. X e' il numero della colonna (1, 2, 3). (La prima colonna e' quella che contiene 1, 4, ..34) 0020 0021 0022 0023 0024 0025 0001 0001 0001 0001 0001 0001 : : : : : : Rosso Nero Pari Dispari 1-18 19-36 Le scommesse vengono immagazzinate in un vettore ed in un database. Per verificare l'utente e memorizzare le scommesse ho utilizzato un Database creato con un driver JDBC freeware: tinySQL. Si tratta di un driver per file di testo e file DBF... non e' certamente il miglior sistema, ne' il piu' veloce... ma la scelta di JDBC permette di mantenere pressoche' inalterato il codice quando si voglia cambiare driver e base di dati (ODBC, MySQL, posGrep, etc..) IL CLIENT Il client consiste in due applet che interagiscono tra di loro (vedasi iac.txt per maggiori informazioni sulla comunicazione fra gli applet). tappeto: consiste in un tappeto verde di gioco, dove si fanno le puntate. Riconosce il tipo di puntata appena appoggiata la chip (che si posiziona con "snap" solo in certe posizioni di una griglia determinata), e mantiene un vettore delle chip presenti sul tappeto. All'avvio della ruota (SPIN), il tappeto trasferisce all'applet della ruota (roulcli.class) tutte le scommesse (metodo chips2bets). roulcli: consiste nella ruota vera e propria. Ruota l'immagine con un algoritmo di rotazione, calcolando ad ogni frame la nuova angolazione. Allo stesso tempo s'incarica della rotazione della pallina, del display con l'ultimo numero uscito (Display.class). All'inizio si incarica anche del logon dell'utente. Una volta uscito il numero, chiede a tappeto di rimuovere le chip perse dal giocatore, ed e'pronto per una nuova tornata. Ecco che oggetti utilizzano i due applet: tappeto ---- Chip +--- (Bet) roulcli +--- PwdDisplay +--- Display +--- Pallina +--- gwClient --- Bet +--- Bet LE CLASSI Server addUser.java Applicazione stand-alone per creare un nuovo utente. gwServer.java Applicazione multithread che ascolta sulla porta 8001... gwServerThread.java Server vero e proprio. Gestisce il socket di connessione. gwProtocol.java (!) Classe per gestire il protocollo di connessione. gwDBase.java Classe che fornisce un'interfaccia al driver JDBC utilizzato. Package "bet.manage" (gestione scommesse) ---------------------------------------------Bet.java Oggetto "scommessa", contiene crediti e codice puntata. BetEncoding.java Fornisce un metodo statico per la decodifica dei codici puntata. BetStore.java Si occupa di memorizzare una scommessa nel DBase. Package "bet.passwd" (gestione passwords) -----------------------------------------Passwd.java Fornisce un metodo che verifica la password passata nel DBase. CryptPwd.java Fornisce un metodo che cripta la password con l'algoritmo MD5. Client roulcli.java (!) Applet principale: visualizza la routa, gestisce la comunicazione C/S. tappeto.java (!) Applet tappeto: visualizza il tappeto di gioco e mantiene una lista di scommesse. Bet.java Oggetto "scommessa", contiene crediti e codice puntata. Chip.java Oggetto "chip", contiene crediti, codice puntata e posizione. Pallina.java Oggetto "pallina": gestione pallina sulla ruota e relativi suoni. Client.java Apre un clentSocket sulla porta 8001 e fornisce due stream di I/O gwClient.java Client di rete: si collega al server e passa le scommesse. Display.java Oggetto che gestisce il display con i numeri usciti PwdDisplay.java Pannello iniziale per Logon. MD5.java Algoritmo MD5. Traduzione a java (c) 1998 by Michael Lecuyer. SVILUPPI FUTURI Ecco alcune idee per sviluppi futuri: 1) La gestione degli utenti e' attualmente limitata a un comando "addUser", che permette soltanto di creare le tabelle e aggiungere un nuovo username/password. Si puo' estendere l'applicazione (che dovrebbe usare JDBC), per cancellare un utente, sospenderlo, visualizzarne i crediti... 2) Gestire allo stesso modo un anagrafico del cliente. 3) Grazie a JBDC risulta facile creare una gestione delle puntate e degli utenti tramite WEB. Si puo' ad esempio creare una serie di pagine amministrative protette da password in cui si fanno delle queries e delle statistiche sui file di log, nonche' la stessa amministrazione utenti. Si possono utilizzare pagine JSP, anche se per la gestione di log e' forse piu' adatto uno script Perl, o delle pagine PHP3. 4) Implementare alcuni tipi di scommessa che attualmente non vengono riconosciuti, come ad esempio i numeri orfanelli e le serie. 5) Migliorare la grafica della pagina, facendo attenzione a rispettare i Tag degli applet. 6) Oscurare la password in digitazione (PwdDisplay.java) 7) addUser.java deve avvisare se l'utente esiste gia', e chiedere conferma quando viene usdato lo switch '-n' LISTATI SERVER: /** *** -------------------------------------------------------*** GoldenWheel v0.01 (gwServer.java) *** Emulazione di Roulette Francese. *** Server Multigiocatore *** ideato e creato da Espeleta Tomas. (c)2000 *** (c) 2000 by Espeleta Tomas. *** Scritto per l'esame di "Fondamenti di informatica III" *** Diploma teledidattico in Ingegneria informatica *** email: [email protected] *** www: http://balder.prohosting.com/espeleta *** indirizzo: v. Amendola 9, 31045 Motta di Livenza - (TV) *** *** -------------------------------------------------------***/ import java.net.*; import java.io.*; public class gwServer { final static int SERVER_PORT = 8001; public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; boolean listening = true; try { serverSocket = new ServerSocket(SERVER_PORT); System.out.println ("Golden-Wheel Server v0.01, listening... (CTRL-C to stop)"); } catch (IOException e) { System.err.println("Could not listen on port: " + Integer.toString(SERVER_PORT)); System.exit(-1); } // Qui accetta le chiamate, creando un nuovo THREAD per ognuna di esse. while (listening) { System.gc(); new gwServerThread(serverSocket.accept()).start(); } serverSocket.close(); } } /** (gwServerThread.java) *** -------------------------------------------------------*** GoldenWheel v0.01 (c)2000 by Espeleta Tomas *** Emulazione di Roulette Francese. *** Thread principale del Server. Memorizza e processa *** le scommesse di un giocatore. *** *** (c) 2000 by Espeleta Tomas. *** Scritto per l'esame di "Fondamenti di informatica III" *** Diploma teledidattico in Ingegneria informatica *** email: [email protected] *** www: http://balder.prohosting.com/espeleta *** indirizzo: v. Amendola 9, 31045 Motta di Livenza - (TV) *** -------------------------------------------------------***/ import java.net.*; import java.io.*; public class gwServerThread extends Thread { private Socket socket = null; public static int counter; public gwServerThread(Socket socket) { super("gwServerThread"); this.socket = socket; counter++; System.out.println("Thread has born: " + Integer.toString(counter)); } public void run() { try { BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(), true); String inputLine, outputLine; // Chiede la Hello-String del protocollo e la scrive... gwProtocol gwp = new gwProtocol(); outputLine = gwp.processInput(null); writer.println(outputLine); // Legge l'input dal socket e lo processa // Se il protocollo ritorna QUIT, esce dal thread while ((inputLine = reader.readLine()) != null) { outputLine = gwp.processInput(inputLine); writer.println(outputLine); if (outputLine.equalsIgnoreCase("QUIT")) break; } writer.close(); reader.close(); socket.close(); } catch (Exception e) { try { socket.close(); } catch (Exception se) { System.out.println("Socket error: " + se); } } } protected void finalize() { counter -= (counter > 0) ? 1 : 0; System.out.println("Thread has died: " + Integer.toString(counter)); } } /** *** *** *** *** *** *** *** *** *** *** ---------------------------------------------------------------- ** GoldenWheel v0.01 (c)2000 by Espeleta Tomas (gwProtocol.java) Emulazione di Roulette Francese. Protocollo di comunicazione (interpreta le richieste del client): 1) autentica l'utente 2) memorizza le scommesse, 3) fa "girare"la ruota, 4) calcola le vincite. 5) restituisce il numero uscito e un array delle vincite al client. (c) 2000 by Espeleta Tomas. *** Scritto per l'esame di "Fondamenti di informatica III" *** Diploma teledidattico in Ingegneria informatica *** email: [email protected] *** www: http://balder.prohosting.com/espeleta *** indirizzo: v. Amendola 9, 31045 Motta di Livenza - (TV) *** *** ---------------------------------------------------------------- */ import import import import import import import java.net.*; java.io.*; java.util.StringTokenizer; bet.manage.Bet; bet.manage.BetStore; bet.manage.BetEncoding; bet.passwd.*; public class gwProtocol { private private private private static static static static final final final final int int int int WAITING = 0; PASSWDREQ = 1; CMDRCV = 2; BETRCV = 3; private int state = WAITING; private int betParam = 0; private int number, j; private private private private private Bet mybet = null; gwDBase myDB; BetStore bets; Passwd passwd; int saldo = 0; public gwProtocol() { myDB = new gwDBase(); bets = new BetStore(myDB); passwd = new Passwd(myDB); } public String processInput(String myInput) { String myOutput = null; int readNumber; // STATO0: Welcome if (state == WAITING) { myOutput = "Welcome to GoldenWheel Server v0.01! Make your bet..."; state = PASSWDREQ; // STATO1: Prima di tutto e' NECESSARIO inserire Username e Passwd // accetto solo il comando: PASSWD <username> <passwd> } else if (state == PASSWDREQ) { if (myInput.startsWith("PASSWD")) { StringTokenizer st = new StringTokenizer(myInput); if (st.countTokens() == 3) { st.nextToken(); String username = st.nextToken(); String pwd = st.nextToken(); StringBuffer s = new StringBuffer(); if (passwd.verify(username, pwd, s)) { state = CMDRCV; myOutput = "OK, welcome " + username + ", " + s; } else { myDB.close(); myOutput = "QUIT"; } // Memorizzo il saldo ottenuto nella variabile "saldo" try { saldo = Integer.parseInt(s.toString()); } catch (NumberFormatException e) { saldo = 0; } } else { state = PASSWDREQ; myOutput = "ERROR: UID/PWD syntax was wrong."; } } else myOutput = "ERROR: Password required!"; // STATO2: Interpreta i comandi accettati } else if (state == CMDRCV) { if (myInput.startsWith("BET")) { state = BETRCV; myOutput = "OK"; } else if (myInput.equals("SPIN")) { number = (int)Math.round(Math.random() * 36); // number = 17; myOutput = Integer.toString(number) + ","; if (bets.size() > 0) { for (j = 0; j < bets.size() - 1; j++) { myOutput += Integer.toString(BetEncoding.decode((Bet)bets.get(j), number)) + ","; } myOutput += Integer.toString(BetEncoding.decode((Bet)bets.get(j), number)); } // Passando il saldo attuale, scrive le variazioni di saldo su DBase e sulla variabile "saldo" saldo = bets.writeIt(number, passwd.getUser(), saldo); // Rimuove tutte le scommesse bets.clear(); } else if (myInput.equalsIgnoreCase("QUIT")) { myDB.close(); myOutput = "QUIT"; // Altrimenti.. restituisce un errore } else { myOutput = "ERROR: Commands accepted: BET, SPIN, QUIT."; } // STATO3: Riceve tre dati per ogni puntata: CLIENTE, CODICE_PUNTATA,CREDITI } else if (state == BETRCV) { try { readNumber = Integer.parseInt(myInput); if (Bet.needNewOne()) mybet = new Bet(); mybet.addvalue(readNumber); myOutput = "OK"; } catch (NumberFormatException e) { mybet.reset(); state = CMDRCV; myOutput = "ERROR: Number format error."; System.out.println(myOutput); } // Se ha terminato di "riempire" l'oggetto scommessa, // lo mette via e torna allo stato "Command receive" if (Bet.ready()) { bets.add(mybet); state = CMDRCV; } } return myOutput; } } /** *** -------------------------------------------------------*** GoldenWheel v0.01 (gwDBase.java) *** Emulazione di Roulette Francese. *** Questo oggetto si occupa di aprire il DBase *** fornisce i due metodi getRs e execute. *** (c)2000 by Espeleta Tomas *** -------------------------------------------------------***/ import java.util.*; import java.sql.*; public class gwDBase { private Connection conn; private Statement st; public ResultSet rs; private void getMyConnection() { String Sistema = System.getProperty("os.name"); // Sotto Windows carico l'ODBC System-DataSource chiamato "mydb" if (Sistema.startsWith("Win")) { try { // Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); // conn = DriverManager.getConnection("jdbc:odbc:mydb"); Class.forName("ORG.as220.tinySQL.textFileDriver").newInstance(); conn = DriverManager.getConnection("jdbc:tinySQL", "", ""); } catch (Exception e) { System.out.println(e); System.exit(1); } // Sotto Unix o altro, cerco di caricare MySql } else { try { // Class.forName("org.gjt.mm.mysql.Driver").newInstance(); // conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1/mydb?user=myusr&password=mypwd"); Class.forName("ORG.as220.tinySQL.textFileDriver").newInstance(); conn = DriverManager.getConnection("jdbc:tinySQL", "", ""); } catch (Exception e) { System.out.println(e); System.exit(1); } } } public gwDBase() { getMyConnection(); try { st = conn.createStatement(); } catch (SQLException e) { System.out.println(e); System.exit(1); } } public ResultSet getRs(String sql) { try { rs = st.executeQuery(sql); } catch (SQLException e) { System.out.println(e); } return rs; } public boolean execute(String sql) { boolean retval = false; try { retval = st.execute(sql); } catch (SQLException e) { System.out.println(e + "(" + sql + ")"); } return retval; } public void close() { try { conn.close(); } catch (Exception ignored) {} } } /* ---------------------------------------** Bet.java ** Oggetto 'scommessa': il protocollo si occupa di riempirlo ** con il dati passati man mano dal client: ** Codice Cliente, Codice Puntata, Crediti giocati. ** ---------------------------------------*/ package bet.manage; public class Bet { private static boolean betready = false; private static boolean needNew = true; private int i = 0; public int CodCliente; public int CodPuntata; public int Credits; public Bet() { needNew = betready = false; } public void reset() { i = 0; betready = false; needNew = true; } public void addvalue(int val) { if (i == 0) { CodCliente = val; i++; } else if (i == 1) { CodPuntata = val; i++; } else if (i == 2) { Credits = val; i = 0; betready = true; needNew = true; } } public static boolean needNewOne() { return needNew; } public static boolean ready() { return betready; } } /* ** ** ** ** ** ** ** ** ** */ -----------------------------------------------------------------BetEncoding.java Contiene il metodo decode(Bet b, int numero_uscito), questo verifica che il numero sia contenuto nella puntata. Restituisce: -1 se non e' una scommessa valida. moltiplicatore se il numero uscito era stato scommesso in b. 0 se il numero uscito non e' stato scommesso. ------------------------------------------------------------------ package bet.manage; public class BetEncoding { static private final int ERROR = -1; static private final int NOMATCH = 0; static private int rossi[] = {1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36}; // numero: numero uscito! // b: scommessa sotto esame static public int decode(Bet b, int numero) { int code = b.CodPuntata; int which = (code / 0x10000); // Prendo i 16 bit piu' significativi int j, n, n1; int retval = NOMATCH; // Moltiplicatore della vincita n = (code & 0x00ff); // Trattiamo a parte lo zero... if (n == 0 && which != 0x01 && which != 0x05) { retval = ERROR; // Puntate non valide } else if (numero == 0) { if (which == 0x05 && n == 0) { // Primi 4 (0,1,2,3) retval = 8; } else if (which == 0x01 && n == 0) { // Pieno retval = 35; } else retval = NOMATCH; // Importante! tutti gli altri casi sono NO match! // Puntata non valida se il n>36 (ovvio!) } else if (n > 36) { retval = ERROR; // Tutte le altre puntate... } else { switch (which) { case 0x01: // Pieno if (n == numero) retval = 35; break; case 0x02: // Cavallo n1 = (code & 0xff00) >> 8; if (n1 > 36) retval = ERROR; if (n == numero || n1 == numero) retval = 17; break; case 0x03: // Terzina if (((n+2) % 3) != 0) retval = ERROR; if (n == numero || (n + 1) == numero || (n + 2) == numero) retval = 11; break; case 0x04: // Quartina if (n > 32 || ((n % 3) == 0)) retval = ERROR; if (numero == n || numero == (n + 1) || numero == (n + 3) || numero == (n + 4) ) retval = 8; break; case 0x05: // Primi 4 (0,1,2,3) retval = NOMATCH; if (numero == 1 || numero == 2 || numero == 3) retval = 8; break; case 0x06: // Due file if (n > 31 || ((n+2) % 3) != 0) retval = ERROR; for (j = 0; j < 6; j++) if (numero == (n + j)) retval = 5; break; case 0x10: // Dozzina if (numero <= 12 && n == 1) retval = 2; if (numero > 12 && numero <= 24 && n == 2) retval = 2; if (numero > 24 && numero <= 36 && n == 3) retval = 2; break; case 0x11: // Colonna if ((numero % 3) == 1 && n == 1) retval = 2; if ((numero % 3) == 2 && n == 2) retval = 2; if ((numero % 3) == 0 && n == 3) retval = 2; break; case 0x20: // Rosso for (j = 0; j < 18; j++) if (numero == rossi[j]) retval = 1; break; case 0x21: // Nero retval = 1; for (j = 0; j < 18; j++) if (numero == rossi[j]) retval = 0; if (numero == 0) retval = 0; break; case 0x22: // Pari if ((numero % 2) == 0) retval = 1; break; case 0x23: // Dispari if ((numero % 2) == 1) retval = 1; break; case 0x24: // 1-18 if (numero < 19) retval = 1; break; case 0x25: // 19-36 if (numero > 18) retval = 1; break; default: retval = -1; } } return (retval * b.Credits); // restituisco la vincita } } /* ** ** ** ** */ ---------------------------------------------------------BetStore.java Estende la classe Vector: Mette via le scommesse su questo vettore speciale che scrive anche sulla tabella di log. ---------------------------------------------------------- package bet.manage; import java.util.Vector; import java.util.Date; import java.text.SimpleDateFormat; import gwDBase; public class BetStore extends Vector { private gwDBase db; public BetStore(gwDBase db) { super(); this.db = db; } // Scrive sul dbase le variazioni al saldo attuale dell'utente // funzione chiamata da public int writeIt(int n, String username, int saldo) { int int int int Bet deltaSaldo = 0; TotScommessa = 0; TotVincita = 0; won; temp = null; // deltaSaldo del casino for (int j = 0; j < size(); j++) { temp = (Bet)get(j); won = BetEncoding.decode(temp, n); //System.out.println("Scommessa : " + Integer.toString(temp.Credits) + ", won: " + won); TotScommessa += temp.Credits; TotVincita += won; if (won == 0) deltaSaldo -= temp.Credits; // il casino vince else deltaSaldo += won; // il casino perde (saldo positivo) } saldo += deltaSaldo; Date d = new Date(System.currentTimeMillis()); SimpleDateFormat f1 = new SimpleDateFormat ("dd/MM/yyyy"); SimpleDateFormat f2 = new SimpleDateFormat ("hh:mm:ss"); db.execute("INSERT INTO logtable (Data, Ora, username, TotScommessa, TotVincita, deltaSaldo) VALUES ('" + f1.format(d) +"','"+ f2.format(d) +"','"+ username +"','"+ Integer.toString(TotScommessa) +"','"+ Integer.toString(TotVincita) +"','"+ Integer.toString(deltaSaldo) + "')"); db.execute("UPDATE passwd SET saldo = '" + Integer.toString(saldo) + "' WHERE username = '" + username + "'"); return saldo; } } /* ** ** ** ** ** ** ** */ ---------------------------------------------------------Passwd.java Oggetto 'password': controlla username e password passati al protocollo dal client. Il costruttore richiede il Dbase dove sono mantenuti i dati per l'autenticazione. Una volta autenticati, mantiene una copia di Username. fornisce i due metodi: verify e getUser. ---------------------------------------------------------- package bet.passwd; import java.sql.*; import gwDBase; public class Passwd { private String username; private gwDBase db; private ResultSet rs; // ---------------------------------------------------------public String getUser() { String retValue = this.username; return retValue; } // ---------------------------------------------------------// verifica che username/password siano validi, scrive in "Saldo" il saldo di tale utente public boolean verify(String username, String passwd, StringBuffer Saldo) { rs = db.getRs("SELECT username, passwd, saldo FROM passwd WHERE username='" + username + "'"); try { if (!rs.next()) { // Username non trovato! this.username = null; System.out.println("User not found!"); } else { int i; byte[] b1 = (new CryptPwd()).crypt(rs.getString("passwd").trim()).getBytes(); byte[] b2 = passwd.getBytes(); for (i = 0; i < b1.length && b1[i] == b2[i]; i++); if (b1.length == b2.length && b2.length == i) { // Username OK! this.username = username; Saldo.append(rs.getString("saldo")); } } } catch (SQLException e) { System.out.println("---->"+e); } return (this.username != null); } // ---------------------------------------------------------public Passwd(gwDBase db) { this.db = db; } } // ---------------------------------------------------------/* -----------------------------------------------** CryptPwd.java ** Fornisce solo un metodo, che cripta la password ** con l'algoritmo standard SHA ** ulteriore livello di sicurezza potrebbe essere ** assicurato da un socket sicuro ** -----------------------------------------------*/ package bet.passwd; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class CryptPwd { private MessageDigest md; // -----------------------------------------------public CryptPwd() { try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { System.out.println(e.toString()); } } // -----------------------------------------------private final String digits = "0123456789ABCDEF"; public String crypt(String toBeCrypted) { StringBuffer result = new StringBuffer(); md.update(toBeCrypted.getBytes()); byte b[] = md.digest(); // Rappresentazione esadecimale della password criptata for (int j = 0; j < b.length; j++) { result.append(digits.charAt((int)(b[j] >> 4) & 0xf)); result.append(digits.charAt((int)(b[j]) & 0xf)); } return result.toString(); } } // ----------------// Add user/password // ----------------import java.util.*; import java.sql.*; class addUser { public static void main(String argv[]) { boolean newtable = false; // flag //System.out.println(Integer.toString(argv.length)); if (argv.length != 3) { if (argv.length == 4 && argv[0].equals("-n")) newtable = true; else { System.out.println("Ohps, syntax error:\n Use: java addUser [-n] <username> <password> <credits>\n -n: creates a new table, REMOVING OLD USERS!"); return; } } try { // Cerchiamo di registrare textFileDriver. Class.forName("ORG.as220.tinySQL.textFileDriver").newInstance(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { System.err.println( "I could not find the tinySQL classes. Did you install\n" + "them as directed in the README file?"); e.printStackTrace(); } try { // Stiamo attenti alle SQLExceptions! // Colleghiamoci al tinySQL Driver. Connection con = DriverManager.getConnection("jdbc:tinySQL", "", ""); // prendiamo un oggetto Statement dalla Connessione Statement stmt = con.createStatement(); // Se c'e' lo switch -n, crea nuova tabella int i = 0; if (newtable) { stmt.executeUpdate("CREATE TABLE passwd (username CHAR(10), passwd CHAR(10), saldo NUMERIC(10))"); System.err.println("Created the passwd table."); stmt.executeUpdate("CREATE TABLE logtable (Data CHAR(10), Ora CHAR(8), username CHAR(10), TotScommessa NUMERIC(10), TotVincita NUMERIC(10), deltaSaldo NUMERIC(10))"); System.err.println("Created the logtable table."); i = 1; } // Insert new user try { stmt.executeUpdate("INSERT INTO passwd (username, passwd, saldo) VALUES('" + argv[0+i] + "', '" + argv[1+i] + "', '" + argv[2+i] +"')"); System.out.println("User added!"); } catch (Exception e) { System.out.println("Some problem adding user: " + e.getMessage()); } stmt.close(); con.close(); } catch( Exception e ) { System.out.println(e.getMessage()); e.printStackTrace(); } } } CLIENT: // // // // // // // // // // // // // ---------------------------------------------------------------Golden-Wheel applet. (roulcli.java) Simulazione della roulette francese. (c)2000 by Espeleta Tomas. Funziona solo se in comunicazione con a pagina web attraverso l'oggetto JSObject. (c) 2000 by Espeleta Tomas. Scritto per l'esame di "Fondamenti di informatica III" Diploma teledidattico in Ingegneria informatica email: [email protected] www: http://balder.prohosting.com/espeleta indirizzo: v. Amendola 9, 31045 Motta di Livenza - (TV) ---------------------------------------------------------------- import com.ms.security.*; import import import import import import import import import java.net.*; java.awt.*; java.awt.image.MemoryImageSource; java.awt.image.PixelGrabber; java.awt.Color; java.applet.Applet; java.applet.AppletContext; java.util.Vector; java.util.StringTokenizer; public class roulcli extends Applet implements Runnable { private final int DELAY = 54; private Thread appletThread; private Image image, ballImg; private Image image2, backImage, tempImg; private Graphics tempG; private MemoryImageSource imgSrc; private int buffer1[], buffer2[]; private int larghezza, altezza; private int appletW, appletH; private int wherex, wherey; private int frame; private int cosNorm[] = new int[360]; private int sinNorm[] = new int[360]; private double angolo, speed; private boolean spinCmd = false; private boolean firstremove = true; // flag per rimuovere una sola volta le chip private String n; // Numero uscito, settato da beginSpin, stampato da aggiornaGraph private Color bgColor; private int winnerNum; // Dati di risposta del server private String wonString; private private private private Pallina pallina; Display display; PwdDisplay pd; gwClient gwc; public Vector bets; // ATTENZIONE! bets deve essere riempito da un altro applet! // ---------------------------------------------------------------public void init() { // Assicura il funzionamento della rete su IE try { if (Class.forName("com.ms.security.PolicyEngine") != null) PolicyEngine.assertPermission(PermissionID.NETIO); } catch (Throwable cnfe) {} // Dimensioni dell'applet appletW = size().width; appletH = size().height; // bgcolor e' il parametro dell'applet per il background try { bgColor = new Color(Integer.parseInt(getParameter("bgcolor"), 16)); } catch (Exception e) { bgColor = Color.white; } // Coloriamo l'applet di bgColor (verde!) Graphics g = getGraphics(); g.setColor(bgColor); g.fillRect(0, 0, appletW, appletH); // Inizializza i suoni della pallina Pallina.initBallSounds(this); // Calcola tabella dei seni e dei coseni calcolaSinCos(); // Crea array delle scommesse e un client GoldenWheel bets = new Vector(30); gwc = new gwClient(getDocumentBase().getHost(), this); // Creo la pallina if ((ballImg = loadImage("images/pallina.gif")) == null) showStatus("Errore nell\'immagine "); // Carico le due immagini della roulette... if ((backImage = loadImage("images/r.jpg")) == null) showStatus("Errore nell\'immagine "); if ((image = loadImage("images/r2.gif")) == null) showStatus("Errore nell\'immagine "); // ... e ne memorizzo le dimensioni larghezza = image.getWidth(this); altezza = image.getHeight(this); // Creo un double-buffer (offscreen) tempImg = createImage(appletW, appletH); tempG = tempImg.getGraphics(); tempG.setColor(bgColor); // Creo i display... quello delle password e' un panel. this.setLayout(new BorderLayout()); display = new Display(tempG, (appletW - 120) / 2, (appletH + backImage.getHeight(this) - 70) / 2, 120, 70); pd = new PwdDisplay(bgColor, gwc); this.add(BorderLayout.SOUTH, pd); // deprecated // Per le animazioni, creo due buffer. Li inizializzo con l'immagine della ruota. buffer1 = new int[larghezza * altezza]; buffer2 = new int[larghezza * altezza]; capturePixels(image, buffer1); imgSrc = new MemoryImageSource(larghezza, altezza, buffer2, 0, larghezza); imgSrc.setAnimated(true); image2 = createImage(imgSrc); imgSrc.newPixels(0, 0, larghezza, altezza, true); } // ---------------------------------------------------------------public void start() { appletThread = new Thread(this); appletThread.setPriority(Thread.NORM_PRIORITY); appletThread.start(); } // ---------------------------------------------------------------public void run() { showStatus("Welcome to GoldenWheel 1.0..."); System.gc(); // Disegno le due immagini della roulette if (backImage != null && image != null) { // (wherex, wherey) e' il centro della roulette wherex = (backImage.getWidth(this) >> 1); wherey = (backImage.getHeight(this) >> 1); tempG.fillRect(0, 0, appletW, appletH); tempG.drawImage(backImage, 0, 0, this); tempG.drawImage(image, 33, 33, this); // Non ci serve piu': la abbiamo in buffer1 ;-) image = null; } // --------------------------------------------// CICLO PRINCIPALE DI ANIMAZIONE // (tm serve a mantenere costante il framerate) long tm = System.currentTimeMillis(); boolean once = true; while (appletThread != null) { // Quando c'e' lo spin, calcola un nuovo angolo if (spinCmd) { angolo = (angolo + speed) % 360; ruota(); // notifica il cambiamento dei pixels... imgSrc.newPixels(0, 0, larghezza, altezza, true); // calcola la nuova posizione della pallina. if (!(pallina.isready())) pallina.nextpos(); // Inizia il suono di rotazione della pallina pallina.changeSound(2); } // Se ci si e' loggati, mostra il display (una volta)... if (gwc.pwdok() && once) { display.paint(); once=false; } // Disegna il nuovo angolo repaint(); // Aspetta il prossimo frame tm += DELAY; delay((int)Math.max(0, tm - System.currentTimeMillis()) ); frame++; // La ruota pian piano si ferma: ogni 38 frame rallenta... if ((speed -= ((frame % 38 == 0) ? 1 : 0)) <= 0) { speed = 0; spinCmd = false; } } } // ---------------------------------------------------------------public void stop() { // Spegni tutti i suoni! 8-) if (pallina != null) pallina.changeSound(0); // Chiudi il client... if (gwc != null) gwc.close(); // ...e annulla il thread. if (appletThread != null) { appletThread = null; backImage = image2 = null; } } // ---------------------------------------------------------------// la coppia paint() - update() permette di eliminare il farfallio // ---------------------------------------------------------------public void paint(Graphics g) { update(g); } public void update(Graphics g) { aggiornaGraph(g); } // ---------------------------------------------------------------// funzione di vero e proprio aggiornamento del tappeto // ---------------------------------------------------------------void aggiornaGraph(Graphics g) { if (spinCmd) { // se ancora c'e' spin... // Disegna background tempG.fillRect(0, 0, appletW, appletH); tempG.drawImage(backImage, 0, 0, null); tempG.drawImage(image2, wherex - (larghezza>>1)-1, wherey - (altezza>>1)-1, null); if (n != null && pallina.isarrived()) { display.setString(n); // Chiama una volta if (firstremove) { firstremove = false; // la funzione di notifica in "tappeto"... // tappeto.removeLostChips(wonString); vedi IAC.TXT getAppletContext().getApplet("sender").getParameter("%removeLostChips%" + wonString); } } else { display.setString(""); } // Disegna display display.paint(); // Disegna pallina if (pallina.isready()) pallina.disegna(tempG, (int)angolo); else pallina.disegna(tempG, wherex, wherey, (int)angolo); } g.drawImage(tempImg, 0, 0, this); } // // // // ---------------------------------------------------------------Calcolo la tabella dei seni e quella dei coseni: Ottengo valori interi perche' li moltiplico per 255 ;-) ---------------------------------------------------------------void calcolaSinCos() { final double SEX2RAD = (2 * Math.PI) / 360; for (int i = 0; i < 360; i++) { cosNorm[i] = (int)(Math.cos(SEX2RAD * (double)i) * 255D); sinNorm[i] = (int)(Math.sin(SEX2RAD * (double)i) * 255D); } } // ---------------------------------------------------------------Image loadImage(String s) { showStatus("Loading images..."); MediaTracker mediatracker = new MediaTracker(this); URL url = null; Image image = null; try { url = new URL(getDocumentBase(), s); } catch(MalformedURLException _ex) { } try { image = getImage(url); mediatracker.addImage(image, 1); mediatracker.waitForID(1); } catch(InterruptedException _ex) { image = null; } if (mediatracker.isErrorID(1)) image = null; return image; } // ---------------------------------------------------------------// Esegue i calcoli su buffer2, ruotando di "angolo". // ---------------------------------------------------------------void ruota() { int cosalfa = cosNorm[359 - (int)angolo]; int sinalfa = sinNorm[359 - (int)angolo]; int lmezzi = larghezza >> 1; int hmezzi = altezza >> 1; // Applico la formula (x1, y1) = (cosalfa*x - sinalfa*y, sinalfa*x+cosalfa*y) // PixelGrabber mette il punto (x,y) in buffer[ for (int y = -hmezzi; y < hmezzi; y++) { int k1 = y * sinalfa >> 8; int l1 = y * cosalfa >> 8; int start = larghezza * (y + hmezzi); for (int x = -lmezzi; x < lmezzi; x++) { int x1 = (x * cosalfa >> 8) - k1; int y1 = (x * sinalfa >> 8) + l1; if (x1 >= -lmezzi && x1 < lmezzi && y1 >= -hmezzi && y1 < hmezzi) buffer2[start + (x + lmezzi)] = buffer1[larghezza * (y1 + hmezzi) + (x1 + lmezzi)]; } } } // ---------------------------------------------------------------// Copia l'immagine data nel buffer // ---------------------------------------------------------------void capturePixels(Image img, int buff[]) { PixelGrabber pg = new PixelGrabber(img, 0, 0, larghezza, altezza, buff, 0, larghezza); try { if (!pg.grabPixels()) { showStatus("Image error"); appletThread = null; } } catch (InterruptedException e) { showStatus("Image error"); appletThread = null; } if ((pg.status() & 0x80) != 0) { showStatus("Image error"); appletThread = null; } } // ----------------------------------------------------------------// Il seguente metodo viene chiamato da Javascript: // (per funzionare su netscape devo fare un catch delle exceptions) // ----------------------------------------------------------------public void beginSpin() { // Non giro la ruota se la password non e' OK. if (!gwc.pwdok()) return; // Mi collego al server... int risultato = -1; String results[] = new String[1]; results[0] = "Error!"; // Creo un collegamento col server (se questo e' giu') if (!gwc.isAlive()) { gwc = new gwClient(getDocumentBase().getHost(), this); } // Passo le scommesse al client GWC e ottengo il risultato if (gwc != null && bets != null) { gwc.setBets(bets); risultato = gwc.bet(results); if (risultato == -1 || results[0].equals("")) n = "Error, " + Integer.toString(risultato); else n = Integer.toString(risultato); } // Memorizzo i risultati winnerNum = risultato; wonString = new String(results[0]); firstremove = true; // flag per rimuovere una sola volta le chip // Creo una pallina che si fermi sul numero ottenuto! ;-) if (risultato != -1) { pallina = null; System.gc(); speed = 10; pallina = new Pallina(ballImg, cosNorm, sinNorm, risultato); pallina.changeSound(1); spinCmd = true; } } // --------------------------------------------------------// Funzione per sapere da fuori (tappeto) se la password e' OK... public boolean pwdok() { return gwc.pwdok(); } // --------------------------------------------------------void delay(int millis) { try { Thread.sleep(millis); } catch (InterruptedException ignored) {} } // --------------------------------------------------------public Insets getInsets() { return new Insets(280,2,2,2); } // --------------------------------------------------------// getParameter: %comando%parametri%separati%da%percentuale // vedi iac.txt public String getParameter(String cmd) { StringTokenizer st = new StringTokenizer(cmd, "%"); if (!cmd.startsWith("%")) return super.getParameter(cmd); try { String s = st.nextToken(); if (s.equals("removeAllElements")) { bets.removeAllElements(); return null; } else if (s.equals("addElement")) { int code = Integer.parseInt(st.nextToken()); int value = Integer.parseInt(st.nextToken()); bets.addElement(new Bet(code, value)); return null; } if (s.equals("pwdok")) { return (new Boolean(pwdok())).toString(); } } catch (Exception ignored) {} return null; } } // // // // // // // // // // // // // ------------------------------------------------------GoldenWheel v1.0 (tappeto.class) Oggetto “tappeto” Applet che ricrea il magico tappeto verde 8-) (c) 2000 by Espeleta Tomas. Scritto per l'esame di "Fondamenti di informatica III" Diploma teledidattico in Ingegneria informatica email: [email protected] www: http://balder.prohosting.com/espeleta indirizzo: v. Amendola 9, 31045 Motta di Livenza - (TV) ------------------------------------------------------- import import import import import import import java.applet.Applet; java.applet.AppletContext; java.awt.*; java.util.Random; java.util.Vector; java.util.StringTokenizer; netscape.javascript.JSObject; public class tappeto extends Applet implements Runnable { private private private private private private private private e' nuova private private private scommesse private Dimension dimensioni; // dimensioni dell'Applet Thread myself; // Thread MediaTracker trk; // per caricare le immagini Graphics tempG; // Doppio buffer Image tappetoImg, tempImg; // Immagini Image chip1Img, chip5Img, chip10Img, chip25Img; boolean inizializzato; // Flag di inizializzazione boolean newbet; // Flag: la chip appena rilasciata sul tappeto, Font mainfont; Color bgColor; Vector Chips; // Font dei messaggi // Colore: impostare col parametro bgColor // il vero e proprio tappeto... memorizza le Chip newChip; // Oggetto chip per le fiches temporanee protected roulcli externo; public JSObject win; String pippo = ""; int xClick, yClick; int newx, newy; int chipidx = -1; int CREDITI = 0; // Griglia di int[] tabX 263, 282, 298, int[] tabY tutte le coordinate dei numeri e degli incroci possibili = new int[] {40, 57, 75, 91, 109, 126, 144, 160, 178, 195, 213, 229, 247, 316, 332, 351, 367, 385, 401, 420, 436, 473, 20 }; = new int[] {21, 34, 52, 66, 82, 98, 114, 126, 152 }; static final int XCHIP1 = 180; static final int XSTEP = 30; static final int YCHIPS = 180; // -------------------------------------------------public void init() { super.init(); dimensioni = size(); trk = new MediaTracker(this); // Inizializza bgColor try { //pippo = Integer.toHexString(Color.decode(getParameter("bgcolor")).getRGB()); bgColor = new Color(Integer.parseInt(getParameter("bgcolor"), 16)); } catch (Exception e) { bgColor = Color.green; } setBackground(bgColor); // Creo un double-buffer (offscreen) tempImg = createImage(dimensioni.width, dimensioni.height); tempG = tempImg.getGraphics(); tempG.setColor(bgColor); // Oggetto per scrivere i crediti nella pag. HTML ;-) win = JSObject.getWindow(this); } // -------------------------------------------------void delay(int millis) { try { Thread.sleep(millis); } catch (InterruptedException ignored) {} } // -------------------------------------------------public void run() { start(); repaint(); while (myself != null) { repaint(); delay(30); } } // -------------------------------------------------public void start() { // Trasforma l'applet in un thread if (myself == null) { myself = new Thread(this); myself.start(); } } // -------------------------------------------------public void stop() { if (myself != null) myself = null; } // -------------------------------------------------// la coppia paint() - update() // permette di eliminare il farfallio public void update(Graphics g) { aggiornaGraph(g); } public void paint(Graphics g) { update(g); } // ---------------------------------------------------------------private void loadImages() { tappetoImg = getImage(getCodeBase(), "images/tappeto.jpg"); trk.addImage(tappetoImg, 1); chip1Img = getImage(getCodeBase(), "images/chip1.gif"); trk.addImage(chip1Img, 2); chip5Img = getImage(getCodeBase(), "images/chip5.gif"); trk.addImage(chip5Img, 3); chip10Img = getImage(getCodeBase(), "images/chip10.gif"); trk.addImage(chip10Img, 4); chip25Img = getImage(getCodeBase(), "images/chip25.gif"); trk.addImage(chip25Img, 5); try { trk.waitForAll(); } catch(InterruptedException ignored) {} inizializzato = true; } // -------------------------------------------------// Funzione che decide SE e DOVE piazzare la chip: (x,y) e' // il punto dove viene rilasciata la chip. (newx, newy) il nuovo punto public boolean place(int x, int y) { int i, j; // Due aree fuori dall'area di puntata valida if (y > 170) return false; if (x < 40 && y > 124) return false; // Cerco a quale punto della griglia si avvicina di piu' // la chip che voglio posizionare. for (i = 1; i < 24 && x > tabX[i]; i++); for (j = 1; j < 8 && y > tabY[j]; j++); // Imposto le nuove coordinate (prendo la distanza minore) newx = ((x - tabX[i-1]) < (tabX[i] - x)) ? i - 1 : i; newy = ((y - tabY[j-1]) < (tabY[j] - y)) ? j - 1 : j; // Non tutta la griglia e' valida! if (newx == 24) { // Colonne if (newy == 0) newy = 1; if (newy == 6) newy = 5; if (newy > 6) return false; } else if (newy == 7) { // 1st, 2nd, 3rd if (x < tabX[8]) { newx = 4; } else if (x < tabX[16]) { newx = 12; } else if (newx < 24) { newx = 20; } } else if (newy == 8) { // 1-18 Even red black Odd 19-36 if (x < tabX[4]) { newx = 2; } else if (x < tabX[8]) { newx = 6; } else if (x < tabX[12]) { newx = 10; } else if (x < tabX[16]) { newx = 14; } else if (x < tabX[20]) { newx = 18; } else if (newx < 24) { newx = 22; } } else if (newx == 0) { if (newy > 0 && newy < 6) { if (x < tabX[0]) { // Zero newx = 25; newy = 3; } else newx = 1; // prima traversa } } return true; } // -------------------------------------------------public void paintChip(Chip mychip, Graphics g) { if (mychip.value == 1) tempG.drawImage(chip1Img, mychip.xPos, mychip.yPos, null); if (mychip.value == 5) tempG.drawImage(chip5Img, mychip.xPos, mychip.yPos, null); if (mychip.value == 10) tempG.drawImage(chip10Img, mychip.xPos, mychip.yPos, null); if (mychip.value == 25) tempG.drawImage(chip25Img, mychip.xPos, mychip.yPos, null); } // -------------------------------------------------public void aggiornaGraph(Graphics g) { if (!inizializzato) { g.setFont(mainfont); g.setColor(Color.white); g.drawString("Sto caricando le immagini...", 15, dimensioni.height/2); loadImages(); return; } tempG.setColor(bgColor); tempG.fillRect(0, 0, dimensioni.width, dimensioni.height); tempG.drawImage(tappetoImg, 0, 0, null); tempG.drawImage(chip1Img, XCHIP1, YCHIPS, null); tempG.drawImage(chip5Img, XCHIP1 + XSTEP, YCHIPS, null); tempG.drawImage(chip10Img, XCHIP1 + XSTEP * 2, YCHIPS, null); tempG.drawImage(chip25Img, XCHIP1 + XSTEP * 3, YCHIPS, null); tempG.setColor(Color.white); tempG.drawString(pippo, 20, 10); /* for (int i = 0; i < Chips.size(); i++) { tempG.setColor(Color.white); tempG.drawString(Integer.toString(((Chip)Chips.elementAt(i)).value), 20, 40+10*i); } */ for (int i = 0; i < Chips.size(); i++) paintChip((Chip)Chips.elementAt(i), tempG); if (newChip != null) paintChip(newChip, tempG); g.drawImage(tempImg, 0, 0, this); } // --------------------------------------------------------// Rimuove le chip perse e ritorna i crediti aggiornati // ** Funzione chiamata al momento giusto da roulcli. public void removeLostChips(String risultati) { int won, removed=0; StringTokenizer st = new StringTokenizer(risultati, ","); try { for (int i = 0; st.hasMoreTokens(); i++) { won = Integer.parseInt(st.nextToken()); if (won > 0) { // Vinto! CREDITI += won; } else if (won == 0) { // Perso! Chips.removeElementAt(i-removed); removed++; } } } catch (Exception e) { pippo = "Exception Removing chip!" + e.toString(); } // ... e la funzione di notifica nella pag HTML win.call("updatebank", null); } // --------------------------------------------------------// ** Funzione chiamata da Javascript per sapere se c'e' qualche chip scommessa public boolean anyBet() { chips2bets(); // riempio il Vector di scommesse return (Chips.size() > 0); } // --------------------------------------------------------public void chips2bets() { // Inizializza l'applet getApplet(), non faccio un cast a roulcli // perche' getApplet su Netscape non ritorna un oggetto corretto... // si vedano le note sulla comunicazione fra applet (iac.txt) Applet roulApplet = getAppletContext().getApplet("receiver"); // IMPORTANTE: riempio il vector bets dell'applet "roulcli" Chip mychip; // Rimuove tutte le scommesse: VEDI IAC.TXT // roulApplet.bets.removeAllElements(); roulApplet.getParameter("%removeAllElements%"); for (int i = 0; i < Chips.size(); i++) { mychip = (Chip)Chips.elementAt(i); // roulApplet.bets.addElement(new Bet(mychip.code, mychip.value)); roulApplet.getParameter("%addElement%" + Integer.toString(mychip.code) + "%" + Integer.toString(mychip.value)); } } // --------------------------------------------------------// setCredits: chiamata da gwClient per impostare i crediti dell'utente public void setCredits(int credits) { CREDITI = credits; win.call("updatebank", null); } // ------------------------------------------------------------// Il seguente metodo viene chiamato da Javascript: // ------------------------------------------------------------public String getCredits() { return Integer.toString(CREDITI); } // -------------------------------------------------// CONTROLLO DEL DRAG AND DROP // -------------------------------------------------- public boolean mouseDown(Event event, int i, int j) { newbet = false; xClick = i; yClick = j; // Inizializza l'applet roulcli x comunicazioni fre i due applet Applet roulApplet = getAppletContext().getApplet("receiver"); if (roulApplet.getParameter("%pwdok%").equals("false")) { return true; } if (yClick > YCHIPS && yClick < YCHIPS + 20) { if (newChip == null) newChip = new Chip(); newChip.xPos = xClick - 10; newChip.yPos = yClick - 10; if (xClick > XCHIP1 && xClick < XCHIP1 + 20) { newChip.value = 1; } else if (xClick > XCHIP1 + XSTEP && xClick < XCHIP1 + XSTEP + 20) { newChip.value = 5; } else if (xClick > XCHIP1 + XSTEP * 2 && xClick < XCHIP1 + XSTEP * 2 + 20) { newChip.value = 10; } else if (xClick > XCHIP1 + XSTEP * 3 && xClick < XCHIP1 + XSTEP * 3 + 20) { newChip.value = 25; } else newChip = null; if (newChip != null) newbet = true; } // Controlla se viene premuto su qualche chip // gia' presente sul tavolo for (int k = 0; k < Chips.size(); k++) { Chip myChip = (Chip)Chips.elementAt(k); if (xClick > myChip.xPos && xClick < myChip.xPos + 20) if (yClick > myChip.yPos && yClick < myChip.yPos + 20) { newChip = myChip; // Copia il puntatore e... chipidx = k; // memorizza l'indice della chip presa } } repaint(); return true; } // -------------------------------------------------public boolean mouseDrag(Event event, int i, int j) { if (newChip == null) return true; if (newChip.value > 0) { // chip presa! newChip.xPos = i - 10; newChip.yPos = j - 10; } repaint(); return true; } // -------------------------------------------------public boolean mouseUp(Event event, int i, int j) { try { if (newChip != null) { // Se la chip viene piazzata con successo if (place(i, j)) { //showStatus(Integer.toString(newx)+ "," + Integer.toString(newy)); //pippo = Integer.toString(newChip.code); newChip.xPos = tabX[newx] - 10; newChip.yPos = tabY[newy] - 10; newChip.code = codifica(newx, newy); if (chipidx == -1) { // ADD CHIP (SE NON GIA' MEMORIZZATA) Chips.addElement(newChip); } // rimuove il valore della chip dai CREDITI if (newbet) CREDITI -= newChip.value; // Altrimenti se era gia' memorizzata, la cancello dal Vector... // e riaggiunge il valore della chip ai CREDITI } else if (chipidx != -1) { CREDITI += newChip.value; Chips.removeElementAt(chipidx); } } win.call("updatebank", null); // Aggiorna tabellone CREDITI chipidx = -1; newChip = null; } catch (Exception e) {pippo = e.toString(); } repaint(); return true; } // -------------------------------------------------public tappeto() { inizializzato = false; mainfont = new Font("Helvetica", 1, 16); Chips = new Vector(); } // -------------------------------------------------public int codifica(int x, int y) { int n = 0; // X Dispari: spazi vuoti if ((x % 2) == 1) { // Numeri if ((y % 2) == 1) { // y dispari n = 2+(3*x-y)/2; n = (0x1 << 16) + n; } // Cavalli sulle righe orizz. if (y == 2 || y == 4) { // y = 2 o 4 n = (3+3*x-y)/2; n = (0x2 << 16) + (n<<8) + (n+1); } // Traverse if (y == 0 || y == 6) { // x dispari, y = 0,6 n = (3*(x-1))/2 + 1; n = (0x3 << 16) + n; } // X Pari: linee } else { // Cavalli sulle righe vert. if (y == 1 || y == 3 || y == 5) { // x pari, y =1,3,5 n = (1+3*x-y)/2; n = (0x2 << 16) + (n<<8) + (n+3); } // Angoli if (y == 2 || y == 4) { // x pari, y = 2 o 4 n = (3*x-y)/2; n = (0x4 << 16) + n; } // Traverse Doppie if (y == 0 || y == 6) { // x pari, y = 0,6 n = (3*(x-1))/2; n = (0x6 << 16) + n; } } // Colonne if (x == 24) { if ((y % 2) == 1) { // x=24, y dispari n = 3 - (y-1)/2; n = (0x11 << 16) + n; } } // Primi quattro numeri if (x == 0) n = (0x5 << 16); // Zero if (x == 25) n = (0x1 << 16); // Scommesse in basso: if (y == 7) { // 1st dozen if (x == 4) { n = (0x10 << 16) + 1; // 2nd dozen } else if (x == 12) { n = (0x10 << 16) + 2; // 3rd dozen } else if (x == 20) { n = (0x10 << 16) + 3; } } else if (y == 8) { // 1-18 if (x == 2) { n = (0x24 << 16) + // Pari } else if (x == 6) { n = (0x22 << 16) + // Rosso } else if (x == 10) { n = (0x20 << 16) + // Nero } else if (x == 14) { n = (0x21 << 16) + // Dispari } else if (x == 18) { n = (0x23 << 16) + // 19-36 } else if (x == 22) { n = (0x25 << 16) + } } 1; 1; 1; 1; 1; 1; return n; } // -------------------------------------------------// getParameter: %comando%parametri%separati%da%percentuale // vedi iac.txt public String getParameter(String cmd) { StringTokenizer st = new StringTokenizer(cmd, "%"); if (!cmd.startsWith("%")) return super.getParameter(cmd); try { String s = st.nextToken(); if (s.equals("removeLostChips")) { removeLostChips(st.nextToken()); return null; } else if (s.equals("setCredits")) { setCredits(Integer.parseInt(st.nextToken())); return null; } } catch (Exception e) { pippo = "Exception executing command!" + e.toString(); } return null; } } // // // // // // // // ---------------------------------------------------------------PwdDisplay.java Display dove viene richiesto username e password. Si tratta di un'estensione dell'oggetto Panel. Su una griglia 3x2 vengono poste due label, due TextField, un bottone. c'e' uun overload di processActionEvent per gestire il bottone 'OK'. ---------------------------------------------------------------- import import import import java.awt.*; java.awt.event.*; java.applet.Applet; java.applet.AppletContext; class PwdDisplay extends Panel { private private private private Font myFont; Color bgColor, backupCol; Label lb1, lb2, lb3; myButton bt3; protected TextField tf1, tf2; public PwdDisplay(Color bgc, gwClient gwc) { GridLayout g = new GridLayout(3,2); setLayout(g); setForeground(Color.white); setBackground(bgc); lb1 = new Label("Username:"); lb2 = new Label("Password:"); lb3 = new Label(""); tf1 = new TextField("", 10); tf2 = new TextField("", 10); bt3 = new myButton(" OK ", gwc, this); add(lb1); add(tf1); add(lb2); add(tf2); add(lb3); add(bt3); show(); // deprecated reshape(40, 270, 200, 80); // deprecated } } // Il bottone e' di tipo "selfbutton", gestisce cioe' in modo // autonomo l'evento ActionEvent. class myButton extends Button { private gwClient client; private TextField u, p; private PwdDisplay owner; public myButton (String label, gwClient client, PwdDisplay owner) { super(label); //enableEvents(AWTEvent.ACTION_EVENT_MASK); this.owner = owner; this.client = client; this.u = owner.tf1; this.p = owner.tf2; } public boolean action(Event e, Object what) { // super.processActionEvent(e); if (client.isAlive()) { if (client.logon(u.getText(), p.getText())) { try { Applet t = ((Applet)getParent().getParent()).getAppletContext().getApplet("sender"); owner.hide(); // Nascondi // vedi IAC.TXT t.getParameter("%setCredits%" + Integer.toString(client.getSaldo())); } catch (Exception ex) { setLabel("ARGH"); } } } return true; } } // // // // ---------------------------------------------------------------Pallina.java Questo oggetto crea, disegna e cambia i suoni della pallina ---------------------------------------------------------------- import import import import java.awt.Color; java.awt.Image; java.awt.Graphics; java.applet.AudioClip; class Pallina extends Object { private private private private private private final final final final final final double NUMBER_ANGLE = 360D/37; int MAX_RADIUS = 104; int MIN_RADIUS = 24; int FINAL_RADIUS = 64; int TEMPO = 3000; int SPEED = 21; // // // // // // Angolo di un numero sulla ruota Raggio massimo (quello di partenza) Raggio minimo Raggio delle caselle dei numeri gradi dopo cui calare velocita' velocita' pallina (gradi/frame) private Image palla; private int x, y, w, h, cx, cy; private int t, alfa, r; private int myspeed; private boolean ready; private boolean arrived; private boolean endSoundStarted; private int numbers[] = new int[] {17,25,2,21,4,19,15,32,0,26,3,35,12,28,7,29,18,22,9,31,14,20,1,33,16,24,5,10,23,8,30,11,3 6,13,27,6,34,17,25}; public static AudioClip rotSound, endSound; // Numero che deve uscire! ;-) private int n; // Puntatori locali alle tabelle sinNorm e cosNorm private int coseni[], seni[]; // ------------------------------------------------------------- // // // // I due seguenti metodi servono a disegnare la pallina su Graphics g A seconda che la pallina stia girando o sia "pronta" a cadere sul numero giusto, l'applet chiama il primo o il secondo metodo. ------------------------------------------------------------public void disegna(Graphics g, int centerx, int centery, int angolo) { cx = centerx; cy = centery; g.drawImage(palla, cx + x, cy + y, null); } // ----------------------------------------------public void disegna(Graphics g, int angolo) { int newx, newy; double a = 6D; // Calcola newx e newy, coordinate del numero uscito! for (int i = 0; i < 37 && n != numbers[i]; i++) a += NUMBER_ANGLE; newx = ((FINAL_RADIUS * coseni[(angolo + 359 - (int)a) % 360]) >> 8) - w; newy = ((FINAL_RADIUS * seni[(angolo + 359 - (int)a) % 360]) >> 8) - h; if (arrived || distance(x, y, newx, newy) < 12) { arrived = true; x = newx; y = newy; changeSound(3); } else { myspeed = 2; nextpos(); } g.drawImage(palla, cx + x, cy + y, null); } // ------------------------------------------------------------public boolean isready() { return ready; } // ------------------------------------------------------------public boolean isarrived() { return arrived; } // ------------------------------------------------------------public void nextpos() { t += myspeed; alfa = (alfa + myspeed) % 360; x = ((r * coseni[359-alfa]) >> 8) - w; y = ((r * seni[359-alfa]) >> 8) - h; if (t > TEMPO && r > FINAL_RADIUS) { // Dopo 8 giri, cala il raggio e la velocita' int decremento1 = ((t % 3) == 0) ? 2 : 0; int decremento2 = ((t % 10) == 0) ? 2 : 0; r -= decremento1; if (myspeed > 4) myspeed -= decremento2; } if (r <= FINAL_RADIUS) ready = true; } // ------------------------------------------------------------public void changeSound(int status) { if (status == 0) { // Stop! rotSound.stop(); endSound.stop(); } else if (status == 1) { // At the beginning... rotSound.stop(); rotSound.loop(); } else if (status == 2) { // While looping... if (r < FINAL_RADIUS + 8) { rotSound.stop(); if (!endSoundStarted) { endSound.loop(); endSoundStarted = true; } } } else if (status == 3) { // Ball stops. endSound.stop(); } } // ------------------------------------------------------------private int distance(int x1, int y1, int x2, int y2) { return (int)(Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))); } // ------------------------------------------------------------public Pallina(Image p, int[] c, int[] s, int n) { super(); this.n = n; this.palla = p; this.coseni = c; this.seni = s; this.w = (p.getWidth(null) >> 1); this.h = (p.getHeight(null) >> 1); this.r = MAX_RADIUS; this.myspeed = SPEED; this.ready = false; this.arrived = false; this.endSoundStarted = false; } // ------------------------------------------------------------// ***** Metodo Statico che carica i suoni della pallina ***** // ------------------------------------------------------------public static void initBallSounds(roulcli owner) { rotSound = owner.getAudioClip(owner.getCodeBase(), "audio/bspin.au"); endSound = owner.getAudioClip(owner.getCodeBase(), "audio/bstop.au"); } // ------------------------------------------------------------} // // // // // // // // // // --------------------------------------------------------------------GoldenWheel Client (c)2000 by Espeleta Tomas (gwClient.java) Oggetto che si occupa della comunicazione con il server, alla creazione si occupa di attivare un socket tramite la classe "Client" fornisce vari metodi: logon: permette l'autenticazione dell'utente setBets: imposta un riferimento locale al vettore di scommesse bet: comunica la scommessa al server. pwdok: restituisce true se ci si e' loggati con successo. --------------------------------------------------------------------- import import import import import java.io.*; java.net.*; java.util.Vector; java.awt.Color; java.awt.Graphics; public class gwClient { private final int OK = 1; private final int ERROR = 2; private private private private private private private private private private private roulcli caller; Vector bets; Client client; BufferedReader reader; PrintWriter writer; String welcome; String response; String servername; int numero, vincita; boolean logged; boolean alive; private String username, passwd; private String ID; private int saldo; // ---------------------------------------------------------------private void delay(int ms) { try { Thread.sleep(ms); } catch (Exception ignored) {} } // ---------------------------------------------------------------private void myError(String message) { caller.showStatus(message); } // ---------------------------------------------------------------private void makeConnection() { client = new Client(servername, 8001); try { reader = new BufferedReader (new InputStreamReader (client.in)); writer = new PrintWriter (new OutputStreamWriter (client.out), true); // WriteServer welcome string welcome = reader.readLine(); alive = true; } catch (IOException e) { myError("Error initializing connection..."); alive = false; } logged = false; } // ---------------------------------------------------------------// Funzione unidirezionale per crittografare la password: MD5 static private final String digits = "0123456789ABCDEF"; static private String crypt(String s) { MD5 md = new MD5(); StringBuffer result = new StringBuffer(); md.update(s.getBytes()); byte[] b = md.digest(); // Rappresentazione esadecimale della password criptata for (int j = 0; j < b.length; j++) { result.append(digits.charAt((int)(b[j] >> 4) & 0xf)); result.append(digits.charAt((int)(b[j]) & 0xf)); } return result.toString(); } // ---------------------------------------------------------------public gwClient(String servername, roulcli caller) { this.caller = caller; this.servername = servername; makeConnection(); username = ""; passwd = ""; // Inizializzo un ID casuale, che servira' ad identificare la sessione ID = Integer.toString((int)(Math.random()*100)+100); } // ---------------------------------------------------------------public void setBets(Vector bets) { this.bets = bets; } // ---------------------------------------------------------------// Registra la scommessa e lancia la pallina. // Restituisce il numero uscito e in risultati i moltiplicatori delle vincite. public int bet(String[] risultato) { int status = OK; int retval = -1; int k = -1; try { for (int i = 0; i < bets.size() && status != ERROR; i++) { // Sends command BET if (status == OK) { writer.println("BET"); response = reader.readLine(); if (!response.startsWith("OK")) status = ERROR; delay(5); } // Sends ID if (status == OK) { writer.println(ID); response = reader.readLine(); if (!response.startsWith("OK")) status = ERROR; delay(5); } // Sends bet code if (status == OK) { writer.println(Integer.toString(((Bet)(bets.elementAt(i))).code)); // Rouge response = reader.readLine(); if (!response.startsWith("OK")) status = ERROR; delay(5); } // Sends bet credits amount if (status == OK) { writer.println(Integer.toString(((Bet)(bets.elementAt(i))).credits)); response = reader.readLine(); if (!response.startsWith("OK")) status = ERROR; delay(5); } } if (status != OK) { myError("Error sending your bets..."); close(); } else { // Sending command SPIN writer.println("SPIN"); response = reader.readLine(); } } catch (Exception e) { myError("Exception detected while sending bets." + e); response = null; } if (response != null) k = response.indexOf(','); if (k != -1) { retval = Integer.parseInt(response.substring(0, k)); risultato[0] = new String(response.substring(k+1, response.length())); } else { retval = -1; risultato[0] = "Error!"; } return retval; } // ---------------------------------------------------------------public void close() { try { client.kill(); alive = false; } catch (Throwable ignored) {} } // ---------------------------------------------------------------public boolean isAlive() { return alive; } // ---------------------------------------------------------------public boolean logon(String usr, String pwd) { username = usr; passwd = crypt(pwd); try { if (!logged) { writer.println("PASSWD " + username + " " + passwd); response = reader.readLine(); if (response.startsWith("OK")) { logged = true; try { saldo = Integer.parseInt(response.substring(response.lastIndexOf(',')+2, response.length())); } catch (NumberFormatException e) { saldo = 0; } myError("User " + usr + ": Welcome! "); } else { // Il server butta giu' la connessione!! myError("User " + usr + " not accepted..."); // ... quindi la ripristino makeConnection(); } delay(5); } } catch (Exception e) { myError("Exception detected while sending password." + passwd); response = null; } return logged; } // ---------------------------------------------------------------public boolean pwdok() { return logged; } // ---------------------------------------------------------------public int getSaldo() { return saldo; } // ---------------------------------------------------------------- } //------------------------------------------------------------------// Client.java // usato da gwClient, semplicemente APRE il socket e fornisce // due stream di I/O (“in” e “out”) //------------------------------------------------------------------import java.io.*; import java.net.*; //------------------------------------------------------------------public class Client { public InputStream in; public OutputStream out; // Il socket rimane privato... private Socket client; //------------------------------------------------------------------public Client(String host, int port) { try { client = new Socket(host, port); in = client.getInputStream(); out = client.getOutputStream(); } catch (Exception e) { System.out.println("IOExc : " + e); } } //------------------------------------------------------------------public void kill() throws Throwable { try { client.close(); super.finalize(); } catch (Exception ignored) { } } } // // // // // // // // ---------------------------------------------------------------Display.java Display dove viene visualizzato il numero uscito Ha bisogno dell' oggetto Graphics su cui scrivere... fornisce i seguenti metodi: setString: Imposta la stringa da visualizzare paint: Disegna il display, nero con bordo giallo. ---------------------------------------------------------------- import import import import java.awt.Graphics; java.awt.Color; java.awt.Font; java.awt.FontMetrics; class Display { static private int rossi[] = {1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36}; private private private private private private String contenuto; Color bgColor, fgColor, backupCol; Graphics g; Font myFont; FontMetrics misura; int left, top, w, h, sw; // ---------------------------------------------------------------public Display(Graphics myG, int left, int top, int w, int h) { bgColor = Color.black; fgColor = Color.white; backupCol = myG.getColor(); myFont = new Font("SansSerif", Font.BOLD, h/5); myG.setFont(myFont); misura = myG.getFontMetrics(); setString("Make your bet!"); this.g = myG; this.left = left; this.top = top; this.w = w; this.h = h; } // ---------------------------------------------------------------public void setString(String s) { int num; contenuto = s; fgColor = Color.white; try { num = Integer.parseInt(s); if (num == 0) fgColor = Color.green; for (int i = 0; i < rossi.length; i++) if (num == rossi[i]) fgColor = Color.red; if (myFont.getSize() < h/2) { myFont = new Font("SansSerif", Font.BOLD, h/2); g.setFont(myFont); misura = g.getFontMetrics(); } } catch (NumberFormatException ignored) {} sw = misura.stringWidth(s); } // ---------------------------------------------------------------public void paint() { g.setColor(bgColor); g.fillRect(left, top, w, h); // Costruisco un bordo giallo oro. g.setColor(new Color(0xa0a030)); for (int b = 0; b < 3; b++) g.drawRect(left + b, top + b, w - b*2, h - b*2); // Scritta g.setColor(fgColor); g.drawString(contenuto, left + (w - sw) / 2, top + h/2 + misura.getHeight()/3); g.setColor(backupCol); } } // // // // ---------------------------------------------------------------Chip.java (chiamata da tappeto.java) Implementa una fiche come immagine con una POSIZIONE e un VALORE ---------------------------------------------------------------- public class Chip { public public public public int int int int Chip() {} } xPos; yPos; code; value; // Posizione sul tappeto // Codice scommessa di questa chip // Valore in crediti ($, dollari o migliaia di lire...) // ---------------------------------------------------------------public class Bet { public int code; public int credits; public Bet(int code, int credits) { this.code = code; this.credits = credits; } public Bet() { } } // ----------------------------------------------------------------