Ultimo Codigo

Después de mucho código e intentos tenemos un resultado de la parte de fechas y torneos, las consultas y sus respectivos resultados se encuentran abajo. también adjunto el código para poder realizar sus pruebas. Saludos.



CÓDIGO VISUAL



CONSULTAS




CÓDIGO PARA COPIAR

equipo(boca).
equipo(river).
equipo(racing).
equipo(independiente).

partidos(
       [A,B,C,D],
       [
  partido(A,B), partido(C,D),
  partido(A,D), partido(B,C),
  partido(A,C), partido(B,D)
       ]
      ).

fechas(
       [A,B,C,D],
       [
  fecha(1,[partido(A,B), partido(C,D)]),
  fecha(2,[partido(A,D), partido(B,C)]),
  fecha(3,[partido(A,C), partido(B,D)])
       ]
      ).

torneoIda(
       [A,B,C,D],'Torneo una sola Vuelta',
       [
  fecha(1,[partido(A,B), partido(C,D)]),
  fecha(2,[partido(A,D), partido(B,C)]),
  fecha(3,[partido(A,C), partido(B,D)])
       ]
      ).

torneoIdaVuelta(
       [A,B,C,D],'Torneo Ida y Vuelta',
       [
  fecha(1,[partido(A,B), partido(C,D)]),
  fecha(2,[partido(A,D), partido(B,C)]),
  fecha(3,[partido(A,C), partido(B,D)])
       ],
       [
           fecha(4,[partido(B,A), partido(D,C)]),
  fecha(5,[partido(D,A), partido(C,B)]),
  fecha(6,[partido(C,A), partido(D,B)])

       ]
      ).


% Consulta Partidos
% partidos([boca,river,racing,independiente], ListadoPartidos).
%
% Consulta Fechas
% fechas([boca,river,racing,independiente],ListadoFechas).
%
% Consulta Torneo Solo Ida
% torneoIda([boca,river,racing,independiente],NombreDelTorneo,ListadoFechas).
%
% Consulta Toneo Ida Vuelta
% torneoIdaVuelta([boca,river,racing,independiente],NombreDelTorneo,FechasIda,FechasVuelta).

Introducción a los paradigmas de programación.




En este blog intentaré desarrollar acerca de los paradigmas de programación, haciendo posteriormente énfasis en uno específico.
Primero, comencemos por lo más básico, la pregunta que todos suponen pero nadie se plantea generalmente. Todos saben que hay diversos paradigmas en el área de programación, pero ¿Qué es un paradigma?

Hay varias definiciones para el mismo:

  •  Según la R.A.E. (Real Academia Española): la palabra paradigma procede del griego paradeigma, que significa: Ejemplo o modelo.
  • Thomas S. Kuhn (1962) 1 en su libro “La Estructura de las Revoluciones Científicas”, considera que el paradigma es un ejemplo o un esquema básico de interpretación de la realidad.
  • Adam Smith define paradigma, en su libro “Los poderes de la mente”, como “un conjunto compartido de suposiciones”.
  • F. Alonso Amo, en su libro “Paradigmas de Programación”, define paradigma “como ejemplo a seguir y como modelo o marco de referencia filosófico/conceptual/cultural/social/moral.”

En conclusión a las definiciones anterior volvemos al tema principal, que es un ¿Paradigma de programación? Aunque en base a las definiciones anteriores con un poco de deducción se podría formar una posible respuesta, vamos a desarrollar un poco el tema, desde lo más básico.

  •  Los paradigmas de programación fue aplicado por primera vez por Robert Floyd en coautoría con Richard Beigel en donde se definió el concepto de Paradigma de Programación como un proceso de diseño que va más allá de una gramática, semántica y algoritmos, sino que es un conjunto de métodos sistemáticos aplicables en todos los niveles de diseño de programas.
  • F. Alonso Amo, en su libro “Paradigmas de Programación”, define paradigmas de programación como “los pilares que definen el desarrollo informático de los programas y por extensión el desarrollo computacional”.
  • Otra definición: Paradigma de programación es una propuesta tecnológica que es adoptada por una comunidad de programadores cuyo núcleo central es incuestionable en cuanto a que unívocamente trata de resolver uno o varios problemas claramente delimitados.



