martedì 26 novembre 2013

Gnome Launcher Creator, piccola utility per creare lanciatori per GNOME

Ho scritto in giornata questa piccola utility che permette di creare dei lanciatori per GNOME in maniera facile, appoggiandosi all'utility per GNOME gnome-desktop-item-edit.

Potete scaricare il sorgente da QUI oppure (e cio è molto triste perché ricorda windows) scaricare direttamente l'eseguibile da QUI.  Se lo dovete compilare assicuratevi di avere installato il pacchetto libgtk-3-dev necessario per le librerie GTK+,  e se avete configurato anche pkg-config, vi basta eseguire da terminale il comando

make 

sulla cartella contenente il file Makefile per compilare direttamente e creare l'eseguibile GLC.

lunedì 18 novembre 2013

Calcolare il determinante di una matrice di qualsiasi ordine in maniera ricorsiva - Software grafico GNU/Linux

Come avevo promesso, ecco la versione GNU/Linux del programma grafico per calcolare il determinante che ho presentato nel precedente post (a dir la verità ci ho fatto qualche lieve modifica)


A differenza della versione per Windows, su Linux con molta probabilità avrete già le librerie installate sul sistema, quindi ecco a voi solo l'eseguibile (per versioni di GTK > 3.0):


martedì 12 novembre 2013

Calcolare il determinante di una matrice di qualsiasi ordine in maniera ricorsiva - Software grafico Windows

Tempo fa ho scritto un post che descriveva il metodo per calcolare il determinante di una matrice in maniera ricorsiva (metodo di Laplace) e mostravo la funzione creata per C++ per calcolare il determinante data una matrice quadrata di un qualsiasi ordine. 

Ho creato un'interfaccia grafica scritta con GTK+ dove si può comodamente inserire la matrice di cui si vuole calcolare il determinante. Per ora il programma è compilato con windows perché in questo momento non ho un linux a portata di mano, quindi l'eseguibile che potrete scaricare è per windows. 

Il programma inizia con un prompt, chiedendo all'utente di inserire l'ordine della matrice:
subito dopo, inserendo un ordine di 3 per esempio, avremo la schermata:

in cui potremmo inserire i valori e calcolare il determinante:

Il programma non è limitato a un certo ordine, teoricamente si può inserire qualsiasi ordine, salvo tempi che si allungano per via dell'elaborazione prima della parte grafica, poi (più veloce) la parte computazionale. I problemi derivati dall'uso di GTK+ su windows è che queste librerie sono nate in ambiente linux, e il porting per windows è complesso e macchinoso rispetto altre librerie grafiche. Ma io sono affezionato a Ubuntu e Gnome :)

Lo potete scaricare da qui (windows):
Istruzioni:
estraete i files in una cartella e lanciate "Determinante.bat", il quale lancerà a sua volta "Determinante.exe" contenuto nella cartella "lib". Ho dovuto fare questo trucchetto perché il programma per funzionare ha bisogno delle librerie GTK+.

A breve anche la versione per linux.

lunedì 11 novembre 2013

Aggiornamento per Memory, gioco in javascript

Ieri ho scritto questo giochino in Javascript:
http://newbufferedwriter.blogspot.com/2013/11/memory-gioco-mnemonico-che-ho-scritto.html

oggi vi ho applicato un piccolo aggiornamento, ovvero invece di vedere i simboli delle lettere, vedere delle immagini. Le modifiche allo script sono state minime, le uniche funzioni che ho modificato sono nuovoGioco(), mostraSimbolo() e una modifica minore in clickTo(). Mentre prima erano delle semplici lettere racchiuse fra i tag <th> della tabella, adesso sono delle immagini, ovvero degli oggetti che devono essere mostrati all'utente creano un nuovo tag (DOM Element in Javascript) di nome "img", e applicarvi un attributo "src" per la sorgente dell'immagine (nome del file). In linea di massima sarebbe possibile fare un confronto tra le immagini per vedere se sono uguali solamente tramite "src", ma ho preferito aggiungere un altro attributo "name" affinché un'immagine abbia un nome univoco. Così i confronti vengono fatti tramite questo attributo. Riporto le funzioni aggiornate, poi tutto rimane uguale:

