Miny - Kontrola počtu min, vítězství, zobrazení pole

Miny - Kontrola počtu min, vítězství, zobrazení pole

Tento článek je součástí porovnání programovacích jazyků C#, Java a GameMaker při tvorbě klasických Min (MineSweeper) viz: -> Miny aneb porovnání programovacích jazyků C#, Java, GM

Nyní napíšeme fce pro kontrolu počtu min v okolí tlačítka, kontrola vítězství, zobrazení volných polí a zobrazení celého minového pole.

C# zápis

Barva dle počtu min

Pouze vrací barvu dle zadaného počtu min.

// barva podle počtu min
public static Color getColor(int count_of_mines)
{
        switch (count_of_mines)
        {
                case 0: return Color.White;
                case 1: return Color.SkyBlue;
                case 2: return Color.GreenYellow;
                default: return Color.Orange;
        }
}

Počet min v okolí

Projede okolí tlačítka a spočítá vrátí počet min v něm.

// projede okolí stisknutého tlačítka a vrátí počet min kolem něj
private int checkMinesAround(int x, int y)
{
        int count = 0;


        for (int i = -1; i <= 1; i++)
        {
                for (int j = -1; j <= 1; j++)
                {
                        // ošetření přetečení
                        if (((x + i < 0) || (x + i >= _xLength)) || ((y + j < 0) || (y + j >= _yLength)) || ((x + i == x) && (y + j == y)))
                                continue;

                        if (_minesArray[x + i, y + j])
                                count++;
                }
        }
        return count;
}

Zobrazení volných polí

Rekurzivně projede okolí stisknutého tlačítka a pokud je hodnota v min v jeho okolí rovna nule, zkontroluje okolí jeho okolních tlačítek a postupuje stejným způsobem.

// projede všechny tlačítka od stisknutého, které mají v okolí nulový počet min a zobrazí je
public void showFree(int x, int y)
{
        for (int i = -1; i <= 1; i++)
        {
                for (int j = -1; j <= 1; j++)
                {
                        // ošetření přetečení
                        if (((x + i < 0) || (x + i >= _xLength)) || ((y + j < 0) || (y + j >= _yLength)))
                                continue;

                        if ((this.checkMinesAround(x + i, y + j) == 0) && (_buttons[x + i, y + j].Enabled == true) && (_buttons[x + i, y + j].Text != "?"))
                        {
                                _buttons[x, y].Text = "0";
                                _buttons[x, y].BackColor = Mines.getColor(0);
                                _buttons[x, y].Enabled = false;
                                this.showFree(x + i, y + j);
                        }
                }
        }
}

Zobrazení celého pole

Jednoduše projedeme celé pole. Povšimněte si odstranění události myši.

// zobrazí celé minové pole (při prohře či výhře)
public void showField()
{
        for (int y = 0; y < _yLength; y++)
        {
                for (int x = 0; x < _xLength; x++)
                {
                        if (_minesArray[x, y])
                        {
                                _buttons[x, y].Text = "M";
                                _buttons[x, y].BackColor = Color.Red;
                        }
                        else
                        {
                                _buttons[x, y].Text = checkMinesAround(x, y).ToString();
                                _buttons[x, y].BackColor = Mines.getColor(checkMinesAround(x, y));
                        }
                        _buttons[x, y].Enabled = false;
                        _buttons[x, y].MouseDown -= new MouseEventHandler(Mines_MouseDown);
                }
        }
}

Vítězství

Zkontroluje počet aktivních tlačítek a porovná tento počet z celkovým počtem min. Pokud se shoduje - zbývají pouze miny.

// pokud je počet aktivních tlačítek roven počtu min (zbývají pouze miny) -> vítězství
public bool checkVictory()
{
        int enabled_buttons = 0;
        foreach (Button but in _buttons)
        {
                if (but.Enabled == true)
                        enabled_buttons++;
        }

        if (enabled_buttons == _countOfMines)
                return true;
        else
                return false;
}

Java zápis

Barva dle počtu min

Pouze vrací barvu dle zadaného počtu min.

// vrací barvu v závislosti na počtu min
public Color getColor(int count_of_mines)
{
        switch (count_of_mines)
        {
                case 0: return Color.white;
                case 1: return Color.blue;
                case 2: return Color.green;
                default: return Color.orange;// větší než 2
        }
}

Nastavení tlačítka

Nastaví tlačítko dle zadaných parametrů.

public void setButton(String text, Color color, int x, int y)
{
        buttons[x][y].setText(text);
        buttons[x][y].setBackground(color);
        buttons[x][y].setEnabled(false);
}

Počet min v okolí

Projede okolí tlačítka a spočítá vrátí počet min v něm.

// vrátí počet min kolem daného tlačítka
public int checkMinesAround(int x, int y)
{
        int count = 0;
        for (int i = -1; i <= 1; i++)
        {
                for (int j = -1; j <= 1; j++)
                {
                        // ošetření přetečení
                        if (((x+i < 0) || (x+i >= x_length)) || ((y+j < 0) || (y+j >= y_length)) || ((x+i == x) && (y+j == y)))
                                continue;

                        if (mines_array[x+i][y+j])
                                count++;
                }
        }
        return count;
}

Zobrazení volných polí

Rekurzivně projede okolí stisknutého tlačítka a pokud je hodnota v min v jeho okolí rovna nule, zkontroluje okolí jeho okolních tlačítek a postupuje stejným způsobem.