Bueno, ahora que están establecidas las bases del tema se puede adentrar un poco más profundo. Los paradigmas están separados en distintos subgrupos, cuya cantidad varía según los autores; eso es exactamente lo que demostraremos ahora exponiendo distintos puntos de vistas o enfoques.



















Como verán, se presentan algunos diversos puntos de vistas acerca de como separar o diferenciar los distintos paradigmas de programación. Pero para desarrollarlos cada uno por separados en este caso usaremos el caso de la primer imagen (el que refiere como 4 paradigmas separados).




1- Paradigma Imperativo: 

"Este paradigma se caracteriza porque presenta como idea central un modelo abstracto de una computadora que consiste en un gran almacenamiento de memoria, en la que se incorporan unos datos que posteriormente son transformados en unos resultados."
                                                             (F. Alonso Amo, Paradigmas de Programación, 2003)


En la programación imperativa se describen sentencias que modifican el estado de un programa. La implementación de hardware de la mayoría de las computadoras es imperativa; prácticamente todo hardware de las computadoras está diseñado para ejecutar código de máquina, el cual es nativo de las mismas, escrito en forma imperativa, esto se debe a que el hardware de las computaras implementa el paradigma  de las Máquinas de Turing.En este paradigma se expresa como debe solucionarse un problema especificando una secuencia de acciones a realizar a través de uno o más procedimientos denominados sub-rutinas o funciones.
Los lenguajes imperativos de alto nivel usan variables y sentencias más complejas, pero aún siguen el mismo paradigma.

Las características fundamentales de este paradigma son [Ghezzi, 1986]:

  • Concepto de celda de memoria ("variable") para almacenar valores.
  • Operaciones de asignación
  • Repetición

Algunos lenguajes de programación que utilizan/pertenecen a este paradigma:
  • Representado por: C, BASIC, PASCAL.
  • Otros lenguajes: Fortran, Perl, PHP, Java, LUA, Go, Python.


2- Paradigma Funcional: 

Este paradigma concibe a la computación como la evaluación de funciones matemáticas y evita declarar y cambiar datos para producir mejores efectos y que sus resultados sean más eficientes. La función se define basándose en procedimientos y ésta puede ser recursiva.

El lenguaje funcional posee cuatro componentes:

  • Un grupo de funciones primitivas
  • Un grupo de formas funcionales
  • La operación de la aplicación
  • Un grupo de datos
Su utilidad radica en conseguir lenguajes expresivos y matemáticamente elegantes, en los que no sea necesario bajar al nivel de la maquina para describir el proceso llevado a cabo por el programa, y evitando el concepto de estado del cómputo.

Este lenguaje es apreciado por presentar ciertas ventajas:

  • Elegancia, claridad, sencillez, potencia y concisión
  • Semánticas claras, simples y matemáticamente bien fundadas.
  • Cercanos al nivel de abstracción de las especificaciones de los problemas a resolver
  • Referencialmente transparentes
  • Altas dosis de paralelismo implícito
  • Aplicaciones variadas
  • Es bastante útil para el desarrollo de prototipos
  • Ausencia de efectos colaterales
  • Proceso de depuración menos problemático
  • Pruebas de unidades más confiables
Algunos lenguajes de programación que utilizan/pertenecen a este paradigma:
  • Representado por: Scheme o Haskell
  • Otros lenguajes: Miranda,  Scala, Lisp, Clojure, Ocaml, SAP Standard ML

3- Paradigma Lógico: 

Se basa en la definición de reglas lógicas para luego, a través de un motor de inferencias lógicas, responder preguntas planteadas al sistema y así resolver los problemas. Este paradigma está dentro del paradigma de programación declarativa junto con el funcional.
Sus campos de aplicación principales son el área de Sistemas Expertos, e Inteligencia Artificial. La mayoría de los lenguajes de programación lógica se basan en la teoría lógica de primer orden, aunque también incorporan algunos comportamientos de orden superior como la lógica difusa.
Por su esencia declarativa, un programa lógico no tiene un algoritmo que indique los pasos que detallen la manera de llegar a un resultado, sino que es el sistema internamente el que proporciona la secuencia de control. No existe el concepto de asignación de variables, sino el de unificación.

Presenta ciertas características principales:

  • Sintaxis y semántica bien definidas
  • Reglas de inferencia
  • Caracterización de propiedades y relaciones
  • Doble dirección (Entrada/Salida) de los datos
  • Datos parcialmente construidos

