Genetic Algorithm & Binding

Genetic Algorithm & Binding
Ya que sabemos como implementar un algoritmo genético básico con la Interface de Waki, vamos a usar el algoritmo genético de ordenamiento del tablero de ajedrez del post Interface. Algoritmo Genético II y crearemos una interfaz gráfica con WPF y como no, aplicaremos lo que sabemos con Binding.
Lo primero que vamos a hacer es que la clase ChessBoard implemente la interfaz INotifyPropertyChanged del namespace System.ComponentModel. Una vez hecho esto, añadimos el evento public event PropertyChangedEventHandler PropertyChanged y creamos un método que realice la llamada. Ahora que ya podemos notificar cambios en las propiedades, le incluimos una llamada a este método desde la propiedad BestParent, es decir, cada vez que se encuentre una solución parcial en el algoritmo queremos que actualice la pantalla, para ello cambiamos también la propiedad Bestparent por su equivalente de propiedad completa.

public event PropertyChangedEventHandler PropertyChanged;

public void OnPropertyChanged(string property)
{
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
private List bestparent;

public List BestParent
{
        get { return bestparent; }
        set
        { 
            bestparent = value;
            OnPropertyChanged(nameof(BestParent));
        }
}

A la clase ChessPiece le he añadido una propiedad nueva llamada Picture para incluirle la forma de la pieza de ajedrez.
Acto seguido, preparamos nuesto código XAMl, donde yo lo que he hecho, como nuestra clase ChessBoard era una lista de objetos ChessPiece, no he cambiado a coordenadas y simplemente he incluido 64 Textblock, uno por casilla y el DataContext de cada Textblock es el que corresponde a cada objeto de la lista de objetos ChessPiece. Posteriormente cada Textblock tendrá un style asociado donde se le crea el Binding con el texto o la figura de ajedrez. (Las piezas de ajedrez son caracteres Unicode. ♜♞♝♛♚♟♖♘♗♕♔♙).
El estilo aplicado a cada Textblock es el siguiente:

<Style x:Key="piece" TargetType="TextBlock">
            <Setter Property="Text" Value="{Binding Picture}"/>

Código XAML

<Window x:Class="ChessBoardProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ChessBoardProject"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="20*"/>
            <ColumnDefinition Width="20"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="20"/>
            <RowDefinition Height="20*"/>
            <RowDefinition Height="20"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="board">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="55"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="55"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="55"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="50"/>
                <RowDefinition Height="55"/>
            </Grid.RowDefinitions>
            

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="0" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="0" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="1" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="1" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="2" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="2" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="3" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="3" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="4" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="4" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="5" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="5" Grid.Column="7"/>

            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="0"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="1"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="2"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="3"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="4"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="5"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="6" Grid.Column="6"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="6" Grid.Column="7"/>

            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="0"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="1"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="2"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="3"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="4"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="5"/>
            <Rectangle Style="{StaticResource blackCell}" Grid.Row="7" Grid.Column="6"/>
            <Rectangle Style="{StaticResource whiteCell}" Grid.Row="7" Grid.Column="7"/>

            <Rectangle Fill="Transparent" Stroke="Black" StrokeThickness="3" Grid.RowSpan="8" Grid.ColumnSpan="8"/>

            <TextBlock DataContext="{Binding BestParent[0]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[1]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[2]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[3]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[4]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[5]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[6]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[7]}" Style="{StaticResource piece}"  Grid.Row="0" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[8]}" Style="{StaticResource piece}"   Grid.Row="1" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[9]}" Style="{StaticResource piece}"   Grid.Row="1" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[10]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[11]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[12]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[13]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[14]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[15]}" Style="{StaticResource piece}"  Grid.Row="1" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[16]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[17]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[18]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[19]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[20]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[21]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[22]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[23]}" Style="{StaticResource piece}"  Grid.Row="2" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[24]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[25]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[26]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[27]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[28]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[29]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[30]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[31]}" Style="{StaticResource piece}"  Grid.Row="3" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[32]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[33]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[34]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[35]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[36]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[37]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[38]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[39]}" Style="{StaticResource piece}"  Grid.Row="4" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[40]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[41]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[42]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[43]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[44]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[45]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[46]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[47]}" Style="{StaticResource piece}"  Grid.Row="5" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[48]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[49]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[50]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[51]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[52]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[53]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[54]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[55]}" Style="{StaticResource piece}"  Grid.Row="6" Grid.Column="7"/>

            <TextBlock DataContext="{Binding BestParent[56]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="0"/>
            <TextBlock DataContext="{Binding BestParent[57]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="1"/>
            <TextBlock DataContext="{Binding BestParent[58]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="2"/>
            <TextBlock DataContext="{Binding BestParent[59]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="3"/>
            <TextBlock DataContext="{Binding BestParent[60]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="4"/>
            <TextBlock DataContext="{Binding BestParent[61]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="5"/>
            <TextBlock DataContext="{Binding BestParent[62]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="6"/>
            <TextBlock DataContext="{Binding BestParent[63]}" Style="{StaticResource piece}"  Grid.Row="7" Grid.Column="7"/>
        </Grid>
        <Button Content="Start" Grid.Column="1" HorizontalAlignment="Right" Grid.Row="1" VerticalAlignment="Bottom" Width="75" Margin="20" Click="Button_Click"/>
    </Grid>
   