function nuovoGioco(){
  array  = new Array();
  caselle_aperte=new Array();
  var array_simboli= new Array();
  for (i=0;i<8;i++){
      var image = new Image();
      image.src=(i+1).toString()+".png";
      image.name=(i+1).toString();
      array_simboli[i] = image;
  }
  var simbolo;
  //Cancello la tabella
  for (i=1;i<=4;i++)
     for(c=1;c<=4;c++) {
        riga = Math.floor(i/4)+1;
        colonna = i-((riga-1)*4);
        document.getElementById(i.toString()+c.toString()).innerHTML="*";
        document.getElementById(i.toString()+c.toString()).setAttribute("style","background-color:white;");
     }
  //Preparo l'array
  var pos1,pos2;
  for (i=0;i<8;i++){
   while(array[pos1]!=null)
       pos1=Math.floor((Math.random()*16));
   array[pos1]=array_simboli[i];
   while(array[pos2]!=null)
       pos2=Math.floor((Math.random()*16));
   array[pos2]=array_simboli[i];
   }
   //Correggo bug
   for (i=0;i<16;i++)
     if (array[i]==null){
         var img = new Image();
         img.src = "1.png";
         img.name = "1";
         array[i]= img;
         break;
     }
}
function mostraSimbolo(riga,colonna){
   document.getElementById(riga.toString()+colonna.toString()).innerHTML="";
   var node = document.createElement("IMG");
   node.setAttribute("src",array[((riga-1)*4)+colonna-1].src);
   node.setAttribute("name",array[((riga-1)*4)+colonna-1].name);
   document.getElementById(riga.toString()+colonna.toString()).appendChild(node);
}




function clickTo(riga,colonna){
   if (caselle_aperte.length==0){
      mostraSimbolo(riga,colonna);
      caselle_aperte[0]=riga.toString()+colonna.toString();
      return;
   }
   if (caselle_aperte.length==1){
      if (caselle_aperte[0]==riga.toString()+colonna.toString())
   return;
      mostraSimbolo(riga,colonna);
      caselle_aperte[1]=riga.toString()+colonna.toString();
      if (getSimboloAt(caselle_aperte[1]).name==(getSimboloAt(caselle_aperte[0])).name){
          document.getElementById(riga.toString()+colonna.toString()).setAttribute('style','background-color:#81F781;');
          document.getElementById(caselle_aperte[0]).setAttribute('style','background-color:#81F781;');
          caselle_aperte.pop();
          caselle_aperte.pop();
          var conta;
          conta=0;
          for (i=1;i&lt;=4;i++)
             for (c=1;c&lt;=4;c++){
                 if (document.getElementById(i.toString()+c.toString()).innerHTML!="*")
                      conta++;
             }
          }
          if (conta==16)
              alert("Hai vinto!");
          return;
      }
      
   if (caselle_aperte.length==2){
      nascondiSimboloS(caselle_aperte[0]);
      nascondiSimboloS(caselle_aperte[1]);
      caselle_aperte.pop();
      caselle_aperte.pop();
      return;
   }
}





E come ieri, ecco il link per la prova:

domenica 10 novembre 2013

Memory, gioco mnemonico che ho scritto in javascript



Aggiornamento: clicca qui

Ispirandomi al gioco che era presente nel vecchio Nokia 3210, ho creato questo gioco con poche linee di codice in Javascript e qualcosa basilare di CSS e HTML. Il file HTML su cui mi baso (ci sono riferimenti alla tabella, id in particolare, e un tasto per "nuovo gioco"):