Algunos lenguajes de programación que utilizan/pertenecen a este paradigma:
  • Representado por: PROLOG.
  • Otros lenguajes: LISP, CLIPS.



2- Paradigma Orientado a Objetos (PaOO):

está basado en la idea de encapsular estado y operaciones en objetos. En general, la programación se resuelve comunicando dichos objetos a través de mensajes (programación orientada a mensajes). Su principal ventaja es la reutilización de códigos y su facilidad para pensar soluciones a determinados problemas. Introduce nuevos conceptos, que superan y/o amplían conceptos antiguos ya conocidos. Entre ellos están:

  • Clase
  • Herencia
  • Objeto
  • Método
  • Evento
  • Mensaje
  • Atributo
  • Estado interno
  • Componentes de un objeto
  • Representación de un objeto
También, por otro lado, la POO (Programación Orientada a Objetos), posee algunas características que, aunque hay cierto desacuerdo sobre cuáles lo definen como "orientado a objeto" cabe nombrarlas por su importancia, las mas destacadas son:
  • Abstracción
  • Encapsulamiento
  • Principio de ocultación
  • Polimorfismo
  • Herencia
  • Recolección de basura

Algunos lenguajes de programación que utilizan/pertenecen a este paradigma:
  • Representado por: Smalltalk.
  • Otros lenguajes: Java, Php, Perl, Bash, ASP

En conclusión, si bien es importante tanto el paradigma a utilizar como el lenguaje, no son una única alternativa, existen diversos lenguajes de programación que son capaces de utilizar más de un paradigma, a continuación muestro algunos ejemplos para concluir parcialmente el tema.

LENGUAJES QUE AL MENOS SOPORTAN DOS PARADIGMAS:

  • Scala: Imperativo, orientado a objetos, funcional, genérico y concurrente
  • Erlang: Funcional, concurrente y distribuido
  • Perl: Imperativo, orientado a objetos y funcional
  • PHP: Imperativo, orientado a objetos, funcional y reflexivo
  • JavaScript: Imperativo, orientado a objetos (prototipos) y funcional
  • Java: Imperativo, orientado a objetos, reflexivo y genérico
  • Python y Ruby: Imperativo, orientado a objetos, reflexivo y funcional
  • C++: Imperativo, orientado a objetos, funcional y genérico
  • C#: Imperativo, orientado a objetos, funcional (lambda), reflexivo y genérico





Fuentes:

Paradigma Logico




Introducción:
Antes de adentrar en el tema de la programación lógica primero debemos iniciar por recordar que tipo de programación es y dar una pequeña introducción al tema.



Programación declarativa:


Paradigma de programación que está basado en el desarrollo de programas especificando o declarando un conjunto de condiciones, proposiciones, afirmaciones, restricciones, ecuaciones o transformaciones que describen el problema y detallan solución.
Como explicamos en la entrada anterior, la programación declarativa parte de la unión de dos paradigmas, el paradigma lógico y el funcional. Ahora nos centraremos en el paradigma lógico y en su lenguaje más representativo, Prolog.



Paradigma Lógico:

Existen diversas definiciones para explicar lo que es, pero para dar una idea a modo introductorio la forma más sencilla de resumirlo podría ser: “El paradigma lógico tiene como característica principal la aplicación de las reglas de la lógica para inferir conclusiones a partir de datos”.


¿Cómo se construye un programa lógico?

Se construye especificando la información del problema real en una base de conocimiento en un lenguaje formal. Su forma de proporcionar respuestas no consiste en que la base de datos tenga todos los datos, sino que contenga la información necesaria para poder resolver el problema mediante un mecanismo de inferencia que actúa sobre ella.

Características Principales:


Lógica proposicional:
Este paradigma basa sus fundamentos en las teorías de la lógica proposicional, especialmente un tipo particular de lógica conocido como “lógica de predicados de primer orden”, o más particular aún, las Clausulas de Horn (una conclusión es cierta si lo es simultáneamente todas sus premisas).


Características/Restricciones de la LPO (Lógica de primer orden):

  • Todo nombre debe referir a un objeto 
  • Ningún nombre puede referir a más de un objeto
  • Un objeto puede tener más de un nombre.

