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