<CENTER>
<p style="font-size:x-large;font-style:italic;">Memory: clicca sulle caselle e memorizzale per trovare le coppie, fino a scoprire tutte le caselle.</p>
<a href="#">
<table>
<tr><th id="11" onclick="clickTo(1,1)">*</th><th id="12" onclick="clickTo(1,2)">*</th><th id="13" onclick="clickTo(1,3)">*</th><th id="14" onclick="clickTo(1,4)">*</th></tr>
<tr><th id="21" onclick="clickTo(2,1)">*</th><th id="22" onclick="clickTo(2,2)">*</th><th id="23" onclick="clickTo(2,3)">*</th><th id="24" onclick="clickTo(2,4)">*</th></tr>
<tr><th id="31" onclick="clickTo(3,1)">*</th><th id="32" onclick="clickTo(3,2)">*</th><th id="33" onclick="clickTo(3,3)">*</th><th id="34" onclick="clickTo(3,4)">*</th></tr>
<tr><th id="41" onclick="clickTo(4,1)">*</th><th id="42" onclick="clickTo(4,2)">*</th><th id="43" onclick="clickTo(4,3)">*</th><th id="44" onclick="clickTo(4,4)">*</th></tr>
</table>
<input type="button" value="Nuovo gioco" onclick="nuovoGioco()" style="width:100px;height:50px;">
</a>
</CENTER>
Mentre  il cuore del programma vero e proprio è lo script in javascript, tutto commentato:
<script type="text/javascript">
//Array per contenere i caratteri da scoprire
var array = new Array();
//Array per controllare il flusso del gioco (se sono state aperte due caselle e sono uguale allora scopri, altrimenti nascondi ecc.
var caselle_aperte = new Array();
/*INIZIO*/
nuovoGioco();

/*
*Questa funzione gestisce quando viene cliccata una casella, e decide cosa fare
*a seconda del contenuto di caselle_aperte
*/

function clickTo(riga,colonna){
   //Caso 1: non ci sono caselle aperte, quindi deve scoprirne una sola
   if (caselle_aperte.length==0){
      mostraSimbolo(riga,colonna);
      caselle_aperte[0]=riga.toString()+colonna.toString();
      return;
   }
   //Caso 2: c'è già una casella aperta, scopri la nuova e controlla se sono uguali
   if (caselle_aperte.length==1){
      //se è la stessa ignora ed esci
      if (caselle_aperte[0]==riga.toString()+colonna.toString())
   return;
     //scopri la casella
      mostraSimbolo(riga,colonna);
      //memorizza la nuova casella in caselle_aperte
      caselle_aperte[1]=riga.toString()+colonna.toString();
     //controlla se i simboli sono uguali
      if (getSimboloAt(caselle_aperte[1])==(getSimboloAt(caselle_aperte[0]))){
          document.getElementById(riga.toString()+colonna.toString()).setAttribute('style','background-color:#81F781;');
          document.getElementById(caselle_aperte[0]).setAttribute('style','background-color:#81F781;');
          //cancella il contenuto di caselle_aperte
          caselle_aperte.pop();
          caselle_aperte.pop();
          //Controlla se hai vinto (cioè se tutte le caselle sono state scoperte
          var conta;
          conta=0;
          for (i=1;i<=4;i++)
             for (c=1;c<=4;c++){
                 if (document.getElementById(i.toString()+c.toString()).innerHTML!="*")
                      conta++;
             }
          }
          if (conta==16)
              alert("Hai vinto!");
          return;
      }
   //Caso 3: ci sono già due caselle scoperte e sono entrambe diverse.
   if (caselle_aperte.length==2){
      //Nascondi i simboli
      nascondiSimbolo(caselle_aperte[0]);
      nascondiSimbolo(caselle_aperte[1]);
      //svuota caselle_aperte
      caselle_aperte.pop();
      caselle_aperte.pop();
      return;
   }
}
/*
* Mostra semplicemente il simbolo in riga,colonna
*/
function mostraSimbolo(riga,colonna){
   document.getElementById(riga.toString()+colonna.toString()).innerHTML=array[((riga-1)*4)+colonna-1];
}
/*
*Nasconde semplicemente il simbolo in riga, colonna
*/
function nascondiSimbolo(riga,colonna){
   document.getElementById(riga.toString()+colonna.toString()).innerHTML="*";
}
/*
*Come sopra, ma overload per un solo parametro di tipo stringa(es:"32, riga 3, colonna 2)
*/
function nascondiSimbolo(_stringa){
   stringa = new String(_stringa);
   riga = stringa.charAt(0);
   colonna = stringa.charAt(1);
   document.getElementById(riga.toString()+colonna.toString()).innerHTML="*";
}
/*
*Ritorna il simbolo che c'è memorizzato in riga, colonna
*/
function getSimboloAt(riga,colonna){
  riga--;
  colonna--;
  return array[(riga*4)+colonna];
}
/*
*Come sopra, ma overload per un solo parametro di tipo stringa(es:"32, riga 3, colonna 2)
function getSimboloAt(_stringa){
  stringa = new String(_stringa);
  riga = stringa.charAt(0);
  colonna = stringa.charAt(1);
  riga--;
  colonna--;
  return array[(riga*4)+colonna];
}
/*
*Inizia un nuovo gioco
*/
function nuovoGioco(){
  //creo di nuovo un array
  array  = new Array();
  //idem
  caselle_aperte=new Array();
  //array che contiene i simbolo, per ora solo lettere
  var array_simboli= new Array("a","b","c","d","e","f","g","h");
  var simbolo;
  //Cancello il contenuto delle caselle e metto "*" al posto
  for (i=1;i<=4;i++)
     for(c=1;c<=4;c++) {
        riga = Math.floor(i/4)+1;
        colonna = i-((riga-1)*4);
        document.getElementById(i.toString()+c.toString()).innerHTML="*";
        document.getElementById(i.toString()+c.toString()).setAttribute("style","background-color:white;");
     }
   //Preparo l'array a random
  var pos1,pos2;
  for (i=0;i<8;i++){
   while(array[pos1]!=null)
       pos1=Math.floor((Math.random()*16));
   array[pos1]=array_simboli[i];
   while(array[pos2]!=null)
       pos2=Math.floor((Math.random()*16));
   array[pos2]=array_simboli[i];
   }
   //Correggo bug, secondo il quale "a" viene memorizzata una sola volta mentre l'altra è null
   for (i=0;i<16;i++)
     if (array[i]==null){
         array[i]="a";
         break;
     }
}
E da qui potrete vedere il risultato:

sabato 9 novembre 2013

Tutorial GTK+ 3.0 . Parte 3 - Packing

Durante lo sviluppo di una applicazione, potreste avere bisogno di aggiungere più oggetti in una finestra. L'esempio precedente ha usato solamente un widget e abbiamo utilizzato semplicemente una chiamata alla funzione  gtk_container_add() per "impacchettare" il widget dentro la finestra.Ma quando avete bisogno di aggiungere più oggetti in una finestra, diviene importante controllare in che modo ogni widget deve essere posizionato e dimensionato. Ecco a cosa serve l'impacchettamento. GTK+ contiene una vasta collezione di containers la cui funzione è quella di controllare il layout dei widget figli aggiunti alla finestra. Vedi Layout Containers per una visione generale. L'esempio seguente mostra come il container GtkGrid vi permette di sistemare i tasti: ecco a voi il famoso Hello World in GTK+:
#include <gtk/gtk.h>

static void print_hello (GtkWidget *widget, gpointer   data){
  g_print ("Hello World\n");
}

int main (int   argc, char *argv[]){
  GtkWidget *window;
  GtkWidget *grid;
  GtkWidget *button;

  /* Questa è una funzione di callback. Gli argomenti da riga di comando
 * vengono ignorati in questo esempio. Se ne parlerà più avanti di queste funzioni.
 */
  gtk_init (&argc, &argv);

  /* crea una nuova finestra e imposta il titolo */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Grid");
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  /* Qui creiamo il container per impacchettare i vari widget */
  grid = gtk_grid_new ();

  /* aggiunge il container alla finestra */
  gtk_container_add (GTK_CONTAINER (window), grid);

  button = gtk_button_new_with_label ("Button 1");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  /* Posiziona il primo tasto nella cella (0, 0), e gli fa occupare
   * solo 1 cella orizzontalmente e verticalmente
   */
  gtk_grid_attach (GTK_GRID (grid), button, 0, 0, 1, 1);

  button = gtk_button_new_with_label ("Button 2");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  /* Posiziona il secondo tasto nella cella (1, 0), e gli fa occupare
   * solo una cella orizzontalmente and verticalmente
   */
  gtk_grid_attach (GTK_GRID (grid), button, 1, 0, 1, 1);

  button = gtk_button_new_with_label ("Quit");
  g_signal_connect (button, "clicked", G_CALLBACK (gtk_main_quit), NULL);

  /* Posiziona il tasto Quit(Esci) nella cella (0, 1), e gli fa riempire
   * 2 colonne.
   */
  gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 2, 1);

  /* Ora che abbiamo impacchettato i widgets, li mostriamo tutti 
   * in una volta, chimaando gtk_widget_show_all() sulla finestra.
   * This call recursively calls gtk_widget_show() on all widgets
   * that are contained in the window, directly or indirectly.
   */
  gtk_widget_show_all (window);

  /* Tutte le applicazioni GTK+ devono avere un gtk_main(). Il controllo finisce qui
   * e rimane in attesa di un qualche evento (come la pressione di un tasto
   * o un evento del mouse) fintantoché gtk_main_quit() viene invocato.
   */
  gtk_main ();

  return 0;
}