Declaraciones:
No posee un algoritmo que detalle los pasos a seguir, el programa es un conjunto de declaraciones formales que describen la solución, estas deben ser correctas por definición. Aquí no existe el concepto de celdas de memoria, sino que las variables son unificadas, cuyos valores temporales se van sustituyendo durante la ejecución del programa.

Backtracking:
Es un mecanismo interno que actúa como control de secuencia. Durante la ejecución, va evaluando y combinando las reglas lógicas de la base de conocimiento para lograr los resultados esperados.

Inversibilidad:
La programación lógica está basada en la noción de que el programa implementa una relación, en vez de una transformación. Los predicados son relaciones, que al no tener predefinido una “dirección” entre sus componentes, permiten que sus argumentos actúen indistintamente como argumentos de entrada y salida. Esta característica se denomina como reversibilidad o inversibilidad. Dado que las relaciones son más generales que las transformaciones, la programación lógica es potencialmente de más alto nivel que la de otros paradigmas.

PROLOG




Historia:

Prolog fue desarrollado por Alain Colmerauer y Philippe Roussel, en Francia, como una herramienta de programación lógica. Interesado por el método de resolución SL, Trudel persuadió a Robert Kowalski para que se uniera al proyecto, dando lugar a una versión preliminar del lenguaje Prolog a finales de 1971 y apareciendo la versión definitiva en 1972. Esta primera versión de prolog fue programada en ALGOL W. Se trataba de un lenguaje totalmente interpretado hasta que David H.D. Warren, desarrollo un compilador capaz de traducir prolog en un conjunto de instrucciones en una maquina abstracta denominada Warren Abstract Machine (WAM). Desde entonces Prolog es un lenguaje semi-interpretado.

En 1995 se establecio un estándar del lenguaje llamado ISO-PROLOG.


Entornos de desarrollo:

Es un lenguaje semi-interpretado. Su funcionamiento es similar a java. El código fuente se complia a un código de byte el cual se interpreta en una maquina virtual denominada Warren Abstract Machine.

El entorno de desarrollo se compone por:


  • Un compilador: transforma el código fuente en código de byte.
  • Un interprete: ejecuta el código de byte.
  • Una biblioteca de entidades: estas bibliotecas son muy amplias. Muchos entornos incluyen unas bibliotecas standart-iso que permiten funcionalidades básicas como manipular cadenas, entrada/salida, etc.


SICStus, SWI-Prolog, CIAO Prolog, y posiblemente otros más, ofrecen entornos integrados generalmente basados en Emacs que resultan muy fáciles de usar. Prácticamente todos ellos son multiplataforma.


Elementos en prolog:

Necesitamos una serie de elementos para el desarrollo en prolog:

  • Átomos: Es una definición genérica de un objeto del mundo que queremos representar.
  • Predicados: Nos permite especificar características de los objetos de nuestro mundo o las relaciones entre ellos.
  • Los nombres de objetos y relaciones deben comenzar con una letra minúscula.
  • Primero se escribe la relación, y luego los objetos separados por comas y encerrados entre paréntesis.
  • Al final de un hecho debe ir un punto (".").

Hechos:


Es algo que esta ocurriendo en el mundo, características o relaciones entre objetos. Suponiendo que se quiera expresar el hecho de que "un coche tiene ruedas". Este hecho, consta de dos objetos, "coche" y "ruedas", y de una relación llamada "tiene". La forma de representarlo en PROLOG es: tiene(coche,ruedas).

Los nombres de objetos y relaciones deben comenzar con una letra minúscula.Primero se escribe la relación y luego los objetos separados por comas y encerrados entre paréntesis.


Variables:

En prolog una variable representa el valor de un átomo. Representa objetos que el mismo prolog determina. Una variable puede estar o no instanciada. Estar instanciada cuando existe un objeto determinado representado por la variable. Los nombres de variables comienzan siempre por una letra mayúscula.Un caso particular es la variable anónima, representada por el carácter subrayado ("_"). Es una especie de comodín que utilizaremos en aquellos lugares que debería aparecer una variable.

Reglas:

Las reglas se utilizan en PROLOG para significar que un hecho depende de uno o mas hechos. Son la representación de las implicaciones lógicas del tipo p ---> q
  • Una regla consiste en una cabeza y un cuerpo, unidos por el signo ":-".
  • La cabeza está formada por un único hecho
  • El cuerpo puede ser uno ó mas hechos (conjunción de hechos), separados por una coma (","), que actúa como el "y" lógico.
  • Las reglas finalizan con un punto (".").






