AdSense

Sunday 14 December 2014

Arduino - Read out height sensor GY-65

(Deutsche Version) A common way to measure relative heights is the usage of a barometric height sensor. Such a sensor measures the pressure and by using the barometric formula (Wikipedia), one can calculate the height. The ambient pressure varies during the days therefore the sensor is calibrated at a well-known height and the other heights are calculated by using this reference pressure and height. The measured heights have a precision of up to 1 meter.

If  you look for the GY-65 at ebay, you can find the sensor for about 5 euro. The sensor has a usual I2C interface so only two wires are needed. Additionally, the I2Cdev library is needed which can be downloaded here. The source code is as simple as possible, at first the sensor is initialised, then measuring the pressure is set and afterwards the pressure is read out and calculated into the height. A basic program looks like this:


#include <I2Cdev.h>
#include "BMP085.h"
#include <Wire.h>

BMP085 barometer;

double pressure;
double altitude;


void setup() {
  Wire.begin();
  
  Serial.begin(9600);
  Serial.println("starting...");
    
  //initialize the barometer
  barometer.initialize();
}

void loop()
{
  // request pressure (3x oversampling mode, high detail, 23.5ms delay).
  // Let's just wait a bit more to be sure...
  barometer.setControl(BMP085_MODE_PRESSURE_3);
  delay(30);
  // read calibrated pressure value in Pascals (Pa)
  pressure = barometer.getPressure();
  // calculate absolute altitude in meters based on known pressure
  // (may pass a second "sea level pressure" parameter here,
  // otherwise uses the standard value of 101325 Pa)
  altitude = barometer.getAltitude(pressure); 
  
  // print back the calculated altitude
  Serial.println(altitude);
  // do this every second
  delay(1000);
}

I2C OLED display

(Deutsche Version) If you look for "Arduino OLED Display" on Ebay, you will find a display with a size of 1 inch and a resolution of 128x84 pixels which is controlled via I2C. It costs less than 4 Euros. Of course, 1 inch isn't much, but I was curious and so I ordered it. To show you how small it really is, I placed a coin next to it:


Connecting the display is very easy (thanks to I2C): you only need the voltage supply and two wire for I2C. But how can you control the display? After some searching on Google I found out that the display is a clonde of the Adafruit OLED display called SSD1306. Adafruit offers an Arduino library for this display which can be downloaded HERE. Additionally you need the Adafruit-GFX-Library. After installing the two libraries you will find the example "ssd1306_128x64_i2c" under "Adafruit_SSD1306" in the Arduino IDE. But if you transmit this example to the Arduino nothing will happen. The china-clone-display has a different I2C adress than the original Adafruit display. You will have to change something in the setup() function. Change
  display.begin(SSD1306_SWITCHCAPVCC, 0x3D);  // initialize with the I2C addr 0x3D (for the 128x64)
to
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64).

After that you can transmit the example to your Arduino and you should see a small demonstration of the different functions of the GFX library on the display. Since there are a lot of functions and the example has a lot of code I will not explain it in detail. I think all of the functions in the example are self-explanatory. I you have problems understanding the code, just have a look in the header file of the GFX library. There you find further explanations like parameters for the functions. You can print text, draw squares, triangles, etc. Even inverting or scrolling the screen is possible.

You also have the possibility to print a user-defined bitmap. I'm going to explain this:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

#define XPOS 50
#define YPOS 25
#define BITMAP_HEIGHT 16 
#define BITMAP_WIDTH  16 
static const unsigned char PROGMEM bitmap[] =
{ B00000001, B10000000,
  B00000010, B01000000,
  B00000100, B00100000,
  B00001000, B00010000,
  B00010000, B00001000,
  B00111111, B11111100,
  B00101000, B00010100,
  B00100100, B00100100,
  B00100010, B01000100,
  B00100001, B10000100,
  B00100010, B01000100,
  B00100100, B00100100,
  B00101000, B00010100,
  B00110000, B00001100,
  B00111111, B11111100,
  B00000000, B00000000 };