</Window>

Para no bloquear la interfaz, creamos una tarea y ejecutamos. Le he puesto un retardo de unos cuantos milisegundos en cada solución parcial para ver como actua el algoritmo y el resultado.
ScreenCapture_05-09-2020 12.44.10.gif
Licencia Creative Commons
Esta obra está bajo una Licencia Creative Commons Atribución-CompartirIgual 4.0 Internacional.

Anuncio publicitario

Dead XOR Alive

Dead XOR Alive

En uno de mis blogs, en Arithmos, publiqué un post sobre una historia de carceleros y presos; minutos después de acabar el artículo, dije, ¿por qué no hago una app que lo muestre?, dicho y hecho, me puse y en una tarde desarrollada estaba.

Y ¿por qué digo esto? para demostrar lo fácil que es desarrollar una pequeña aplicación con C# y WPF.

Si leen el artículo, podrán observar que la aplicación solo muestra un tablero de ajedrez, con monedas en cada casilla con una cara o una cruz aleatoriamente, un cuadro mágico que es el elegido por el carcelero y un cuadro del tablero que debe calcular uno de los presos para que el siguiente convicto les salve de la muerte, este último cuadro no es otro que una operación XOR.

El modelo podría ser una clase Chessboard que alberga objetos del tipo CoinBox, las monedas que ya de camino le diremos que color tiene el cuadro donde se apoyan en el tablero.

    public class Chessboard
    {
        public List CoinsBox { get; set; }

        public Chessboard() : this(-1) { }

        public Chessboard(int headsCount)
        {
            CoinsBox = new List();
            FillChessboard(headsCount);
        }

        ///
        /// Rellena el tablero con cuadros y monedas aleaotorias con cara y cruz
        /// 

        /// Número de caras. si es -1, se genera aletoriamente
        void FillChessboard(int headsCount)
        {
            var random = new Random();

            headsCount = headsCount == -1 ? random.Next(64) : headsCount;

            // Llenar Lista con monedas con cruz
            Enumerable.Range(0, 64).ToList()
            .ForEach(n => CoinsBox.Add(new CoinBox(n, false, (n / 8) % 2 == 0 ? n % 2 == 0 : n % 2 != 0)));

            // Cambiar n monedas a cara
            Enumerable.Range(0, headsCount).ToList().ForEach(n => CoinsBox[random.Next(64)].IsHeads = true);

            // Cuadro mágico
            CoinsBox[random.Next(64)].IsMagicBox = true;

            // Cuadro que debe cambiar
            var changed= CoinsBox
                .Where(n => n.IsHeads).Aggregate(MagicBox.Index, (acum, n) => acum ^ n.Index, op => op);
            CoinsBox[changed].IsChangedBox = true;

        }

        public CoinBox MagicBox => CoinsBox.Where(n => n.IsMagicBox).FirstOrDefault();
        public CoinBox ChangedBox => CoinsBox.Where(n => n.IsChangedBox).FirstOrDefault();
        public int ParityChessboard => CoinsBox
                .Where(n => n.IsHeads).Aggregate(0, (acum, n) => acum ^ n.Index, op => op);

        public string ParityChessboardToString => $"La paridad del tablero es {ParityChessboard}";
        public string ResultToString => $"Si cambiamos la moneda {ChangedBox.Index}, la paridad del tablero será {MagicBox.Index} que es el cuadrado mágico!!!";
        public string MagicBoxToString => $"El cuadro mágico seleccionado por el carcelero es el número {MagicBox.Index}";
        public string ChangeBoxToString => $"La moneda que debe cambiar el convicto es la número {ChangedBox.Index}";
        public string ListaXORToString => $"La operación XOR de las monedas que tienen cara {string.Join(", ", CoinsBox.Where(k => k.IsHeads).Select(i => i.Index))} y el cuadro mágico {MagicBox.Index} da como resultado {ChangedBox.Index} o la operación XOR entre el cuadro mágico {MagicBox.Index} y la paridad del tablero {ParityChessboard} es {ChangedBox.Index}";
    }

    public class CoinBox
    {

        public CoinBox(int index, bool isHeads, bool isBlack)
        {
            Index = index;
            IsHeads = isHeads;
            IsBlack = isBlack;
        }

        public int Index { get; set; }

        public bool IsHeads { get; set; }

        public bool IsTails { get { return !IsHeads; } }

        public bool IsChangedBox { get; set; }

        public bool IsMagicBox { get; set; }

        public bool IsBlack { get; set; }
    }