Programando en Prolog:

Se tiene que tener dos cosas en cuenta: la especificación de los hechos y las preguntas sobre esos objetos o relaciones.



Prolog saca la respuesta explorando cada uno de los hechos introducidos en la base de datos hasta encontrar uno que coincida, que será el caso en la que la respuesta será afirmativa o negativa. Se usan operadores lógicos como AND, OR y NOT; Prolog busca satisfacer la primera parte de la pregunta, y si lo es busca en la segunda.


Objetos de datos:

Tipos de datos primitivos y constantes: Enteros, reales, caracteres.

Los identificadores con minúscula representan hechos, los que van con mayúscula variables.
  • Átomos: constantes y variables de cadena.
  • Listas, representadas entre [ ].
  • Tipos definidos por el usuario. Las reglas para definir relaciones pueden actuar como tipos de usuario.




Ventajas y desventajas de la programación lógica

Ventajas:


  • Habilidad para calcular de forma procedural. Las ventajas de la forma declarativa son claras (es más fácil pensar las soluciones y muchos detalles procedurales son resueltos automáticamente por el propio lenguaje) y podemos aprovecharlas.
  • Facilidad para programar ya que se pueden escribir programas rápidamente con pocos errores originando programas claramente legibles, aun si no se conoce bien el lemguaje.
  • No hay que pensar demasiado en la solución del problema, ya que Prolog infiere sus respuestas basándose en las reglas declaradas dentro del programa
  • Prolog utiliza un mecanismo de búsqueda independiente de la base de hechos. Es una buena estrategia puesto que garantiza el proceso de todas las posibilidades.

Desventajas:


  • La resolución automática podría dar una respuesta incorrecta a una consulta. Son poco eficientes.
  • Prolog algunas veces es incapaz de reconocer que un problema es inaplicable o insuficiente. Si el programa no contiene suficiente información para contestar una consulta, es incapaz de reconocerlo y responde no.
  • Los motores de inferencia poseen algunos límites.



Tipos de problema que soluciona prolog:


La evolución histórica de los sistemas expertos también se ha producido a medida que se ha ido desarrollando la inteligencia artificial y los diferentes métodos que han ido empleando para su resolución. El desarrollo de lenguajes como LISP y PROLOG condicionaron esa evolución.

La resolución de juegos y la planificación así como la construcción de agentes inteligentes constituyen amplios campos que abarca la rama de la inteligencia artificial. 



Algunos juegos y programas bastantes populares que se han programado en prolog son:


problema de las 8 reinas

analogía: para resolver cuestiones de analogía  geométrica en tests de inteligencia

sistemas expertos: pueden percibir el ambiente mediante sensores y actúan sobre ese ambiente por medio de efectores.
Compiladores: la construcción de compiladores e interpretes son campos de desarrollo muy adecuados para prolog.
Torres de hanoi

¿Por qué SWI-Prolog?

Próximamente estaremos usando el SWI-Prolog como proyecto de una materia con la finalidad de la acreditación parcial de la materia. El nombre SWI proviene de Sociaal-Wetenschappelijke Informatica ("Informática de Ciencias Sociales").
SWI-Prolog es una implementación open source (código abierto) del lenguaje de programación Prolog. Su autor principal es Jan Wielemaker.
Optamos por la utilización de este recurso debido gran cantidad de bibliotecas, herramientas y, por supuesto, una documentación muy completa y extensiva. Ofrece un servicio muy simple de implementar y a su vez muy potente y eficaz. Es gratuito y puede correr plataformas Windows, Linux y Macintosh.

Igualmente dejo una lista de otras posibilidades para la utilización de prolog:





Fuentes:




Introducción


Es innegable lo complejos que son los problemas que encaran la AFA y otras organizaciones similares en otros países a la hora de organizar sus torneos de fútbol. Todos los equipos tienen que jugar contra todos, pero hay ciertas restricciones que no pueden dejarse de lado: algunos partidos son demasiado importantes y por ende hay que fijar su fecha, hay que asignar árbitros a los partidos, etc.

El objetivo de este trabajo práctico es armar un modelo muy simple en PROLOG que permita generar torneos de todos contra todos basándose en restricciones.

Modelo