void setup()   {                

  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x64)
  
  //clear display buffer
  display.clearDisplay();
  //draw a bitmap stored in variable bitmap with given size at XPOS, YPOS in color white
  display.drawBitmap(XPOS, YPOS, bitmap, BITMAP_WIDTH, BITMAP_HEIGHT, WHITE);
  display.display();
 
}


void loop() { 
}


In this example we are going to draw a bitmap with the size of 16x16 pixels. Of course you can choose another size. The bitmap has to be stored in a character array. It is very important to use the keyword "PROGMEM" when declaring the variable. This will make the Arduino store the variable in the flash memory. The library only accepts bitmaps stored in flash. In the example, two characters store the 16 bit data of a line of the bitmap. If a bit is set, a pixel is set when the bitmap is drawn. To increase readability, line breaks were inserted. On line in the code is on line of the bitmap. To draw the bitmap, you have to call the function drawBitmap(). Parameters are: x- and y-position of the bitmap, the variable in which the bitmap is stored, height und width of the bitmap and its color (BLACK or WHITE) of a set pixel.

The result:

Friday 5 December 2014

Sharpen a brush

(Deutsche Version) A newly bought brush is usually sharp and also a bit hard so you can draw very fine lines. After a while, the hair of the brush starts to point into every direction so you cannot use the brush any more. To get the brush back into the state which it has been after buying, you can use a simple trick.
A used brush which you cannot use for fine details any more.
First you have to create a mixture of sugar and water. Simply mix the two ingredients and stir. Now you may put the brush in the liquid. The surface tension keeps the hair together.
Brush tip with the sugar water mixture applied. The hair is kept together (Surface tension).
To get the brush back into the perfect shape, you have to wipe off the brush off carefully, this gets it even sharper. If the brush dries, the tip gets even better, as good as for a newly bought brush. I use brushes of the size 00, you can get them in every toy's shop. If you take good care of the brush, you should be able to use it forever.
The sharpened brush.

Saturday 15 November 2014

An introdurction to tabletops

(Deutsche Version) Since I have been playing tabletops for quite a while now, I want to post an introduction today because I think that tabletops are the best and most intresting kind of parlour games. Tabletops do exist in many different worlds, I will focus on the fantasy setting. Technologically, a fantasy setting is like in the Middle Ages when gunpowder was just developed. There are many different races like dwarves, elves, orcs, goblins, dragons and many more. Additionally, magic exists as for example a wizard being capable of shooting fire balls.

A tabletop consists of figures which are placed on a table or gaming plate. Well-known producers of tabletop miniatures are for example Kings of War von Mantic Games, Warhammer von Games Workshop, Dwarf Wars von West Wind Productions or Hail Caesar von Warlord Games. Personally, I use the miniatures from Mantic Games because they are quite cheap and have sime interesting units like archangels or brock riders which are not sold by other manufacturers.

The basic principle of a tabletop is two armies (or more) fight against each other, similar to the video games of the series Total War.

Painting and constructing
If you want to start with a tabletop, you have to have an army. Usually there are starter sets, i.e. from Mantic Games, consisting of one or two armies, dice and a rule book. This set then delivers single plastic pieces which have to be painted and constructed. This already offers one point of conflict: Construct first or paint first? Personally, I think that painting first is better, if the figures are already constructed, you cannot paint all places as good as prior to constructing. If you pain first, I would suggest to painting above all places with glue again after construction to have a better look. Another important argument for painting first is that otherwise you can already play with the constructed figures. Painting will be shifted to later and maybe never done, this is responsible for whole armies being unpainted what looks miserably. If you paint first, you can only play with the figures when everything is done, so you have the motivation to paint them.

For construction, I use the well known Revell Contacta glue, you can purchase this cheaply in nearly every toy store. I also use colours from Revell, at first I used the Email colours, they are really strong (except for white) but are rather thick and not easy to handle because they cannot be thinned with water. I later switched to the Revell Aqua colours, they are really easy to handle and can be thinned with water so you can also use different painting techniques like washing by thinning the paint with lots of water. Additionally, the Aqua colours should dry faster (4 hours vs. 1 hour).

