Ejercicio Liga

Vamos a realizar varias clases para implementar una Liga de Fútbol.

En primer lugar crearemos la clase Equipo, que tendrá un nombre (pedido en el constructor) y puntos. Getters y setters mágicos.

Después la clase Partido, que tendrá un Equipo local y un Equipo visitante y unos goles del local y goles del visitante. En el constructor le pasamos el equipo local y el visitante. Los goles tendrán getter y setter mágicos.

Por último tenemos la clase Liga, que dispondrá de un array con diferentes equipos. Para añadirlos implementaremos la función Add(Equipo). Tendrá también un array de Partidos que incialmente estará vacío. Cuando llamemos a la función crearLiga() nos creará los partidos con los equipos que tengamos.

Un ejemplo:

$a=new Equipo(«Logroñés»);

$b=new Equipo(«ALbacete»);

$c=new Equipo(«Numancia»);

$liga=new Liga();

$liga->add($a);

$liga->add($b);

$liga->add($c);

$liga->crearLiga(); //Nos añadirá a partidos los siguientes partidos: Logroñés-Albacete, Logroñés-Numancia y Albacete-Numancia


class Equipo {

private $nombre;
private $puntos;

function __construct($nombre) {
$this->nombre = $nombre;
}

function __get($name) {
if (!property_exists($this, $name)) {
throw new Exception("La propiedad $name no existe");
}
return $this->$name;
}

function __set($name, $value) {
if (!property_exists($this, $name)) {
throw new Exception("La propiedad $name no existe");
}
$this->$name = $value;
}

}

class Partido {

private $local;
private $visitante;
private $gol_local;
private $gol_visitante;

function __construct(Equipo $local, Equipo $visitante) {
$this->local = $local;
$this->visitante = $visitante;
}

function __get($name) {
if ($name == "gol_local" || $name == "gol_visitante") {
return $this->$name;
} else {
throw new Exception("La propiedad $name no existe");
}
}

function __set($name, $value) {
if ($name == "gol_local" || $name == "gol_visitante") {
$this->$name = $value;
} else {
throw new Exception("La propiedad $name no existe");
}
}

}

class Liga {

private $equipos = [];
private $partidos = [];

function add(Equipo $equipo) {
$this->equipos[] = $equipo;
}

function crearLiga() {
$this->partidos = [];
for ($i = 0; $i < count($this->equipos) - 1; $i++) {
for ($j = $i + 1; $j < count($this->equipos); $j++) {
$this->partidos[] = new Partido($this->equipos[$i], $this->equipos[$j]);
}
}
}

function crearLigaIdayVuelta() {
$this->partidos = [];
foreach ($this->equipos as $local) {
foreach ($this->equipos as $visitante) {
if ($local != $visitante) {
$this->partidos[] = new Partido($local, $visitante);
}
}
}
}

}

Ejercicio: Clase complejo

Crear una clase para trabajar con números complejos.

class Complejo

Tendrán una parte real y una imaginaria, ambas de tipo float. Deben inicializarse en el constructor.

Crearemos las siguientes funciones:

sumar(complejo) ->Suma al número el número complejo que le pasamos

multiplicar(complejo)->Multiplica por el complejo que le pasamos

igual(complejo) -> devuelve true si los números complejos son iguales

Todas estas funciones trabajan con el propio número. Veamos un ejemplo:

$c=new Complejo(2,3);

$d=new Complejo(1,4);

$c->suma($d);

Ahora $c vale (3,7), es decir, la suma de $c y $d. Todas las funciones se aplican al propio objeto.

Además las propiedades deben ser de tipo privado, accederemos a través de setter y getter mágicos.

Crearemos una función mágica tostring que nos pinte el número complejo en su forma acostumbrada (a+bi)

Crearemos también una propiedad virtual de sólo lectura que nos devuelva el valor absoluto del número complejo. El valor absoluto viene definido por la raíz cuadrada de la suma del cuadrado de a y b