Nuestro modelo contempla los siguientes elementos:
  • Equipos: Representamos los equipos como átomos: chivas, monterrey, cruzAzul, etc.
  • Partidos: Los partidos se representan con una función: partido(Equipo1, Equipo2) es el partido donde Equipo1 juega de local contra Equipo2. De esto se desprende que partido(X,Y) es distinto de partido(Y, X).
  • Fechas: Una fecha se describe con la estructura fecha(N, Ps), donde N indica el número de fecha (comienzan a numerarse a partir de 1) y Ps es una lista de partidos. Esta lista representa en realidad un conjunto, con lo cual no debe tener duplicados, y las distintas permutaciones son consideradas equivalentes.
  • Torneos: Representamos un torneo con una lista de fechas, donde los números de fecha comienzan en 1 y crecen sin repetirse. Nosotros consideraremos únicamente torneos de todos contra todos, donde los equipos juegan exactamente una vez en cada fecha (no hay fechas libres ni pueden jugar más de una vez). Por lo tanto, todas las fechas de un torneo tendrán la misma cantidad de partidos.
  • Árbitros: Representamos los árbitros como átomos: elizondo, gimenez, pezzota, etc.

Pautas


  • No es necesario verificar la buena formación de los argumentos. Por ejemplo, que las listas sean efectivamente listas, que contengan elementos esperados y que no tengan repetidos en el caso de conjuntos.
  • Para resolver los ejercicios se pueden usar todos los predicados built-in de SWI-Prolog, pero no el operador cut (!).

Enunciado


Definir un predicado:

torneoIdaYVueltaConCondicionesYArbitros(Equipos, Conds, Arbitros, Torneo).

Verdadero cuando Torneo es un torneo de ida y vuelta para los equipos de Equipos, respetando las restricciones en Conds (condiciones) y dirigido por árbitros de Árbitros.

El torneo resultante tendrá entonces n−1 fechas, donde n es la cantidad de equipos.

La estructura resultante es:

torneo(apertura(FechasLocales), clausura(FechasVisitantes))

donde las FechasVisitantes son el “espejo” de FechasLocales.

Recordar que dos fechas son consideradas iguales si tienen el mismo número y los mismos partidos, no importa en qué orden y con qué repeticiones.

Asignación de arbitros:

Para solucionar el tema de la asignación de árbitros debemos definir un predicado

fechaConArbitros(Arbitros, Fecha, FechaConArbitros)

verdadero cuando FechaConArbitros es una fecha igual a Fecha a la que se han asignado árbitros distintos tomados del conjunto Árbitros. Los elementos de FechaConArbitros serán de la estructura dirigido(partido, arbitro), donde Partido es un partido de Fecha.

Ejemplo:

?- fechaConArbitros([gimenez, pezzota, beligoy],
                             fecha(1, [partido(boca, river),partido(racing, velez)]),
                             Fecha).

Fecha = fecha(1, [dirigido(gimenez, partido(boca, river)),
         dirigido(pezzota, partido(racing, velez))]) ;
Fecha = fecha(1, [dirigido(gimenez, partido(boca, river)),
         dirigido(beligoy, partido(racing, velez))]) ;
Fecha = fecha(1, [dirigido(pezzota, partido(boca, river)),
         dirigido(gimenez, partido(racing, velez))]) ;
Fecha = fecha(1, [dirigido(pezzota, partido(boca, river)),
                             dirigido(beligoy, partido(racing, velez))]) ;

Condiciones


Las condiciones que usaremos son de cuatro tipos:
  1. Hay dos equipos que deben enfrentarse como muy tarde en cierta fecha. Por ejemplo Boca y River deben enfrentarse antes de la fecha 14.
  2. Hay dos equipos que deben enfrentarse exactamente en un cierta fecha. Por ejemplo Lanus y Banfield deben enfrentarse exactamente en la fecha 8.3. 
  3. Hay un conjunto de equipos que pueden enfrentarse entre sí a lo sumo en un partido por fecha. Por ejemplo no puede pasar que River, Boca, Racing, San Lorenzo e Independiente jueguen entre sí en dos partidos la misma fecha: sea como fuera la forma en la que se crucen estos cinco equipos, esto generaría dos clásicos en la misma fecha, lo cual se desea evitar.
  4. Hay un conjunto de equipos que no pueden enfrentarse todos entre sí en la misma fecha. Por ejemplo, no puede pasar que Newell’s, Rosario Central, Colon y Union jueguen en la misma fecha: serían todos los partidos santafesinos juntos, y es mejor repartirlos. 