Tutorial GTK+ 3.0 - Parte 2 - Hello World!

Nella lunga tradizione dei linguaggi di programmazione e librerie, ecco a voi il famoso Hello World in GTK+:
#include <gtk/gtk.h>

/* Questa è una funzione di callback. Gli argomenti da riga di comando
 * vengono ignorati in questo esempio. Se ne parlerà più avanti di queste funzioni.
 */
static void print_hello (GtkWidget *widget, gpointer   data){
  g_print ("Hello World\n");
}

static gboolean on_delete_event (GtkWidget *widget, GdkEvent  *event, gpointer   data){
  /* Se il valore di ritorno è FALSE nel segnale "delete_event",
   * GTK lancierà il segnale "destroy". Ritornare TRUE vuol dire che
   * non vuoi che la finestra venga distrutta.
   *
   * Ciò è utile per chiedere all'utente 'sei sicuro di volere uscire?'
   */

  g_print ("Si è verificato l'evento \"delete\"\n");
  return TRUE;
}

int main (int   argc, char *argv[]){
  /* GtkWidget è il tipo base per tutti i widgets */
  GtkWidget *window;
  GtkWidget *button;

  /* Questa viene chiamata in tutti i programmi GTK. Gli argomenti 
   * vengono presi dalla linea di comando e resi disponibile per l'applicazione 
   */
  gtk_init (&argc, &argv);

  /* Crea una nuova finestra, e imposta il titolo */
  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Hello");

  /* Quando la finestra lancia il segnale "delete-event"(emesso 
   * dal GTK+ in risposta a un evento proveniente dal window manager,
   * solitamente cliccando il tasto "chiudi" della finestra), 
   * chiediamo a essa di eseguire la funzione on_delete_event() definita sopra.
   *
   * I dati passati alla funzione di callback sono NULL e sono ignorati
   * dalla funzione di callback.
   */
  g_signal_connect (window, "delete-event", G_CALLBACK (on_delete_event), NULL);

  /* Qui colleghiamo l'evento "destroy" alla funzone gtk_main_quit().
   *
   * Questo segnale viene emesso quando chiamiamo gtk_widget_destroy() sulla
   * finestra, o se ritorniamo FALSE nella funzione callback "delete_event".
   */
  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);

  /* Imposta i bordi della finestra. */
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  /* Crea un tasto con la scritta "Hello World". */
  button = gtk_button_new_with_label ("Hello World");

  /* Quando il tasto riceve il segnale "clicked", esso chiamerà la
   * funzione print_hello() passando NULL come argomento.
   *
   * La funzione print_hello() è definita sopra.
   */
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);

  /* La funzione g_signal_connect_swapped() collegherà il segnale "clicked"
   * del tasto alla funzione gtk_widget_destroy(); invece di chiamarla 
   * direttamente usando il tasto come suo argomento, questa funzione manderà 
   * a essa gli argomenti user_data. Questo causerà la distruszione della 
   * finestra chiamando gtk_widget_destroy() sulla finestra.
   */
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);

  /* Questo "impacchetterà" il tasto nella finestra. GtkWindow eredita da  GtkBin,
   * il quale è uno speciale contenitore avente solamente un figlio
   */
  gtk_container_add (GTK_CONTAINER (window), button);

  /* Il passo finale è mostrare il widget appena creato... */
  gtk_widget_show (button);

  /* ...e la finestra */
  gtk_widget_show (window);

  /* Tutte le applicazioni GTK+ devono avere un gtk_main(). Il controllo finisce qui
   * e rimane in attesa di un qualche evento (come la pressione di un tasto
   * o un evento del mouse) fintantoché gtk_main_quit() viene invocato.
   */
  gtk_main ();

  return 0;
}
                              Parte 2 - Packing >>>