Mad Minesweeper

Submitted by gary on Sat, 09/28/2013 - 23:13

Just for fun був написаний сапер для андроїда.
Це перша моя програма, яка має хоч трошки корисної функціональності
Ігрове поле фіксованих розмірів. Клітинки поля це кнопки (!), які динамічно розміщуються на екрані.
Так як не вистачило натхнення/вміння, то рестарт гри відбувається після зміни орієнтації телефону.
В програмі є ігрове поле. Якщо клацнути по клітинці, то вона відкриється. У випадку міни - програш. Якщо в сусідній клітинці є міна - виводиться число з кількістю мін в сусідніх клітинках. Якщо поряд немає мін, клітинка відкривається, і автоматом відкриваються всі прилеглі клітинки там де немає мін. При довгому натисненні на клітинку, вискакує контекстне меню, і можна поставити мітку: @ або ?, або очистити ці мітки. Якщо на клітинці стоїть мітка - клітинка не клікабельна. При відкритті всіх клітинок, під якими не було мін - виводиться повідомлення про перемогу (toast), і клітинки де стояли міни стають зеленого кольору. При програші клітинки з мінами підсвічуються червоним кольором. В програмі реалізоване меню, в яких викликається спливаюче вікно. При натисненні "Купить PRO-версію", в браузері відкривається сайт garik.pp.ua))
Як на мене все достатньо криво, але для початку краще криво ніж нічого :)

Лістінг:

package ua.pp.garik.android.madminesweeper;

import java.util.Random;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;

public class Playground extends Activity implements OnClickListener {
final Context context = this;
LinearLayout llPlayground;
int wrapContent = LinearLayout.LayoutParams.WRAP_CONTENT;
int match_parent = LinearLayout.LayoutParams.FILL_PARENT;
int buttonID_forcontextmenu;

int BOMB_COUNT = 10;
int MINEFIELD_WIDTH = 9;
int MINEFIELD_HEIGTH = 9;
int GAME_WIN = 0;

int[][] MINEFIELD = new int[MINEFIELD_WIDTH][MINEFIELD_HEIGTH];
int[][] MINEFIELD_OPENED = new int[MINEFIELD_WIDTH][MINEFIELD_HEIGTH];
int[][] MINEFIELD_IDs = new int[MINEFIELD_WIDTH][MINEFIELD_HEIGTH];

int[][] btnIDs = new int[MINEFIELD_WIDTH*MINEFIELD_HEIGTH+1][2];

@Override
public void onClick(View v) {
//не клікать по кнопках, де текст ? або @ (бо або це мітка, або вже всеодно підірвався)))
Button tmp_Btn = (Button)findViewById(v.getId());
if (tmp_Btn.getText().equals("?") || tmp_Btn.getText().equals("@")) {
return;
}


if (MINEFIELD[btnIDs[v.getId()][0]][btnIDs[v.getId()][1]] < 0 && GAME_WIN != 1) {
Toast.makeText(this, "ХАХАХА! Ти програв!!!", Toast.LENGTH_LONG).show();
Toast.makeText(this, "Невдаха)", Toast.LENGTH_LONG).show();
MINEFIELD_OPENED[btnIDs[v.getId()][0]][btnIDs[v.getId()][1]] = 1;
for (int j = 0; j < MINEFIELD_HEIGTH; j++) {
for (int i = 0; i < MINEFIELD_WIDTH ; i++) {
if (MINEFIELD[i][j] < 0) {
Button tmpBtn = (Button)findViewById(MINEFIELD_IDs[i][j]);
tmpBtn.setBackgroundColor(0xffff0000);
tmpBtn.setText("@");
}
}
}
} else {
open_fields(btnIDs[v.getId()][0], btnIDs[v.getId()][1]);
int opened_count = 0;
for (int j = 0; j < MINEFIELD_HEIGTH; j++) {
for (int i = 0; i < MINEFIELD_WIDTH ; i++) {
if (MINEFIELD_OPENED[i][j] == 1) {
opened_count++;
if (MINEFIELD[i][j] < 0) {
opened_count = opened_count - 1000;
}
}
}
}
if (opened_count == MINEFIELD_HEIGTH* MINEFIELD_WIDTH - BOMB_COUNT) {
Toast.makeText(this, "Ти переміг!", Toast.LENGTH_LONG).show();
GAME_WIN = 1;
for (int j = 0; j < MINEFIELD_HEIGTH; j++) {
for (int i = 0; i < MINEFIELD_WIDTH ; i++) {
if (MINEFIELD[i][j] < 0) {
Button tmpBtn = (Button)findViewById(MINEFIELD_IDs[i][j]);
tmpBtn.setBackgroundColor(0xff00ff00);
tmpBtn.setText("@");
}
}
}
}
}
//v.setBackgroundColor(0xffff0000);
}

void open_fields(int x_, int y_) {
//Log.v("Gare", "x_: " + String.valueOf(x_) + " y_: " + String.valueOf(y_));
if (x_ >= 0 && x_ < MINEFIELD_WIDTH && y_ >= 0 && y_ < MINEFIELD_HEIGTH) {
if (MINEFIELD_OPENED[x_][y_] == 0) {
Button tmpBtn = (Button)findViewById(MINEFIELD_IDs[x_][y_]);
if (MINEFIELD[x_][y_] > 0) {
tmpBtn.setText(String.valueOf(MINEFIELD[x_][y_]));
}
tmpBtn.setBackgroundColor(0xffffffff);
MINEFIELD_OPENED[x_][y_] = 1;
if (MINEFIELD[x_][y_] == 0) {
open_fields(x_-1, y_-1);
open_fields(x_, y_-1);
open_fields(x_+1, y_-1);
open_fields(x_+1, y_);
open_fields(x_+1, y_+1);
open_fields(x_, y_+1);
open_fields(x_-1, y_+1);
open_fields(x_-1, y_);
}
}
}
}

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_playground);
llPlayground = (LinearLayout) findViewById(R.id.llPlayground);
LinearLayout llTmp;
int current_id = 0;
int x, y;
LinearLayout.LayoutParams lParams;
Button btnNew;

