Creación masiva de clases de C++ (u otros lenguajes) mediante plantillas

Esta tarde estaba haciendo pruebas y he tenido que crear unas 30 o 40 clases, por tanto, necesitaba automatizar y mejorar el proceso. Con Visual Studio el tema de crear clases lo veo un infierno, con eclipse la cosa mejora, pero sigue existiendo el problema.

Por tanto os pongo este script que con solo preguntaros 2 cosas por clase, podeis crear clases a gran velocidad. Es obligatorio que cambieis las plantillas a vuestras necesidades. Se podría uasar para cualquier lenguaje, ya que la generación del nombre del fichero es otra plantilla en sí. Queda pendiente sacar la plantilla a un archivo externo. Hay que decir que lo he hecho en menos de 1 hora.

Aquí lo pego, aunque por si se ve mal también dejo un pastebin:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# vim: set fileencoding=utf-8 :
# 
# Script para generar clases de C++ agilmente
# Requerido: Python 3.x
#
# 1ª vez de uso se creará un script que debe de configurarse según las necesidades
# Esta configuración es global: directorio de salida, autor y formato fecha
# En siguientes ejecuciones solo preguntará interacticamente y en bucle:
# - Nombre de clase
# - Proposito
#
# Para dejar de crear clases poner un nombre de clase en blanco
#
# Las plantillas deben modificarse y adaptarse a las necesidades de cada uno.
# Queda pendiente sacar las plantillas a fichero
#

import os, sys
import configparser
from datetime import date
d = date.today()

# global
TODIR = "."
NAMESPACE = "Dune"
AUTOR = "Ricardo Marmolejo García"
FORMAT_FECHA = "%d/%m/%y"
config_file = "create_class.cfg"

if(not os.path.exists(config_file)):
    # escribir una config por defecto
    config = configparser.ConfigParser()
    config.add_section('create_class')
    config.set('create_class', 'TODIR', "%s" % TODIR)
    config.set('create_class', 'NAMESPACE', "%s" % NAMESPACE)
    config.set('create_class', 'AUTOR', "%s" % AUTOR)
    config.set('create_class', 'FORMAT_FECHA', "%s" % FORMAT_FECHA)

    f = open(config_file, 'w')
    config.write(f)
    f.close()
    
    print("Se ha creado una configuración por defecto en %s." % config_file)
    print("Condigurelo, y vuelva a ejecutar el script.")
    sys.exit(1)

else:
    
    config = configparser.ConfigParser()
    config.read(config_file)
    
    TODIR = config.get('create_class', 'TODIR')
    NAMESPACE = config.get('create_class', 'NAMESPACE')
    AUTOR = config.get('create_class', 'AUTOR')
    FORMAT_FECHA = config.get('create_class', 'FORMAT_FECHA')

# obtener fecha, en el formato especificado
FECHA = d.strftime(FORMAT_FECHA)

salir = False

while not salir:
    
    CLASSNAME = input("Escribe el nombre de la clase (dejelo en blanco si quiere terminar): \n")
    
    if CLASSNAME == "":
        salir = True
        break
    
    PROPOSITO = input("Escriba el propósito de esta clase: \n")
    print("\n")

    '''
    Plantillas:
    
        - template_cpp_namefile: Plantilla que genera el nombre del archivo cpp
        - template_h_namefile: Plantilla que genera el nombre del archivo .h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    '''
    template_cpp_namefile = "__CLASSNAME__.cpp"
    template_h_namefile = "__CLASSNAME__.h"

    '''
    
    Plantillas:
    
        - template_cpp: Plantilla que genera el contenido del cpp
        - template_h: Plantilla que genera el contenido del h
    
    Campos disponibles:
    
    __NAMESPACE__ = Nombre del namespace original
    __NAMESPACE_UPPER__ = Nombre del namespace en mayusculas (puntos pasan a ser guiones bajos)
    __NAMESPACE_LOWER__ = Nombre del namespace en minusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME__ = Nombre de Clase original
    __CLASSNAME_UPPER__ = Nombre de Clase en mayusculas (puntos pasan a ser guiones bajos)
    __CLASSNAME_LOWER__ = Nombre de Clase en minusculas (puntos pasan a ser guiones bajos)
    __FILE__ = Nombre del archivo original
    __FILE_UPPER__ = Nombre del archivo en mayusculas (puntos pasan a ser guiones bajos)
    __FILE_LOWER__ = Nombre del archivo en minusculas (puntos pasan a ser guiones bajos)
    __PROPOSITO__ = Proposito de la clase
    __AUTOR__ = Autor de la clase
    __FECHA__ = Dia, Mes y año del momento de la creación
    '''

    template_h = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#ifndef __FILE_UPPER__