class Complejo {

private $real;
private $imaginaria;

function __construct(float $real, float $imaginaria) {
$this->real = $real;
$this->imaginaria = $imaginaria;
}

function sumar(Complejo $complejo) {
$this->real += $complejo->real;
$this->imaginaria += $complejo->imaginaria;
}

function multiplicar(Complejo $complejo) {
$real = $this->real * $complejo->real -
$this->imaginaria * $complejo->imaginaria;
$imaginaria = $this->real * $complejo->imaginaria +
$this->imaginaria * $complejo->real;
$this->real=$real;
$this->imaginaria=$imaginaria;
}

function igual(Complejo $complejo) {
return $this->real == $complejo->real && $this->imaginaria == $complejo->imaginaria;
}

function __get($name) {
if ($name=="absoluto"){
return sqrt($this->real**2+$this->imaginaria**2);
}
if (!property_exists($this, $name)) {
throw new Exception("La propiedad $name no existe");
}
return $this->$name;
}

function __set($name, $value) {
if (!property_exists($this, $name)) {
throw new Exception("La propiedad $name no existe");
}
$this->$name = $value;
}

function __toString() {
return $this->real . " + " . $this->imaginaria . "i";
}

}

¿Un return o varios?

La cosa no está clara:

https://stackoverflow.com/questions/36707/should-a-function-have-only-one-return-statement

Artículo sobre el tema:

https://www.anthonysteele.co.uk/TheSingleReturnLaw

Una buena práctica:

Minimize the number of returns in each routine. It’s harder to understand a routine if, reading it at the bottom, you’re unaware of the possibility that it returned somewhere above.

Use a return when it enhances readability. In certain routines, once you know the answer, you want to return it to the calling routine immediately. If the routine is defined in such a way that it doesn’t require any cleanup, not returning immediately means that you have to write more code.

Escribir en fichero


string docPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
StreamWriter outputFile = new StreamWriter(Path.Combine(docPath, "salida.txt")));
outputFile.WriteLine("Esto es una línea");
outputFile.WriteLine("Esto es otra");
outputFile.Close();

Kata: Dilema del prisionero

El Dilema del prisionero es un clásico de la teoría de juegos. El enunciado clásico es así:

<i>La policía arresta a dos sospechosos. No hay pruebas suficientes para condenarlos y, tras haberlos separado, los visita a cada uno y les ofrece el mismo trato. Si uno confiesa y su cómplice no, el cómplice será condenado a la pena total, diez años, y el primero será liberado. Si uno calla y el cómplice confiesa, el primero recibirá esa pena y será el cómplice quien salga libre. Si ambos confiesan, ambos serán condenados a seis años. Si ambos lo niegan, todo lo que podrán hacer será encerrarlos durante un año por un cargo menor.</i>

Lo curioso del caso es que la mejor estrategia conjunta es callarse, pero la mejor estrategia individual es confesar. El juego se ha transformado en una versión en la que los participantes ganan dinero dependiendo de lo que elijan. La matriz de pago suele ser la siguiente:

Cooperar Desertar
Cooperar 3, 3 -5, 5
Desertar 5, -5 -1, -1

Cada jugador elige de antemano lo que va a hacer. Si los dos han decidido cooperar gana cada uno 3€. Si los dos deciden desertar pierden cada uno 1€. Si uno deserta y el otro coopera el que deserta gana 5€ y el que coopera pierde 5€.

Como es imaginable hay muchas estrategias si tenemos que jugar varias veces este juego. Podemos cooperar siempre, desertar siempre, reaccionar a lo que haga el otro jugador, jugar al azar…

Para probar diferentes estrategias vamos a programar un juego que permita varios jugadores, cada uno con su estrategia, y los va a enfrentar uno a uno con la matriz de pagos puesta más arriba. Los enfrentamientos tienen 50 rondas cada uno. Al final de cada enfrentamiento los jugadores habrán ganado o perdido dinero. Se sumarán los importes y se mostrará una clasificación.

Por ejemplo, tenemos los jugadores Pánfilo, cuya estrategia es cooperar siempre, Maquiavelo, que siempre deserta y Tuntún, que elige al azar. Se enfrentarían siguiendo el esquema:

Maquiavelo-Pánfilo

Maquiavelo-Tuntún

Pánfilo-Tuntún

Cada enfrentamiento implica jugar 50 veces seguidas al dilema del prisionero. Por ejemplo, en Maquiavelo Pánfilo sería algo como esto:

Maquiavelo: Deserta | Pánfilo: Coopera (Maquiavelo gana 5€ y Pánfilo pierde 5€)

Maquiavelo: Deserta | Pánfilo: Coopera (Maquiavelo gana 5€ y Pánfilo pierde 5€)

(Así 50 veces) El resultado final es que Maquiavelo habrá ganado 250 € y Pánfilo habrá perdido 250 €

Una vez realizados todos los enfrentamientos se mostrará el ranking por dinero obtenido.

Para la realización del ejercicio pensad primero en el enfoque: Qué clases vais a implementar, si conviene utilizar interfaces, etcétera.