If the army is constructed, you can start to play. Therefore you need another player with an army or you simply purchase two armies and let them fight against each other. You can use nearly everything as a gaming field, starting at the carpet or a table to a green felt mat or special gaming mats and even modular terrain as I already described it in this blog. For the beginning, a table is sufficient with some objects like a piece of paper as a swamp, a book as a hill, the only limitation here is your mind.

Rules
I now want to address the rules of these games, especially the rules for kings of war which you can download here on the bottom of the page. Basically, the game is round based, one player after the other. Every player has three parts during his turn.

Movement
At first, movements are executed, every unit has a movement value in inches which describes how far a unit may move. There are special rules for attacking enemies which are explained in the rule books.

Shooting phase
After the movement, ranged attacks are executed, all units which are not in melee may shoot. There are usual ranged infantry units but also artillery and magic attacks, all of them are handled in this round. Let's for example face dwarven crossbowmen (Ironwatch) from Kings of War. They have a ranged ability (Ra) of 5+ and 10 attacks. This means that you have to throw 10 dice and every result of 5 or higher counts as one hit. Next, the damage is calculated. Therefore, every die that hit the enemy is thrown again. If the dwarves for example shoot on orc warriors (Greatax) which have a defense value (De) of 4+, you have to throw now 4 or higher to inflict a point of damage. Afterwards a nerve test is performed, this will be explained below.

Melee phase
After the ranged phase, the melee phase starts. All melees are initiated in the movement phase by bringing your units in contact with the enemy. The melee phase is similar to the shooting phase, except for that the melee value instead of the ranged value is used. Here, also hits and then damage is calculated and afterwards a nerve test has to be performed.

Nerve test
After the shooting and melee phase, a nerve test has to be executed. The nerve test determines whether a unit can still fight or is damaged too heavily, the moral has broken down or the unit has been wiped out completely. Therefore, two dice are thrown and all the damage from the unit has to be added. Every unit has a nerve value, consisting of two numbers. If the sum out of dice and damage is as big as the first number, the unit has lost its moral, can only do some basic movements like going backwards or turn and cannot shoot in the next round. A round later, this effect is gone again. If the sum is as high as the second number, this means that the unit is wiped out. Either all soldiers are dead or they fled and will never return again - this unit will not fight again and has to be removed from the battlefield.

These are the main principles for playing a tabletop. Of course I just showed some simple aspects of tabletops, if you really want to play a tabletop, you should look into the rule book. The different games have different rule sets, personally, I prefer the rules from Kings of War because they are quite simple and still allow a lot of tactical depth, so the game does not only consist of checking special rules and reading in the rule book all the time.

There are other settings where you can find tabletops like e.g. science fiction tabletops which have quite similar rules, and also historical variants, completely without magic. There also exist tabletops in other scales like a space ship fight or a sea fight with ships. I really like Kings of War from Mantic Games best, the scale, 28 mm, is a good compromise between size of units and the size of the details. It also is the most common scale for tabletop miniatures. I hope that I was able to arouse interest for tabletops so more people can discover this amazingly interesting sort of parlour games.

Sunday 2 November 2014

Tabletop terrain - water

(Deutsche Version) The basics of creating your own terrain are quite simple. Construct your model, paint it and add grass or some decorative stuff. Of course you can spend an infinite amount of time for doing this but the basic principle is easy. What I did not try until now was water. The easiest version of water is a simple blue area with a shiny surface. Usually, this does not look that good.

There are several commercial solutions to create nice water which I did not try at all. I used silicone instead, which you can get cheaply, for example at Obi (I used this one from an Obi in Germany). The result looks quite good:
When working with the silicone, you should keep in mind that it dries very fast and sticks to your fingers. Creating a wavy surface is easily achieved, if you want to have a flat surface, this is much harder. Additionally, you should keep in mind that the silicone is not perfectly transparent. Therefore, I would suggest to only use the silicone for a thin layer or the waves effect. If the terrain piece shall also consist of grass, I would highly recommend to applying this before the silicone due to the fact that the small grass pieces stick horribly to the silicone and nearly cannot be removed any more. If you want to create deep water, you can see a test object from me in the next two pictures:

The test object is 1 cm deep. The surface is much flatter but still not a perfect flat surface as you would want to have for a lake. For larger volumes, keep in mind that the silicone does not stick to itself after it has started to dry, this creates white areas which do not look good, as you can see in the pictures.
Compared to the price of other commercial products, the silicone is much cheaper and still looks quite nice.

Siege equipment part I: Siege ladder

(Deutsche Version) Since I explained how to create parts for a castle, I now have to focus on the attackers. As a first step, I want to start with the most easy part, namely the siege ladder.
To create a siege ladder, you need a piece of wood which has a cross-section area of 3x3 mm, I used balsa wood. For a ladder, you need 72 cm. The balsa wood is cut into two pieces of 18 cm length and 9 short pieces of 4 cm. Now, you have to mark the large pieces at the positions 1,3,5,... cm and glue the short parts on them. This completes the siege ladder, you can add some brown color (I would propose watercolour because you still can see the wood structure from below).

Tabletop terrain - hills

(Deutsche Version) In this post I want to introduce some new terrain plates: Hills. As like all my other terrain pieces, I build them from styrofoam. I also use the base plate made from wood on which I glue all the other things.

I defined the height of the hills as 5 cm, this fits to the 28 mm figures. Let's figure out the transition between two terrain pieces. This has to be the same for all hill pieces for being able to combine the terrain in any way. I build the hill from 5 plates of 1 cm thickness which are 8, 9, 10, 11 and 12 cm width. The scheme looks like this:
Now you can build the first basic shapes: Edges and corners. For a corner you need 5 pieces in the size of 12x12, 11x11, 10x10, 9x9, 8x8 cm. These are glued on top of each other fitting to one edge.
Now, this looks a bit like a hill. To improve it, you can easily tear off parts out of the styrofoam which looks a bit more like rocks than the 5 plates before.
Now you have to paint the hill. The two plains in brown and the rest in grey. All the grey parts are then drybrushed in white and then grass is put on the plains.
I would suggest to tear off more styrofoam than in this picture (this was my first try so it does not look that good). You can now build additional pieces like edges or inner corners.
The elevated plain is simply a 6 cm thick block of styrofoam glued on a wooden base plate.

Tabletop terrain - the castle part II: tower

(Deutsche Version) Basically a castle consists of three parts: Walls, turrets and at least one gate. Let's continue with the second part of the castle, i.e. the tower.
At first the plan: The tower has to be connected to the wall on both sides. I defined the area of the tower to 12x12 cm. This means that there has to be 4 cm of wall on each side of the tower.

The tower consists of three 6 cm thick styrofoam plates which are cut to 12x12 cm and then glued on top of each other.
As a next step, the small wall pieces on the side are built. Therefore two blocks of 12x4 cm are cut out of the 6 cm thick styrofoam. As the last step, the platform on top has to be built: A 14x14 cm big plate out of the 1 cm styrofoam has to be equipped with merlons. I used two parts which are 14 cm long and two parts which are 12 cm long to create the merlons as depicted below. Additionally you need merlons for the small wall pieces on the side which are 4 cm wide and fit to the other wall.
Afterwards, you have to paint everything, similar to the instructions in the wall post.

Tabletop terrain - the castle part I: wall

(Deutsche Version) I always liked sieges very much, therefore there had to be some kind of castle in my terrain. At first I will start with the easiest part of my castle. A straight piece of wall.

The first thing you have to consider is how to fit two wall pieces together. My plan is the following:
On the left, you can see how the merlons should look like. On a transition from one wall peice to another, two 1 cm wide high pieces meet and form a "normal" 2 cm wide high piece:
The wall is made of styrofoam, I use a 6 cm thick plate for the wall and another 1 cm thick plate for the merlons. This is now glued together and then painted. Prior to painting:
The first layer of colour - I use full-shade tinting colour which you can buy cheaply.
As a next step (and to improve the look) I  use a method called drybrush. The brush is dipped into a little colour which is then wiped off onto a piece of paper. Now you simply take the dry brush and brush above the grey colour - you can see the result here:
I think that the structure of styrofoam (which you can see even better after dry brushing) looks pretty good. Alternatively you could use extruded polystyrene (XPS), this material has a flat surface and can be cutted more easily. If you want to see any structure, you have to scar this into the XPS. This can look better than with styrofoam but is more expensive and takes more time.

