#include using namespace Upp; class Bombs : public TopWindow { public: virtual void Paint(Draw& w); virtual void LeftDown(Point p, dword flags); virtual void RightDown(Point p, dword flags); private: Size level; int cx, cy; int normal_cells, bombs; Buffer field; MenuBar menu; StatusBar status; byte& Field(int x, int y) { return field[x + y * cx]; } enum { HIDDEN = 16, BOMB = 32, MARK = 64, EXPLODED = 128, UNIT = 30, }; void About(); void File(Bar& menu); void Game(Bar& menu); void Menu(Bar& menu); void ShowStatus(); void Level(Size sz); void Uncover(int x, int y); void Generate(); void UncoverAll(); public: typedef Bombs CLASSNAME; Bombs(); }; void Bombs::Generate() { cx = level.cx; cy = level.cy; field.Alloc(cx * cy); for(int i = cx * cy - 1; i >= 0; i--) field[i] = (rand() & 15) < 3 ? HIDDEN|BOMB : HIDDEN; normal_cells = 0; for(int x = 0; x < cx; x++) for(int y = 0; y < cy; y++) if((Field(x, y) & BOMB) == 0) { normal_cells++; for(int xx = -1; xx <= 1; xx++) for(int yy = -1; yy <= 1; yy++) if((xx || yy) && x + xx >= 0 && x + xx < cx && y + yy >= 0 && y + yy < cy && (Field(x + xx, y + yy) & BOMB)) Field(x, y)++; } bombs = cx * cy - normal_cells; Rect r = GetRect(); r.SetSize(AddFrameSize(UNIT * cx, UNIT * cy)); SetRect(r); ShowStatus(); Refresh(); } void Bombs::UncoverAll() { for(int i = cx * cy - 1; i >= 0; i--) field[i] &= ~HIDDEN; Refresh(); } void Bombs::Paint(Draw& w) { for(int x = 0; x < cx; x++) for(int y = 0; y < cy; y++) { byte f = Field(x, y); w.DrawRect(x * UNIT, y * UNIT + UNIT - 1, UNIT, 1, SBlack); w.DrawRect(x * UNIT + UNIT - 1, y * UNIT, 1, UNIT, SBlack); w.DrawRect(x * UNIT, y * UNIT, UNIT - 1, UNIT - 1, (f & (HIDDEN|MARK)) ? SLtGray : f & BOMB ? SLtRed : SWhite); String txt; Color ink = SBlack; Color cross = Null; if(f & MARK) { txt = "M"; ink = SLtRed; if((f & (HIDDEN|BOMB)) == BOMB) { ink = SLtBlue; cross = SLtRed; } } else if(!(f & HIDDEN)) if(f & BOMB) txt = "B"; else { f = f & 15; txt = String(f + '0', 1); ink = f == 0 ? SLtGreen : f == 1 ? SLtBlue : SBlack; } Size tsz = GetTextSize(txt, Roman(2 * UNIT / 3)); w.DrawText(x * UNIT + (UNIT - tsz.cx) / 2, y * UNIT + (UNIT - tsz.cy) / 2, txt, Roman(2 * UNIT / 3), ink); if(f & EXPLODED) cross = SLtBlue; w.DrawLine(x * UNIT, y * UNIT, x * UNIT + UNIT - 1, y * UNIT + UNIT - 1, 1, cross); w.DrawLine(x * UNIT, y * UNIT + UNIT - 1, x * UNIT + UNIT - 1, y * UNIT, 1, cross); } } void Bombs::Uncover(int x, int y) { if(x >= 0 && x < cx && y >= 0 && y < cy) { byte& f = Field(x, y); if((f & (HIDDEN|MARK)) == HIDDEN) { if(f & BOMB) { f |= EXPLODED; normal_cells = 0; UncoverAll(); return; } if((f &= ~HIDDEN) == 0) for(int xx = -1; xx <= 1; xx++) for(int yy = -1; yy <= 1; yy++) if(xx || yy) Uncover(x + xx, y + yy); normal_cells--; if(normal_cells == 0) { UncoverAll(); PromptOK("[*@4A6 Nice!]&You have found all the bombs!"); } } } } void Bombs::LeftDown(Point p, dword flags) { if(!normal_cells) return; p /= UNIT; Uncover(p.x, p.y); Refresh(); ShowStatus(); } void Bombs::RightDown(Point p, dword flags) { if(!normal_cells) return; p /= UNIT; if(Field(p.x, p.y) & HIDDEN) { Field(p.x, p.y) ^= MARK; Refresh(); } } void Bombs::ShowStatus() { status = Format("%d bombs, %d cells remaining", bombs, normal_cells); } void Bombs::Level(Size sz) { level = sz; } void Bombs::About() { PromptOK("[*A9/ uBombs]&[A5 Ultimate`+`+ example]"); } void Bombs::File(Bar& menu) { menu.Add("Exit", Breaker(IDOK)); menu.Separator(); menu.Add("About..", THISBACK(About)); } void Bombs::Game(Bar& menu) { menu.Add("Restart", THISBACK(Generate)); menu.Separator(); menu.Add("Easy", THISBACK1(Level, Size(10, 10))) .Check(level.cx == 10); menu.Add("Medium", THISBACK1(Level, Size(15, 15))) .Check(level.cx == 15); menu.Add("Difficult", THISBACK1(Level, Size(25, 20))) .Check(level.cx == 25); } void Bombs::Menu(Bar& menu) { menu.Add("File", THISBACK(File)); menu.Add("Game", THISBACK(Game)); } #define IMAGECLASS BombsImg #define IMAGEFILE #include Bombs::Bombs() { level = Size(10, 10); AddFrame(menu); menu.Set(THISBACK(Menu)); AddFrame(status); AddFrame(InsetFrame()); Title("uBombs"); Icon(BombsImg::Small()); Generate(); } GUI_APP_MAIN { Bombs().Run(); }