// pokud je počet min daného tlačítka roven 0 projede jeho okolí a odkryje pole s ním spajaté, které také mají počet min v jejich okolí roven 0
public void showFree(int x, int y)
{
        for (int i = -1; i <= 1; i++)
        {
                for (int j = -1; j <= 1; j++)
                {
                        // ošetření přetečení
                        if (((x+i < 0) || (x+i >= x_length)) || ((y+j < 0) || (y+j >= y_length)) || ((x+i == x) && (y+j == y)))
                                continue;

                        if ((this.checkMinesAround(x+i, y+j) == 0) && (buttons[x+i][y+j].isEnabled() == true) && (buttons[x+i][y+j].getText() != "?"))
                        {
                                this.setButton("0", this.getColor(0), x+i, y+j);
                                this.showFree(x+i, y+j);
                        }
                }
        }
}

Zobrazení celého pole

Jednoduše projedeme celé pole. Povšimněte si odstranění události myši.

// zbrazí pole min (prohra/výhra)
public void showField()
{
        for (int y = 0; y < y_length; y++)
        {
                for (int x = 0; x < x_length; x++)
                {
                        if (mines_array[x][y])
                                this.setButton("M", Color.red, x, y);
                        else
                                this.setButton(String.valueOf(this.checkMinesAround(x, y)), this.getColor(this.checkMinesAround(x, y)), x, y);
                }
        }
}

Vítězství

Zkontroluje počet aktivních tlačítek a porovná tento počet z celkovým počtem min. Pokud se shoduje - zbývají pouze miny.

// po stisku tlačítka se zkontroluje kolik zbývá aktivních polí, pokud je číslo rovno počtu min vrátí true
public boolean checkVictory()
{
        int enabled_buttons = 0;

        for (int y = 0; y < y_length; y++)
        {
                for (int x = 0; x < x_length; x++)
                {
                        if (buttons[x][y].isEnabled())
                                enabled_buttons++;
                }
        }

        if (enabled_buttons == count_of_mines)
                return true;
        else
                return false;
}

GameMaker - zápis

Barva a zobrazení počtu min

Tyto náležitosti se provádějí v draw eventu.

draw_sprite(sprite_index, -1, x, y);

draw_set_font(font0);

switch (mines_around)
{
    case 0: draw_set_color(c_white); break;
    case 1: draw_set_color(c_blue); break;
    case 2: draw_set_color(c_green); break;
    default: draw_set_color(c_red); break;
}

// vykreslí počet min okolo stisknutého tlačítka
if (sprite_index == spr_clicked)
    draw_text(x - 3, y - 8, mines_around);

Počet min v okolí

Na tohle si napíšeme script, který pak budeme volat pomocí script_execute(ná­zev, parametry...)

Kontrola je mina

Přistoupí k objektu, dle souřadnic a zjistí z proměnné mine, která se nastavuje při vytváření polí, zda je na zadaném mina či ne.

//is mine

if (instance_exists(instance_position(argument0, argument1, obj_button)))
{
    if (instance_position(argument0, argument1, obj_button).mine == true)
    {
        return true;
    }
}

return false;

Počet min v okolí

//check_mines_around

count = 0;

if (script_execute(is_mine, argument0 - sprite_width, argument1)) { count += 1 }
if (script_execute(is_mine, argument0 + sprite_width, argument1)) { count += 1 }

if (script_execute(is_mine, argument0 - sprite_width, argument1 - sprite_height)) { count += 1 }
if (script_execute(is_mine, argument0, argument1 - sprite_height)) { count += 1 }
if (script_execute(is_mine, argument0 + sprite_width, argument1 - sprite_height)) { count += 1 }

if (script_execute(is_mine, argument0 - sprite_width, argument1 + sprite_height)) { count += 1 }
if (script_execute(is_mine, argument0, argument1 + sprite_height)) { count += 1 }
if (script_execute(is_mine, argument0 + sprite_width, argument1 + sprite_height)) { count += 1 }

return count;

V události Room start v obj_button tento script zavoláme a přiřadíme tlačítkům kolik mají min v okolí, pak je pouze zobrazíme v události draw.

// po vytvoření všech tlačítek se nastaví počet min okolo
mines_around = script_execute(check_mines_around, x, y);

Zobrazení volných polí

Tímto způsobem se projede okolí tlačítka - vpravo, vlevo, nahoře a dole. Rekurze pak zkontroluje zbytek. V kódu je jen kontrola pravého souseda.

// show_free
if (script_execute(check_mines_around, argument0 + sprite_get_width(spr_button), argument1) == 0)
{
    with (instance_position(argument0 + sprite_get_width(spr_button), argument1, obj_button))
    {
        if (sprite_index != spr_clicked)
        {
            sprite_index = spr_clicked;
            script_execute(show_free, argument0 + sprite_get_width(spr_button), argument1);
        }
    }
}

Zobrazení celého pole

Jednoduše projedeme celé pole. Povšimněte si fce screen_redraw, pokud ji nepoužijete, pak se při show_message nepřekreslí obrazovka a vy neuvidíte ono pole.

// show_all
for (i = 1; i < instance_count; i += 1)
{
    with (instance_id[i])
    {
        if (mine == true)
            sprite_index = spr_mine;
        else
            sprite_index = spr_clicked;
    }
}

// překreslí se
screen_redraw();

Vítězství

Zkontroluje počet instancí, které nemají sprite roven spr_clicked -> tedy aktivní a porovná tento počet z celkovým počtem min. Pokud se shoduje - zbývají pouze miny.

// check_victory
clicked = 0;

for (i = 1; i < instance_count - 1; i += 1)
{
    if (instance_id[i].sprite_index != spr_clicked) { clicked += 1 }
}

if (clicked == obj_controler.mines_count)
    return true;

return false;

Pokračování > Zajímavosti a poznámky


 

  Aktivity (1)

Článek pro vás napsal David Jančík [sczdavos]
Avatar
Autor je vášnivý programátor v .NET C# a PHP. Nezná slovo "nelze", nebojí se zkoušet nepoznané a pronikat do nových technologií.

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 



 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!