Tabletop terrain - a lake

(Deutsche Version) Constructing a lake is pretty simple. At first you have to create a basic terrain plate. Afterwards you draw the lake onto it:
Now cut/tear out the lake from the styrofoam:
As a next step, paint everything brown. Afterwards paint the lake blue. To have a better optical result, you can also glue some sand to the edge of the lake:
Now add some grass:
And if you want to, you cann add some Iceland moss:

Tabletop terrain - the first plate

(Deutsche Version) Let's start with the first and easiest plate: Grass. The Plate looks like this:
The plate consists of a 10 mm thick MDF plate topped by a 10 mm styrofoam plate (this makes is possible to have structures which are up to 1 cm deeper than the basis height). On top there is a layer of grass. You can buy grass at a cheap price at ebay. To glue the grass to the plate, I use a 1:1 mixture of Ponal Holzleim and water. This allows you to spread the glue all over the plate before it is dry. As a colour, I use wall paint, this is quite cheap. Alternatively I used spray colours, unfortunately they are quite expensive (but easy to apply).

This is the basic construction of the terrain plate. One problem left to solve is to prevent the movement of the plates. If you would use the plates like they are now, they could move and there appear gaps. Therefore I had to think of a simple principle to have the plates to lock to each other. On the bottom side of each plate, there is a triangle at each corner which pokes out and a notch which locks to such a triangle. The triangle and notch look like this:
I use a wooden bar of the size 20x10 mm which is cut into pieces of the lengths 4 and 2 cm. The long piece fits with the long edge to a diagonal of the plate to have the corners to coincide. The short piece has to fit on the other side of the diagonal so that its other corner coincides with the edge of the plate.

If you fit two plates together it looks like this:
Respectively for 4 plates:
As a next step, I plan to put magnets on the bottom of the plates so the plates will stick to each other. Currently I have to wait for the magnets, as soon as they arrive, I will report the progress.

If you already have constructed 3 plates, the gluing of the bars is quite easy. You just have to place 3 plates in the shape of an L and fit another plate to them. Now you can simply glue the bars into place.

Tabletop terrain - basics

(Deutsche Version) You do not necessarily need a terrain for tabletop games. Usually a carpet or table is also suitable. Unfortunately, this does not look that good and also tactical depth is missing, given by obstacles, hills, rivers and others.

To improve the look, you can buy a cheap gaming mat which come in different looks like grass, desert and several more. Alternatively, you can use a felt mat. To improve the tactical depth, you can use terrain pieces which you just have to place on the mat (e.g. hills or a forest).

To achieve a higher level of good-looking, you could think of building your whole terrain out of one piece. For someone who has a lot of space this is suitable, otherwise you should ask yourself where to store a 1.2x1.8 m big plate which even has a sensitive and rough surface.