Ejemplos:
  1. jugarALoSumoEn(Equipo1, Equipo2, NumeroFechaMaxima)
  2. jugarExactamenteEn(Equipo1, Equipo2, NumeroFecha)
  3. noHayDosPartidosEntre(Equipos)
  4. noJueganTodosJuntos(Equipos)

Ejemplo de Programa


?- torneoIdaYVueltaConCondicionesYArbitros(
    [rosarioCentral, belgrano, tiroFederal, chacarita],
    [jugarExactamenteEn(rosarioCentral, belgrano, 2)],
        [gimenez, elizondo, pezzota, baldassi],
        Torneo).

Torneo = torneo(
    apertura([fecha(1,
          [dirigido(gimenez, partido(rosarioCentral, chacarita)),
           dirigido(elizondo, partido(belgrano, tiroFederal))]),
                     fecha(2,
          [dirigido(gimenez, partido(rosarioCentral, belgrano)),
           dirigido(elizondo, partido(tiroFederal, chacarita))]),
                     fecha(3,
         [dirigido(gimenez, partido(rosarioCentral, tiroFederal)),
         dirigido(elizondo, partido(belgrano, chacarita))])]),
    clausura([fecha(1,
         [dirigido(gimenez, partido(chacarita, rosarioCentral)),
         dirigido(elizondo, partido(tiroFederal, belgrano))]),
                     fecha(2,
         [dirigido(gimenez, partido(belgrano, rosarioCentral)),
         dirigido(elizondo, partido(chacarita, tiroFederal))]),
                     fecha(3,
         [dirigido(gimenez, partido(tiroFederal, rosarioCentral)),
         dirigido(elizondo, partido(chacarita, belgrano))])]))

Resolución - Modelo

De a poco voy a ir subiendo mi código de resolución acá, si alguien quiere y puede comentar su código es mejor para la comunidad, ya que es un blog de conocimiento publico,

Código:

% Equipos

equipo('River').
equipo('Boca').
equipo('Independiente').
equipo('San Lorenzo').
equipo('Estudiantes').
equipo('Racing').
equipo('Banfield').
equipo('Lanus').

% equipos(X) devuelve el listado de equipos.

equipos(R) :- findall(X, equipo(X), R).

% Partidos

partidos([],[]).
partidos(Equipos,Partidos) :- perm(2,Equipos,Partidos).

% Permutacion(CantidadDeElementos, Lista, Resultado).

perm(1, Input, [Last]) :-
    member(Last, Input).
perm(N, Input, [First,Second|Perm]) :-
    N > 1, N0 is N-1,
    member(First, Input),
    dif(First, Second),
    perm(N0, Input, [Second|Perm]).

Modelo 2.0

equipo(river).
equipo(boca).
equipo(racing).
equipo(independiente).


partido(X,Y) :- equipo(X), equipo(Y), X \= Y.
listarPartidos(List) :- findall(partido(X,Y),partido(X,Y),List).


listarFechas([],[]).
listarFechas(Partidos,Fechas) :- perm(2,Partidos,Fechas).


perm(1, Input, [Last]) :-
    member(Last, Input).
perm(N, Input, [First,Second|Perm]) :-
    N > 1, N0 is N-1,
    member(First, Input),
    dif(First, Second),
    perm(N0, Input, [Second|Perm]).

Combinatoria en PROLOG

Esta semana investigando sobre PROLOG averiguamos con el grupo sobre combinatoria y como aplicarlo a listas, encontramos lo siguiente:

Permutaciones

Permutación de la lista L es una lista que contiene todos los elementos de la lista L en algún orden .
Codigo:

perm(List,[H|Perm]) :- delete(H,List,Rest),perm(Rest,Perm).
perm([],[]).

delete(X,[X|T],T).
delete(X,[H|T],[H|NT]) :- delete(X,T,NT).

Combinaciones 

La combinación es un subconjunto arbitrario del conjunto que contiene determinado número de elementos. El orden de los elementos es irrelevante.
Codigo:

comb(0,_,[]).
comb(N,[X|T],[X|Comb]) :- N > 0, N1 is N - 1, comb(N1,T,Comb).
comb(N,[_|T],Comb) :- N > 0, comb(N,T,Comb).

Es posible programar el generador de combinaciones sin aritmética . El siguiente procedimiento comb2 asume la lista con N variables libres como su segundo argumento y se une estas variables. Por lo tanto, utilizan ? -comb2 ( [ 1,2,3,4 ] , [X , Y] ) para generar combinaciones con dos elementos.
Codigo:

comb2(_,[]).
comb2([X|T],[X|Comb]):-comb2(T,Comb).
comb2([_|T],[X|Comb]):-comb2(T,[X|Comb]).

Combinaciones con Repetición

Este tipo de combinación puede contener un elemento más veces. Por lo tanto , no es un conjunto, es un multi-conjunto.

Codigo:

comb_rep(0,_,[]).
comb_rep(N,[X|T],[X|RComb]):-N>0,N1 is N-1,comb_rep(N1,[X|T],RComb).
comb_rep(N,[_|T],RComb):-N>0,comb_rep(N,T,RComb).

Variaciones

La variación es un subconjunto dado con número de elementos. El orden de los elementos en la variación es significativa.

Codigo:

varia(0,_,[]).
varia(N,L,[H|Varia]):-N>0,N1 is N-1,delete(H,L,Rest),varia(N1,Rest,Varia).

Variaciones con repetición

Una vez más, este tipo de variación puede contener elementos repetidos .
Codigo:

varia_rep(0,_,[]).
varia_rep(N,L,[H|RVaria]):-N>0,N1 is N-1,delete(H,L,_),varia_rep(N1,L,RVaria).




Prolog - Manejo de Listas

Esta semana nuestro avance se centro principalmente en el manejo de listas, las practicas realizadas fueron las siguientes y se centran en el funcionamiento de la recursividad en las listas en Prolog.

% Longitud de una Lista
% longitud(+Lista,-LongitudLista).

longitud([],0).
longitud([_|T], R2) :- longitud(T,R), R2 is R + 1.

% Invertir una Lista
% invertir(+Lista,-ListaInvertida).
% agregar_final(+Elemento,+Lista,-ListaConElemento).

invertir([],[]).
invertir([Ca|Resto],R2) :- invertir(Resto,R),agregar_final(Ca,R,R2).
agregar_final(E,[],[E]).
agregar_final(E,[Ca|Resto],[Ca|R]) :- agregar_final(E,Resto,R).

% Concatenar dos Listas
% concatena(+Lista1,+Lista2,-ListasConcatenadas).

concatena([],L2,L2).
concatena([Ca|Resto],L2,[Ca|R]) :- concatena(Resto,L2,R).

% Comprimir Lista
% comprime(+Lista,-ListaComprimida).

comprime([Ca1,Ca2|Resto],[(Ca1,1)|R]) :-
Ca1\=Ca2, comprime([Ca2|Resto],R).
comprime([Ca1,Ca1|Resto], [(Ca1,N2)|R]):-
comprime([Ca1|Resto],[(Ca1,N)|R]), N2 is N+1.
comprime([],[]).
comprime([E],[(E,1)]).





Fuentes:

Video Tutoriales de josecarpioc.

Prolog - Predicados Built In

flatten(+ListaAnidada, -ListaPlana)
Es verdadero si ListaPlana es una versión no anidada de ListaAnidada.
intersection(+Conjunto1, +Conjunto2, -Intersección)
Verdadero si Intersección unifica con el conjunto de Conjunto1 y Conjunto2.
length(?Lista, ?Longitud)
Longitud es la longitud de Lista.
maplist(:Goal, ?List)
Verdadero si el Goal se cumple en todos los elementos de la lista.
maplist(:Goal, ?List1, ?List2)
Mapea la lista en pares de elementos entre la lista1 y la lista2.
memberchk(?Elem, +List)
Variante determinista de member/2 en la cual se checkea que List sea una lista.
nth0(?Index, ?List, ?Elem)
True when Elem is the Index'th element of List. Counting starts at 0.
select(?Elem, ?List1, ?List2)
Verdadero cuando Lista1 con el Elem removido da como resultado Lista2.
sublist(:Goal, +List1, ?List2)
Recorre la Lista1 dentro de la Lista2 
subset(+SubConjunto, +Conjunto)

Verdadero si Subconjunto es tal del Conjunto