#define __FILE_UPPER__

#include "../Component.h"

namespace __NAMESPACE__ {

class __CLASSNAME__ : public Component
{
public:
    __CLASSNAME__();
    virtual ~__CLASSNAME__();
    
public:

    // SERVICIOS DE LA COMPONENTE
    

public:

    /**
    Ejecutado en su primer tick
    */
    virtual void OnCreate();

    /**
    Actualizado intensivamente
    */
    virtual void Update();

    /**
    Actualizado en una frecuencia fija
    */
    virtual void UpdateFixed();

    /**
    Ejecutado antes de su destrucción
    */
    virtual void OnDestroy();

};

} // end namespace __NAMESPACE_UPPER__

#endif __FILE_UPPER__
"""

    template_cpp = """//---------------------------------------------------------------------------
// __FILE__
//---------------------------------------------------------------------------

/**
@file __FILE__

__PROPOSITO__

@author __AUTOR__
@date __FECHA__
*/

#include "../Common.h"
#include "__CLASSNAME__.h"
#include "../Entity.h"

namespace __NAMESPACE__ {

__CLASSNAME__::__CLASSNAME__()
{
    
}

__CLASSNAME__::~__CLASSNAME__()
{
    
}

void __CLASSNAME__::OnCreate()
{
    
}

void __CLASSNAME__::Update()
{
    
}

void __CLASSNAME__::UpdateFixed()
{
    
}

void __CLASSNAME__::OnDestroy()
{
    
}

} // end namespace __NAMESPACE_UPPER__
"""

    # init vars
    NAMESPACE_UPPER = NAMESPACE.upper()
    NAMESPACE_LOWER = NAMESPACE.lower()
    CLASSNAME_UPPER = CLASSNAME.upper()
    CLASSNAME_LOWER = CLASSNAME.lower()
    NAMESPACE_UPPER = NAMESPACE_UPPER.replace(".", "_")
    NAMESPACE_LOWER = NAMESPACE_LOWER.replace(".", "_")
    CLASSNAME_UPPER = CLASSNAME_UPPER.replace(".", "_")
    CLASSNAME_LOWER = CLASSNAME_LOWER.replace(".", "_")

    for newfile in [    [template_cpp_namefile, template_cpp],
                        [template_h_namefile, template_h]       ]:

        FILE = newfile[0]
        FILE = FILE.replace("__NAMESPACE__", NAMESPACE)
        FILE = FILE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
        FILE = FILE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
        FILE = FILE.replace("__CLASSNAME__", CLASSNAME)
        FILE = FILE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
        FILE = FILE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
        FILE_UPPER = FILE.upper()
        FILE_LOWER = FILE.lower()
        FILE_UPPER = FILE_UPPER.replace(".", "_")
        FILE_LOWER = FILE_LOWER.replace(".", "_")

        generated_file = os.path.join(TODIR, FILE)
        
        if not os.path.exists(generated_file):

            VALUE = newfile[1]
            VALUE = VALUE.replace("__NAMESPACE__", NAMESPACE)
            VALUE = VALUE.replace("__NAMESPACE_UPPER__", NAMESPACE_UPPER)
            VALUE = VALUE.replace("__NAMESPACE_LOWER__", NAMESPACE_LOWER)
            VALUE = VALUE.replace("__CLASSNAME__", CLASSNAME)
            VALUE = VALUE.replace("__CLASSNAME_UPPER__", CLASSNAME_UPPER)
            VALUE = VALUE.replace("__CLASSNAME_LOWER__", CLASSNAME_LOWER)
            VALUE = VALUE.replace("__FILE__", FILE)
            VALUE = VALUE.replace("__FILE_UPPER__", FILE_UPPER)
            VALUE = VALUE.replace("__FILE_LOWER__", FILE_LOWER)
            VALUE = VALUE.replace("__PROPOSITO__", PROPOSITO)
            VALUE = VALUE.replace("__AUTOR__", AUTOR)
            VALUE = VALUE.replace("__FECHA__", FECHA)

            file_cpp = open(generated_file, "w", encoding='utf-8')
            file_cpp.write(VALUE)
            file_cpp.close()
            
            print("%s se ha creado correctamente" % FILE)
            
        else:
            
            print("%s ya existe!, no se ha creado." % FILE)
            
    print("\n")

Android links recopilation

Pongo una recopilación de enlaces, sobre android:

1º SDK (sdk android)
http://developer.android.com/sdk/index.html

2ºEclipse Helio (para Java o Classic)
http://www.eclipse.org/downloads/

3º ADT 18 (plugin eclipse)
Según Google: http://developer.android.com/sdk/eclipse-adt.html
Según Mind the Robot: http://mindtherobot.com/blog/209/android-beginners-from-bare-windows-to-your-first-app/

4º NDK (c++ / NativeActivity)
Según Google: http://developer.android.com/sdk/ndk/index.html
Según Mind The Robot: http://mindtherobot.com/blog/452/android-beginners-ndk-setup-step-by-step/

Interesante:
Charla sobre NDK: http://www.youtube.com/watch?v=byFTAhXVF7k&feature=player_embedded#
Google I/O 2011: Bringing C and C++ Games to Android: http://www.youtube.com/watch?v=5yorhsSPFG4
NativeActivity: http://developer.android.com/reference/android/app/NativeActivity.html

Algoritmos Genéticos

Buena os pongo otro post interesante (que le puede resultar útil a alquien y no quiero que se pierda) que he puesto en el mismo foro que el post anterior:

A mi me interesa bastante la IA como ya muchos sabreis :D. Hace tiempo que estudie el tema y mola mucho :D

Os dejo un código que hice hace tiempo, parece sencillo, pero tiene bastante teoría detras. Yo siempre uso Python para cacharrear y C++ para implementarlo en serio.

http://pastebin.com/Y0KxMg7X

El problema me lo invente. El objetivo del código:

– Resolver la ecuación: f(x) = A*x^2-4*x-1 . Es decir el coeficiente A es la única variable. B = -4 y C = -1

Teniendo en cuenta:
– f(-10) = 339
– f(0) = -1
– f(10) = 259

Mi idea inicial, era hacer el cromosomo A, B y C pero como tardaba mil años, limite B y C. Y el espacio de soluciones quedo así:

Cromosoma(randomClamp(-10000, 10000), -4, -1)

La solución es 3. Pero se trata de resolverla por AG en lugar de métodos analíticos.

Cada ejecución puede tardar más o menos, mi salida es:
Problema: f(x) = A*x^2-4*x-1 y 3 puntos. Calcular A:
Solucion A = 3.000040 – Con un Error de 0.000063 en 15620 generaciones
Presione una tecla para continuar . . .

Tarda unas 15000 generaciones(que son pocos segundos de computación) debido a que el espacio de soluciones es muy grande y la perturbación es de solo un 5%, por tanto muta relativamente despacio en un espacio muy grande. Una mutación muy grande es casi peor, porque se convierte en busqueda aleatoria pero es más probable que encuentre un optimo global, en cambio si tiene mutaciones pequeñas puede quedarse estancado en un óptimo local como el oso panda XD

Un saludo. Ricardo

 

Cursillo acelerado de Lua + Luabind

Buenas, tras 1000 años sin escribir, hago un paréntesis para pastear un post que he puesto en un foro privado que posiblemente caiga en el olvido, y sería una pena, ya que seguro que el tema le interesa a alguien. El post dice así:

Buenas:

Tras la conversación con Ardían, y gente que he visto en los foros que estáis interesados en aprender Lua/Scripting. Yo tengo bastante experiencia porque lo estoy usando intensivamente para el PFC.

No creo que haga falta evangelizar mucho los beneficios de Lua, se vende por si sólo, pero vamos:
– Es muy rápido. Si una llamada directa a un método hace 2 usos de la pila, haciéndola a través de Lua, puede que aumente a 4 o 6 usos.
– Es más rápido usar el lenguaje a pelo, esta claro, pero hardcodearte todo, es una práctica de programación bastante mala. El poder hacer desacoplamiento de la lógica a cambio de perder una microsegundos por llamada, vale la pena y bastante.
– Aceleras el desarrollo al no tener que necesitar compilar. Ya solo por este motivo, tendrías que usarlo.
– Existe un compilador que lo convierte en bytecode (como java) y supuestamente te acelera la carga inicial, aunque se suele usar más para proteger los scripts. (Yo nunca lo he usado).

Lua es para C, no permite nada de POO, y se basa mucho en la pila, es bastante jodido. Pero con Lua + LuaBind el bindeo del API es muy fácil, permite herencia simple y múltiple, polimorfismo, sobrecarga de operadores, etc, etc … Se usa muchísimo en videojuegos profesionales.

He hecho un código independiente y compilable con un montón de pruebas individuales que abarcan el 90% del día a día con luabind. Estudiaros el tema, porque si lo conocéis, no podréis dejar de vivir sin Lua+Luabind XDD

Os lo paso compilado para Linux, pero lo interesante es el código y los comentarios que he hecho deprisa y corriendo.

De todas formas para compilarlo en Ubuntu/Debian:
sudo apt-get install liblua5.1-0-dev libluabind-dev
make
./main

Un saludo. Ricardo

No se cuento durará el link, asi que lo pongo en pastebin:

main.cpp – http://pastebin.com/b2JBy17Q
test.lua – http://pastebin.com/5v6Dx2JC
Makefile – http://pastebin.com/0NPkQATN

Espero que os sea útil !

Sigueme en Twitter

Como veis, tengo el blog algo paredete, el motivo es que este año me gustaría acabar la carrera, y no tengo mucho tiempo. De todas formas, soy bastante adicto al twitter, y me podeis preguntar sobre cualquier tema tocado en el blog o cualquiera de la temática. Desde finales de junio me he empezado a especializar en IA para el proyecto de fin de carrera y porque es algo que me parece fascinante desde hace mucho tiempo

Otro proyecto que tengo actualmente es a modo de ayudarme para el PFC, escribir un curso de IA en un blog especializado, aqui podeis ver mi primer post.

Seguiré publicando cuando me sobre tiempo o lo vea oportuno, puede que añada la temática de IA al blog, ya que ese es de los principales motivos por el que nos posteo aquí, la mayoría de los visitantes son de Linux.

Bueno lo dicho, SEGUIRME!:

 

@makiolo

@makiolo

Linux: Limitación de Descarga y Subida a nivel de Kernel

Teoría:

Cuando alcanzamos los límites de nuestra conexión, ya sea en subida y/o en bajada, los tiempos de respuesta (latencia, ping) se disparan, debido a que se están formando colas en el router. Y en general, los routers domésticos, gestionan muy mal las colas (son sistemas embebidos con muy poca memoria).

Por ello, es mejor acumular las colas en nuestros potentes ordenadores, en lugar de nuestros tristes routers que regalan con las portabilidades.

Realmente, lo de acumular la cola en el host, solo sirve para la subida, ya que la subida solo depende de nosotros. La técnica para controlar el límite de bajada es el siguiente: nuestro ordenador recibe paquetes, y tiene capacidad para gestionar todo el flujo pero intencionadamente se descartan paquetes hasta conseguir el flujo deseado. El punto anterior en la traza hasta nosotros, se dará cuenta que estamos descartando paquetes. Todos los routers interpretan esto como congestión, aunque sea congestión simulada. El router emisor se relaja hasta que le aceptemos todos los paquetes, que será cuando alcanzemos el flujo de descarga deseado. El único problema, es que cíclicamente los emisores probarán suerte volviendo aumentar el flujo para ver si hemos superado la congestión, y necesariamente cíclicamente se descartarán paquetes. Esto no es grave, también pasa cuando descargamos algo, y llega al auténtico límite de nuestra conexión, pero es interesante comentarlo.

Todo esto de controlar la congestión mediante colas en el propio host para mantener las latencias se denomina QoS. Calidad de servicio.

Aunque algunos routers caseros han intentado implimentar el QoS, en si experiencia, dejan bastante que desear. Si queremos un QoS de calidad, la única opción es montar un host sobre Linux que hará la función de router, entre otras cosas gestionando todos los flujos con QoS y prácticamente capacidad para colas tan grandes como nuestra capacidad RAM.

Si nuestra LAN es pequeña, este esquema no es barato, tener que tener un pc 24 horas con la función principal de rutear (pero router de calidad empresarial eso sí.). Otra forma sería poner los límites en cada uno de los hosts.

Evidenetemente las restricciones las pondrá un root, para que no haya forma de saltarse los límites de descarga/subida. Esto en Linux en fácil, en Windows, por su mal diseño, te obliga a trabajar como administrador, y por tanto podrías cerrar procesos como NetLimiter que realizan tambien QoS, pero en Windows.

Linux utiliza el comando “tc” para controlar los flujos, pero su uso es realmente extenso, por ello existe un script cuya funcionalidad se limita a un caso de uso muy común (limitar todo el ancho de banda, bajada y subida sin diferenciar Web de Emule, etc …). El script en cuestión es wondershaper.

Bueno, pasamos a lo interesante xD.

Práctica:

Hacemos un test de velocidad, asegurate que nadie use internet, o desenchufa a todos en el switch xD. Necesitamos los datos de la conexión en Kbps (bits). Es decir para 6 Mb de bajada 1 Mb de subida son 6144Kbps / 1024Kbps teorícos pero por el over heat del TCP/IP será un 15-20% menos, supongamos 5100/750. Ese es el limite real, que sera lo que deevuelva un test de velocidad. A ese resultado reducirlo otra 20% más, como margen para permitir una ventana de concurrencia con los demás hosts, quedandose 4080 Kbps / 600 Kbps. Hemos puesto un colchon de un 20%, debeis probar varios valores, entre mayor sea el colchón más asegurado esta el ping. con un 20% debería no subir nunca el ping, pero si de por sí vuestro router es malo(puede repartir mal el tiempo entre bocas), por puede que necesiteis más colchón para asegurar la calidad del servicio. Ahora simplemente INSTALAR Y LIMITAR.

Instalamos el script: sudo apt-get install wondershaper
Con ifconfig miramos nuestro interfaz en uso: Por ejemplo, en mi caso eth0.
Limitramos la conexión: sudo wondershaper eth0 4080 600
Yo aparte me he puesto un alias en el .bash_aliases: alias limitar=’sudo wondershaper eth0′

Ahora hay que hacer pruebas, limitar todos los hosts, aumentar la concurrencia y en todo host debería tener unos tiempos mínimos de latencia. Si realmente necesitas un colchón muy grande, como un 60% o así, es que tienes un problema en tu red, probablemente exceso de colisiones, puede que uses un hub, o que la red sea muy grande y necesites separar los dominios de colisión con routers o puentes.

El script depende de iproute, en otras distribuciones tambien llamado iproute2, en ubuntu viene instalado, pero igual en otras distribuciones no viene.

Cuando ya tengais los valores correctos, para hacerlo definitivos:

1º Editamos: sudo gedit /etc/network/interfaces
2º Y lo dejáis así, pero con vuestros valores :D:

auto lo
iface lo inet loopback
up /usr/sbin/wondershaper eth0 4080 600
down /usr/sbin/wondershaper remove eth0

Existen otras formas, más dinámicas y válidas para cualquier adaptador con los script de if.up e if.down pero a mi me vale así.

Por último para eliminar el QoS (y se puede deducir del paste anterior) escribimos:
sudo wondershaper remove eth0

Ya puedo jugar el Counter Strike, mientras los demás están con el JDownloader, Emule, Torrent … !! :D

Multiprogramación en Linux

He estado programando en multiproceso, para aclarar algunos conceptos, ya que en C++ no tenía mucha experiencia …
He subido el programa a pastebin, por si le puede ser útil a alguien que este empezando:

http://pastebin.com/kkqtc5f1 Se compila sin nada raro: g++ multiproceso.cpp -o multiproceso.

Hago uso de fork(), semaforos compartidos, memoria compartida …

Lo protendo implementar, (mucho más elaborado, y en su sitio), en mi PFC, ya que actualmente tengo un grado de concurrencia, pero solo a nivel de hilos, (multihilo), y ya que estoy planteando el juego de forma muy distribuida, estoy llegando fácilmente a tener entre 500 a 1000 hilos. Con esas cifras, que evidentemente debo reducir, ya que corro el peligro de sufrir mucho overheating en el planificador.

Todavía tengo que hacer pruebas para ver si es viable, pero mi intención es poner en otro proceso la capa de IA al menos, y la capa de animaciones, y tal vez otro procesos más, solo para raycasting. La comunicación entre procesos, pretendo que sea algo parecido al pastebin, pero implimentandome un heap que gestione los huecos.

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.