The optimal solution is now a modular gaming table. There exist several companies which sell them like Ziterdes, Citadel or Kallistra.
The terrain pieces of Ziterdes and Citadel are quite alike, both consist of 60x60 cm plates which can feature hill corners. Citadel is much more expensive than Ziterdes, both have little diversity (there are hill corners, for the plates of Ziterdes there are also rivers but that's all), in addition, the plates are quite big so there are only few alternatives of how to combine the plates.
Personally, I like Kallistra, the terrain consists of hexagons which can be combines like in The Settlers of Catan. There is a wide range of hexagons like rivers, hills, bridges and even modular castles. Unfortunately, Kallistra is designed for the 15 mm scale, this means that 28 mm figures would stand on very small towers and walls. This is the only reason why I didn't buy the terrain from Kallistra, whoever does not need a fortress can use the Kallistra terrain.

With all the possible systems not being suitable for me I decided to build my own terrain. The basic principle is similar to Citadel/Ziterdes: I use plates which can be combined modularly. I decided to use a edge length of 20 cm to have more possible combinations. My terrain is designed to have several different aspects like the Kallistra terrain: Hill corners and edges, lakes, high plateaus, fortresses and maybe even sea. In the next posts, I will explain how I built the terrain respectively how you can build the terrain (and spend not that much money). To have a comparison, I want to show some basic prices of the terrain.

Ziterdes: A 60x60 cm plate (painted and some grass on it) costs 28 €, if you buy a set of 6, 22 €. Calculated for a 20x20 cm plate this is about 2.4 €.

Citadel: The 6 plate set (unpainted, no grass) costst 230 €, this is about 38 € per plate respectively 4.3 € per 20x20 cm plate.

Kallistra: A set consisting of 21 plates covers 90x120 cm and costs 50 pounds, with grass 75, this is about 60/90 €. This results in a price of 2.2/3.3 € per 20x20 cm plate.

To have a comparison: For one 20x20 cm plate, I spent about 85 ct, adding grass will result in about 1 €.

To summarize everything: The price to cover an area of 180x120 cm you have to spend:
Ziterdes: 130 €
Citadel: 230 €
Kallistra: 120/180 €
home-made (my terrain): about 54 €

Friday 31 October 2014

Get to work Arduino Nano V3.0 Clone with CH340G

At Ebay you can buya clone of the Arduino Nano for less than 3 Euro. Often it can be found under names like  "Nano V3.0 ATmega328 CH340G" with the addition "for Arduino" or "Arduino compatible", for example here.

These clones don't use a FT232R as USB-Serial converter  like the "original". The use a CH340G (as you can guess), so the drivers of the Arduino IDE won't work with the clone. You have to install a special driver on your own. You can download it here from the manufacturer. There are also drivers for MAC und Linux but I will only explain how to install the driver for Windows. At first, you have to extract the ZIP archive. If you use Windows 64bit, you have to copy the file "DRVSETUP64.exe" from the folder "DRVSETUP64" to its parent folder which contains (amongst others) the file "CH341SER.INF". Depending on your system you then have to run "SETUP.EXE" (32bit) or "DRVSETUP64.exe" (64bit). Click "INSTALL" and the driver is beeing installed. The Arduino board MUST NOT be connected to your computer, when you install the driver. Connect the Arduino AFTER the successful installation. Windows will then recognize it.

Sunday 5 October 2014

C# - Program to solve a sudoku

(Deutsche Version) To solve a sudoku by hand is not that difficult. But after some time, a programmer wants to write a program which can also do this. The basic principle is pretty easy. The first empty bracket is filled (with a 1). Afterwards, the program checks whether the sudoku is still correct. If so, the next bracket is filled, if not, the previous bracket is counted up about 1. This is continued until the Sudoku is completely filled.

First, I created a window which shows a sudoku:

<Window x:Class="SudokuSolver.SudokuShowWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="SudokuShowWindow" Height="550" Width="550">
    <Grid Name="Grid1" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
            <ColumnDefinition Width="50"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
        </Grid.RowDefinitions>

    </Grid>
</Window>

And the corresponding code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace SudokuSolver
{
    /// <summary>
   /// Interaktionslogik für SudokuShowWindow.xaml
    /// </summary>
    public partial class SudokuShowWindow : Window
    {
        public SudokuShowWindow()
        {
            InitializeComponent();
        }

        public int[] numbers;
        public TextBlock[] TextBlocks;

        public void refreshValues(int[] _numbers)
        {
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (_numbers[i * 9 + j] != numbers[i * 9 + j])
                    {

                        TextBlocks[i * 9 + j].Text = _numbers[i * 9 + j].ToString();
                    }
                }
            }
        }

        public static SudokuShowWindow newSudokuShowWindow(int[] numbers)
        {
            SudokuShowWindow window = new SudokuShowWindow();
            window.numbers = new int[81];
            window.TextBlocks = new TextBlock[81];
            for (int i = 0; i < 9; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    window.numbers[i * 9 + j] = numbers[i * 9 + j];
                    TextBlock tb = new TextBlock();
                    tb.Text = numbers[i * 9 + j].ToString();
                    tb.HorizontalAlignment = HorizontalAlignment.Center;
                    tb.VerticalAlignment = VerticalAlignment.Center;
                    Grid.SetRow(tb, i);
                    Grid.SetColumn(tb, j);

                    Thickness thk = new Thickness(0, 0, 0, 0);
                    if (i == 2 || i == 5)
                    {
                        thk.Bottom = 1;
                    }
                    if (i == 3 || i == 6)
                    {
                        thk.Top = 1;
                    }
                    if (j == 2 || j == 5)
                    {
                        thk.Right = 1;
                    }
                    if (j == 3 || j == 6)
                    {
                        thk.Left = 1;
                    }
                    Border border = new Border();
                    border.BorderThickness = thk;
                    border.BorderBrush = Brushes.Black;
                    Grid.SetRow(border, i);
                    Grid.SetColumn(border, j);

                    window.Grid1.Children.Add(border);
                    window.Grid1.Children.Add(tb);

                    window.TextBlocks[i * 9 + j] = tb;
                }
            }
            window.Show();
            return window;
        }


    }
}

This is now used to show the sudoku. The solver shows the actual sudoku and opens a new window for every found solution. MainWindow is empty, it is just used to start the program.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SudokuSolver
{
    /// <summary>
   /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            Thread thread = new Thread(workLoop);
            thread.Start();
        }

        private SudokuShowWindow window;
        private int numberCounter;
        private int[] initialNumbers;
        private int[] numbers;
        List<int[]> Solutions = new List<int[]>();

        private void workLoop()
        {
            //The initial Sudoku which should be solved
            initialNumbers = new int[81]
            {
                5,3,0,   0,7,0,   0,0,0,
                6,0,0,   1,9,5,   0,0,0,
                0,9,8,   0,0,0,   0,6,0,

                8,0,0,   0,6,0,   0,0,3,
                4,0,0,   8,0,3,   0,0,1,
                7,0,0,   0,2,0,   0,0,6,

                0,6,0,   0,0,0,   2,8,0,
                0,0,0,   4,1,9,   0,0,5,
                0,0,0,   0,8,0,   0,7,9
            };
            numbers = new int[81];
            for (int i = 0; i < 81; i++)
            {
                numbers[i] = 0;
            }

            //Invoke window actions because we are not in the main thread
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                window = SudokuShowWindow.newSudokuShowWindow(initialNumbers);
            }));

            //Position of the "cursor" in the sudoku
            numberCounter = 0;

            int ctr = 0;
            bool noi = false;


            while (true)
            {
                if (isItValid())
                {
                    noi = false;

                    //A valid solution!
                    if (numberCounter > 80)
                    {
                        int[] totalNumbers = new int[81];
                        for (int i = 0; i < 81; i++)
                        {
                            totalNumbers[i] = initialNumbers[i];
                            if (totalNumbers[i] == 0)
                            {
                                totalNumbers[i] = numbers[i];
                            }
                        }

                        bool eq = false;
                        foreach (int[] solution in Solutions)
                        {
                            bool leq = true;
                            for (int i = 0; i < 81; i++)
                            {
                                if (solution[i] != totalNumbers[i])
                                {
                                    leq = false;
                                }
                            }
                            if (leq)
                            {
                                eq = true;
                            }

                        }
                        if (!eq)
                        {
                            int[] tmp = new int[81];
                            for (int i = 0; i < 81; i++)
                            {
                                tmp[i] = totalNumbers[i];
                            }
                            Solutions.Add(tmp);
                        }
                        else
                        {
                            System.Console.WriteLine("Done!");
                            break;
                        }

                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            SudokuShowWindow.newSudokuShowWindow(totalNumbers);
                        }));

                        //Check for other solutions?

                        noi = true;
                        while (true)
                        {
                            numberCounter--;
                            if (initialNumbers[numberCounter] == 0)
                            {
                                if (numbers[numberCounter] >= 9)
                                {
                                    numbers[numberCounter] = 0;
                                }
                                else
                                {
                                    numbers[numberCounter]++;
                                    break;
                                }
                            }
                        }
                    }

                    if (numberCounter > 80)
                    {
                        break;
                    }

                    if (numbers[numberCounter] == 0 && initialNumbers[numberCounter] == 0)
                    {
                        iterateOne();
                    }
                    else
                    {
                        if (!noi)
                        {
                            increaseNumberCounter();
                        }
                    }
                }
                else
                {
                    if (numberCounter > 80 || numberCounter < 0)
                    {
                        break;
                    }
                    if (numbers[numberCounter] >= 9)
                    {
                        decreaseOne();
                        Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            int[] totalNumbers = new int[81];
                            for (int i = 0; i < 81; i++)
                            {
                                totalNumbers[i] = initialNumbers[i];
                                if (totalNumbers[i] == 0)
                                {
                                    totalNumbers[i] = numbers[i];
                                }
                            }
                            window.refreshValues(totalNumbers);
                        }));

                    }
                    else
                    {
                        iterateOne();
                    }
                }
                ctr++;
                if (ctr > 1000)
                {
                    ctr = 0;
                    Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                    {
                        int[] totalNumbers = new int[81];
                        for (int i = 0; i < 81; i++)
                        {
                            totalNumbers[i] = initialNumbers[i];
                            if (totalNumbers[i] == 0)
                            {
                                totalNumbers[i] = numbers[i];
                            }
                        }
                        window.refreshValues(totalNumbers);
                    }));
                    Thread.Sleep(1);
                }
            }
            Application.Current.Dispatcher.BeginInvoke(new Action(() =>
            {
                window.Close();
            }));
        }

        void increaseNumberCounter()
        {
            numberCounter++;
            while (numberCounter <= 80 && initialNumbers[numberCounter] != 0)
            {
                numberCounter++;
            }
        }

        void iterateOne()
        {
            if (numberCounter > 80)
            {
                return;
            }
            while (initialNumbers[numberCounter] != 0)
            {
                numberCounter++;
            }
            numbers[numberCounter]++;
        }

        void decreaseOne()
        {
            if (numberCounter > 80)
            {
                numberCounter = 80;
            }
            numbers[numberCounter] = 0;
            if (numberCounter == 0)
            {
                return;
            }

            while (numberCounter >= 0)
            {
                numberCounter--;
                while (numberCounter > 0 && initialNumbers[numberCounter] != 0)
                {
                    numberCounter--;
                }
                if (numberCounter < 0)
                {
                    return;
                }
                if (numbers[numberCounter] < 9)
                {
                    numbers[numberCounter]++;
                    return;
                }
                else
                {
                    numbers[numberCounter] = 0;
                }
            }
        }

        bool isItValid()
        {
            int[] totalNumbers = new int[81];
            for (int i = 0; i < 81; i++)
            {
                totalNumbers[i] = initialNumbers[i];
                if (totalNumbers[i] == 0)
                {
                    totalNumbers[i] = numbers[i];
                }
            }
            //Check Horizontal
            List<int> testList;
            for (int i = 0; i < 9; i++)
            {
                testList = new List<int>();
                for (int j = 0; j < 9; j++)
                {
                    if (testList.Contains(totalNumbers[i * 9 + j]))
                    {
                        //Invalid
                        return false;
                    }
                    if (totalNumbers[i * 9 + j] != 0)
                    {
                        testList.Add(totalNumbers[i * 9 + j]);
                    }
                }
            }

            //Check Vertical
            for (int j = 0; j < 9; j++)
            {
                testList = new List<int>();
                for (int i = 0; i < 9; i++)
                {
                    if (testList.Contains(totalNumbers[i * 9 + j]))
                    {
                        //Invalid
                        return false;
                    }
                    if (totalNumbers[i * 9 + j] != 0)
                    {
                        testList.Add(totalNumbers[i * 9 + j]);
                    }
                }
            }
            //Check squares
            for (int ii = 0; ii < 3; ii++)
            {
                for (int jj = 0; jj < 3; jj++)
                {
                    testList = new List<int>();
                    for (int i = ii * 3; i < ii * 3 + 3; i++)
                    {
                        for (int j = jj * 3; j < jj * 3 + 3; j++)
                        {
                            if (testList.Contains(totalNumbers[i * 9 + j]))
                            {
                                //Invalid
                                return false;
                            }
                            if (totalNumbers[i * 9 + j] != 0)
                            {
                                testList.Add(totalNumbers[i * 9 + j]);
                            }
                        }
                    }
                }
            }
            //Valid
            return true;
        }
    }
}