Como algo particular, la asignación del color del cuadro mediante la operación (n / 8) % 2 == 0 ? n % 2 == 0 : n % 2 != 0) con la que con el índice del cuadro le decimos si el cuadro es negro o blanco o las expresiones lambda que calculan la operación XOR sobre una lista de elementos mediante la función lambda Aggregate, la cual le pasamos un parámetro acumulador inicial y posteriormente es usado elemento a elemento con la operación XOR.Para la vista, he creado un control definido por el usuario llamado Box, el cual contiene el Binding cambiando su aspecto según las propiedades del objeto CoinBox asociado a su Datacontext. Como podéis ver a continuación, creo converter para transformar valores booleanos en Visibility, Brush o Bitmap. (Si alguien los quiere los converter, los cuelgo)

<UserControl x:Class="DxorAlive.Box"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:DxorAlive"
             mc:Ignorable="d" 
             d:DesignHeight="43" d:DesignWidth="43" Margin="1">
    <UserControl.Resources>
        <local:BoolToVisibleConverter x:Key="b2tvc" Reverse="False"/>
        <local:ImageConverter x:Key="itc"/>
        <local:BoolToColorConverter x:Key="btcc"/>
    </UserControl.Resources>
    <Grid>

        <Rectangle Width="64" Height="64" Stroke="Gray" StrokeThickness="1" Fill="{Binding IsBlack, Converter={StaticResource btcc}}"/>
        <Rectangle Width="62" Height="62" Stroke="Red" StrokeThickness="2" Visibility="{Binding IsMagicBox, Converter={StaticResource b2tvc}}"/>
        <Rectangle Width="60" Height="60" Stroke="Orange" StrokeThickness="2" Visibility="{Binding IsChangedBox, Converter={StaticResource b2tvc}}"/>
        <Image Source="{Binding IsHeads, Converter={StaticResource itc}}" Height="48"/>
    </Grid>
</UserControl>

Ahora solo nos queda crear o con xml o desde la clase de la vista (runtime) una matriz de objetos cada uno con su datacontext. Yo lo he he desarrollado con código en vez de crear 64 cuadros del tipo Box. Llamamos al método FillChessboard y se genera un nuevo tablero.

        private void FillChessboard(int headsCount)
        {
            grid.Children.Clear();
            // Crear tablero
            var cb = new Chessboard(headsCount);

            //crear cuadros y monedas
            cb.CoinsBox.ForEach(n =>
            {
                var c = new Box();
                c.DataContext = n;
                var row = n.Index / 8;
                var col = n.Index % 8;
                Grid.SetRow(c, row);
                Grid.SetColumn(c, col+1);
                grid.Children.Add(c);
            });

            this.DataContext = cb;

        }

he aquí el resultado. Un saludo a tod@s

deadxoralive1.png
Os dejo el enlace del ejecutable

PD: Y como llevo una temporada enamorado de Kotlin, os paso código en este lenguaje para una app de consola. I ♥ kt

 
import kotlin.random.Random

fun main(args: Array) {
    val c= Chessboard(5)
    println(c)

}


class Chessboard(var headsCount: Int) {
    val coinsBox = mutableListOf()

    init {
        headsCount = if (headsCount == -1) Random.nextInt(64) else headsCount
        fillChessboard()
    }

    private fun fillChessboard() {
        // Rellenar de monedas
        (0..63).toList().forEach {
            coinsBox.add(CoinBox(it, false, if ((it / 8) % 2 == 0) (it % 2 == 0) else (it % 2 != 0)))
        }
        // Caras
        (0..headsCount!!).toList().forEach { coinsBox[Random.nextInt(64)].isHeads = true }
        // cuadro mágico
        val vMB = Random.nextInt(64)
        coinsBox[vMB].isMagicBox = true
        // moneda cambiante
        coinsBox[coinsBox.filter { i-> i.isHeads }.fold(vMB) { acc, opXOR -> acc.xor(opXOR.index) }].isChangedBox=true

    }

    override fun toString(): String {
        return "$magic\n$parityToString\n$changed\n$result\n$listaXOR\n$chessboard"
    }

    val magicBox = coinsBox.filter { n -> n.isMagicBox }.firstOrNull()
    val changedBox = coinsBox.filter { n -> n.isChangedBox }.firstOrNull()
    val parityChessBoard = coinsBox[coinsBox.filter { i-> i.isHeads }.fold(0) { acc, opXOR -> acc.xor(opXOR.index) }]

    val parityToString= "La paridad del tablero es ${parityChessBoard.index}"
    val result = "Si cambiamos la moneda ${changedBox?.index}, la paridad del tablero será ${magicBox?.index} que es el cuadrado mágico"
    val magic = "El cuadro seleccionado por el carcelero es el número ${magicBox?.index}"
    val changed = "La moneda que debe cambiar el convicto es la número ${changedBox?.index}"
    val listaXOR = "La operación XOR de las monedas que tienen cara ${coinsBox.filter { k-> k.isHeads }.joinToString(", "){it.index.toString()}} " +
            "y el cuadro mágico ${magicBox?.index} da como resultado ${changedBox?.index} " +
            "\no la operación XOR entre el cuadro mágico ${magicBox?.index} y la paridad del tablero ${parityChessBoard.index} es ${changedBox?.index}"
    val chessboard = coinsBox.joinToString("") {k-> "\t${k.index} ${if (k.isHeads) "H" else "T"} ${if ((k.index+1) % 8==0) "\n" else ""}"  }

}


data class CoinBox(
    val index: Int,
    var isHeads: Boolean,
    var isBlack: Boolean,
    var isChangedBox: Boolean = false,
    var isMagicBox: Boolean = false