Blog

  • Conway’s Game of Life in C# e Raylib

    Ecco un’implementazione in C# e Raylib di Conway’s Game of Life.

    /*
    Conways' Game of Life - version 0.0.1
    Licensed under the terms of LGPL v 3.0
    */
    using Raylib_cs;
    namespace myRaylibTestApp;
    class Cell {
    	public bool statePresent;
    	public bool stateNext;
    	public bool hasLivedOnce;
    	public int x, y;
    	public Cell(int x, int y) {
    		this.stateNext = false;
    		Random random = new Random();
    		int randomNumber = random.Next(0, 99);
    		if (randomNumber > 50) {
    			this.statePresent = true;
    		}
    		this.x = x;
    		this.y = y; 
    	}
    	public void Draw() {
    		if (this.statePresent) {
    			Raylib.DrawRectangle(x*6, y*6, 6, 6, Color.Red);
    		}else{
    			if (this.hasLivedOnce) {
    				Raylib.DrawRectangle(x*6, y*6, 6, 6, Color.LightGray);
    			} else {
    				Raylib.DrawRectangle(x*6, y*6, 6, 6, Color.DarkGray);
    			}
    		}
    	}
    	
    }
    class Program
    {
    	const int SCREEN_W = 600;
    	const int SCREEN_H = 600;
    	public static void Main()
    	{
    		Raylib.InitWindow(SCREEN_W, SCREEN_H, "Game of life");
    		Raylib.SetTargetFPS(30);
    		
    		/* Cells initializing*/
    		Cell[,] theCell = new Cell[100,100];
    		for (int i = 0; i < 100; i++) {
    			for (int j = 0; j < 100; j++) {
    				theCell[i,j] = new Cell(j, i);
    			}	 
    		}
    		/*-------*/
    		while (!Raylib.WindowShouldClose())
    		{
    			/*compute effect of neighbours*/
    			
    			for (int y = 0; y < 100; y++) {
    				for (int x = 0; x < 100; x++) {
    					int s = 0;
    					int tlx, tly, brx, bry;
    					tlx = x-1;
    					tly = y-1;
    					brx = x+1;
    					bry = y+1;
    					if (tlx < 0) {
    						tlx = 0;
    					}
    					if (tly < 0) {
    						tly = 0;
    					}
    					if (brx > 99) {
    						brx = 99;
    					} 
    					if (bry > 99) {
    						bry = 99;
    					}
    					for (int row = tly; row <= bry; row++) {
    						for (int col = tlx; col <= brx; col++) {
    							if (row == y && col == x) {
    								continue;
    							}
    							
    							if (theCell[row,col].statePresent) {
    								s++;
    							}
    						}
    					}
    					if (theCell[y,x].statePresent && s == 2 || s == 3) {
    						theCell[y,x].stateNext = true;
    					}else{
    						theCell[y,x].stateNext = false;
    					}
    					if (!theCell[y,x].statePresent && s == 3){
    						theCell[y,x].stateNext = true;
    					}
    				}
    			}
    			for (int y = 0; y < 100; y++) {
    				for (int x = 0; x < 100; x++) {
    					theCell[y,x].statePresent = theCell[y,x].stateNext;
    					if (theCell[y,x].statePresent) {
    						theCell[y,x].hasLivedOnce = true;
    					}
    				}
    			}
    			Raylib.BeginDrawing();
    			Raylib.ClearBackground(Color.White);
    			for (int y = 0; y < 100; y++) {
    				for (int x = 0; x < 100; x++) {
    				   theCell[y,x].Draw();
    				}
    			}
    			Raylib.EndDrawing();
    		}
    		Raylib.CloseWindow();
    	}
    }
  • Connessione Joystick DB9 (C64) su Windows tramite Arduino e Python

    Con un modulo Arduino e qualche riga di Python è possibile utilizzare un Joystick del Commodore come periferica di input.

    Nel test ho utilizzato un Joystick Alberici Albatros.

    Materiale occorrente:

    • Joystick con connessione DB9
    • Connettore DB9 Maschio da collegare ad Arduino
    • Arduino
    • Python
    • Software Vjoy

    Ecco lo schema generale di funzionamento: Arduino legge l’input grezzo proveniente dal joystick e lo converte in un messaggio inviato tramite porta seriale, python processa questo messaggio e governa il virtual Joystick (che viene visto da Windows come una periferica di gioco fisica).

    Sketch Arduino:

    const int pinUp    = 2;
    const int pinDown  = 3;
    const int pinLeft  = 4;
    const int pinRight = 5;
    const int pinFire  = 6;
    
    unsigned long lastSend = 0;
    const unsigned long interval = 20; // ms (50 Hz)
    
    void setup() {
      pinMode(pinUp,    INPUT_PULLUP);
      pinMode(pinDown,  INPUT_PULLUP);
      pinMode(pinLeft,  INPUT_PULLUP);
      pinMode(pinRight, INPUT_PULLUP);
      pinMode(pinFire,  INPUT_PULLUP);
    
      Serial.begin(115200);
    }
    
    void loop() {
      if (millis() - lastSend >= interval) {
        lastSend = millis();
    
        int up    = !digitalRead(pinUp);
        int down  = !digitalRead(pinDown);
        int left  = !digitalRead(pinLeft);
        int right = !digitalRead(pinRight);
        int fire  = !digitalRead(pinFire);
    
        Serial.print("U:");
        Serial.print(up);
        Serial.print(" D:");
        Serial.print(down);
        Serial.print(" L:");
        Serial.print(left);
        Serial.print(" R:");
        Serial.print(right);
        Serial.print(" F:");
        Serial.println(fire);
      }
    }
    

    Programma python per processare i dati provenienti dalla seriale:

    import re
    import serial
    import pyvjoy
    
    # --- CONFIG ---
    PORT = "COM7"      # <-- cambia qui
    BAUD = 115200
    VJOY_ID = 1
    # --------------
    
    LINE_RE = re.compile(r"U:(\d)\s+D:(\d)\s+L:(\d)\s+R:(\d)\s+F:(\d)")
    
    AX_MIN = 0x0001
    AX_MAX = 0x8000
    AX_CEN = 0x4000
    
    def axis(neg, pos):
        if neg and not pos: return AX_MIN
        if pos and not neg: return AX_MAX
        return AX_CEN
    
    ser = serial.Serial(PORT, BAUD, timeout=1)
    j = pyvjoy.VJoyDevice(VJOY_ID)
    
    # reset iniziale
    j.reset()
    j.set_axis(pyvjoy.HID_USAGE_X, AX_CEN)
    j.set_axis(pyvjoy.HID_USAGE_Y, AX_CEN)
    j.set_button(1, 0)
    
    print("OK - leggo seriale e mando a vJoy (CTRL+C per uscire)")
    
    last = None
    try:
        while True:
            line = ser.readline().decode("ascii", errors="ignore").strip()
            m = LINE_RE.match(line)
            if not m:
                continue
    
            up, down, left, right, fire = map(int, m.groups())
            state = (up, down, left, right, fire)
            if state == last:
                continue
            last = state
    
            j.set_axis(pyvjoy.HID_USAGE_X, axis(left, right))
            j.set_axis(pyvjoy.HID_USAGE_Y, axis(up, down))  # su = min, giu = max
            j.set_button(1, 1 if fire else 0)
    
    except KeyboardInterrupt:
        pass
    finally:
        # rilascia tutto
        j.set_axis(pyvjoy.HID_USAGE_X, AX_CEN)
        j.set_axis(pyvjoy.HID_USAGE_Y, AX_CEN)
        j.set_button(1, 0)
        ser.close()
        print("\nChiudo.")
    

    Si consiglia di testarlo su WinUAE e Sensible Soccer 🙂

  • Free Protocol su Weintek HMI

    Ecco un esempio di come è possibile leggere dei dati dalla porta seriale di un HMI Weintek utilizzando il Free Protocol.

    Materiale software/hardware occorrente:

    • un modulo Arduino;
    • Arduino IDE;
    • Weintek Easybuilder Pro;
    • un cavo USB.

    Questo codice Arduino scrive dei dati sulla porta seriale, in questo caso un’onda sinusoidale.

    const unsigned long BAUD = 9600;
    const float PERIOD_MS = 20000.0f; 
    const float AMP = 100.0f; 			
    
    void setup() {
    
        Serial.begin(BAUD);
    
    }
    
    void loop() {
    	
        unsigned long t = millis();
        float n = (2.0f * PI) * ( (float)t / PERIOD_MS );
        float val = AMP * sin(n);
        Serial.println(val, 2);
        delay(100);
    
    }

    A scopo di diagnostica si può controllare l’output generato tramite il monitor seriale di Arduino IDE o anche tramite il programma HTERM.

    Attenzione a impostare correttamente il Baudrate, il numero di bit di dati, di stop e il controllo parità.

    Le impostazioni predefinite della comunicazione seriale di Arduino prevedono 8 bit per i dati, nessuna parità e un bit di stop.1

    In Easy Builder Pro creiamo un nuovo progetto, va bene il modello MT8050ie.

    Aggiungiamo un dispositivo di tipo Free Protocol e impostiamo anche qui i parametri di comunicazione.

    Come porta di comunicazione utilizziamo la COM 1 (RS-232).

    Impostiamo una macro che legga i dati dalla porta seriale, copiandoli poi su una variabile float dello HMI.

    Ci sono due passaggi:

    • lettura dei dati grezzi in ASCII dalla porta seriale (funzione INPORT);
    • conversione in formato float (funzione ASCII2FLOAT).
    macro_command main()
        
        //read ASCII from serial and save in LW-0
        char wResponse[6], receive_len
        INPORT(wResponse[0], "Free Protocol", 6, receive_len)
        if receive_len >= 6 then
            SetData(wResponse[0], "Local HMI", LW, 0, 6)
        end if
        
        //convert read to float and save in LW-10
        float output
        ASCII2FLOAT(wResponse[0], output, 6)
        SetData(output, "Local HMI", LW, 10, 1)
    
    end macro_command

    I dati della variabile float possono essere storicizzati (Data Storico > campionamento Dati > Nuovo … e specifichiamo l’indirizzo di memoria della variabile).

    Il file di progetto Easy Builder Pro è scaricabile da questo link.

    1. Il manuale di Arduino di Paolo Aliverti ed. LSWR 2^ Ed. pag. 377 ↩︎

  • Un secchio zincato

    Se ne sta accanto alla stufa a legna, ospita la cenere di ciò che ha assicurato il calore della giornata trascorsa.

  • Un casale

    Eretto in cima a un colle, subisce l’assedio del progresso.

  • Trabocchi

    Giulianova, trabocchi presenti al porto.

  • Una caffettiera

    Ausilio mattutino per rimuovere i residui del sonno.

  • Umile arredo urbano

    Una fontanella al centro di un piccolo parco, contornata da due panchine. Un’altalena e uno scivolo per bambini completano l’arredo di questo fazzoletto verde ombreggiato da tigli.

    OpenStreetMap