for (int j = 0; j < MINEFIELD_HEIGTH; j++) {
for (int i = 0; i < MINEFIELD_WIDTH ; i++) {
MINEFIELD[i][j] = 0;
MINEFIELD_OPENED[i][j] = 0;
}
}
Random random = new Random();


for (int i = 0; i < BOMB_COUNT; i++) {
x = random.nextInt(MINEFIELD_WIDTH);
y = random.nextInt(MINEFIELD_HEIGTH);
while (MINEFIELD[x][y] < 0) {
x = random.nextInt(MINEFIELD_WIDTH);
y = random.nextInt(MINEFIELD_HEIGTH);
}
MINEFIELD[x][y] = -9;

if (x > 0) {
MINEFIELD[x-1][y]++;
}
if (y > 0) {
MINEFIELD[x][y-1]++;
}
if ((x > 0) && (y > 0)) {
MINEFIELD[x-1][y-1]++;
}
if (x < MINEFIELD_WIDTH - 1) {
MINEFIELD[x+1][y]++;
}
if (y < MINEFIELD_HEIGTH - 1) {
MINEFIELD[x][y+1]++;
}
if ((x < MINEFIELD_WIDTH - 1) && (y < MINEFIELD_HEIGTH - 1)) {
MINEFIELD[x+1][y+1]++;
}     
if ((x < MINEFIELD_WIDTH - 1) && (y > 0)) {
MINEFIELD[x+1][y-1]++; 
}
if ((x > 0) && (y < MINEFIELD_HEIGTH - 1)) {
MINEFIELD[x-1][y+1]++;
}           
}

for (int j = 0; j < MINEFIELD_HEIGTH; j++) {
llTmp = new LinearLayout(this);
lParams = new LinearLayout.LayoutParams(match_parent, match_parent, .11f);
llPlayground.addView(llTmp, lParams);
for (int i = 0; i < MINEFIELD_WIDTH ; i++) {
current_id++;
//MINEFIELD[i][j] = i*j; 
lParams = new LinearLayout.LayoutParams(match_parent, wrapContent, .11f);
btnNew = new Button(this);
btnNew.setId(current_id);
btnNew.setOnClickListener(this);
btnNew.setBackgroundColor(0xffdadada);
lParams.setMargins(0, 0, 1, 1);
MINEFIELD_IDs[i][j] = current_id;
btnIDs[current_id][0] = i;
btnIDs[current_id][1] = j;
if (MINEFIELD[i][j] > 0) {
//btnNew.setText(String.valueOf(MINEFIELD[i][j]));
}      
registerForContextMenu(btnNew);
llTmp.addView(btnNew, lParams);
}
}
}

@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
//Toast.makeText(this, "context : " + String.valueOf(MINEFIELD[btnIDs[v.getId()][0]][btnIDs[v.getId()][1]]), Toast.LENGTH_LONG).show();
if (MINEFIELD_OPENED[btnIDs[v.getId()][0]][btnIDs[v.getId()][1]] == 0) {
menu.add(0, 500+1, 0, "Mine");
menu.add(0, 500+2, 0, "Unknown");
menu.add(0, 500+3, 0, "Clear");
buttonID_forcontextmenu = v.getId();
super.onCreateContextMenu(menu, v, menuInfo);
}
}


@Override
public boolean onContextItemSelected(MenuItem item) {
Button curBtn = (Button)findViewById(buttonID_forcontextmenu);
switch (item.getItemId()) {
case 501:
curBtn.setText("@");
break;
case 502:
curBtn.setText("?");
break;
case 503:
curBtn.setText("");
break;
}
return super.onContextItemSelected(item);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, 1, 0, "Про програму");
menu.add(0, 2, 0, "Автор");
menu.add(0, 3, 0, "Купить PRO-версію");

return super.onCreateOptionsMenu(menu);
}

public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case 1: {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle("Про програму");
alertDialogBuilder.setMessage("Сапер. Версія 0.03\n" +
"(така ж крива як і 0.01)\n" +
"@ - міна :)\n" +
"Для рестарту змініть орієнтацію телефону о_О")
.setCancelable(true)
.setPositiveButton("Ок",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
return true;
}
case 2: {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
alertDialogBuilder.setTitle("Автор");
alertDialogBuilder
.setMessage("Ігор Дубій\n" +
"http://garik.pp.ua\n" +
"netzver@gmail.com\n")
.setCancelable(true)
.setPositiveButton("Ок",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
return true;

case 3: {
Toast.makeText(this, "Ти перший хто сюди нажав)", Toast.LENGTH_LONG).show();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://garik.pp.ua"));
startActivity(browserIntent);
return true;
}
default:
return super.onOptionsItemSelected(item);
}
}
}
Pictures: