Samples Gallery & Reference > Games
Hexagon Minesweeper by bplus
(1/1)
Qwerkey:
Hexagon Minesweeper
Author: @bplus
Source: qb64.org Forum
URL: https://www.qb64.org/forum/index.php?topic=1558.msg128396#msg128396
Version: v3.1W Crater 2021-01-19 update
Tags: [Graphics], [2D], [Audio]
Description:
I have a new and improved Hexagonal Minesweeper. I was challenged to add particle explosion at SmallBASIC board at Syntax Bomb forum. Couldn't help myself, I tweaked Crater Maker some more to scale to board size and closer fit to Bomb sound. PS the exe is for Windows 64
Controls:
Right & Left Mouse Buttons
Source Code:
--- Code: QB64: ---OPTION _EXPLICIT 'Bplus started 2019-08-08 from quick version of Hex Minesweeper and Minesweeper Custom Field' 2021-01-19 update move all ogg files into separate sub folder for Windows users'============================================================================================================'' Hex Minesweeper v3.1W: Field Customization, Sound Effects and mod Crater Maker!'' bplus mod 2021-01-19'============================================================================================================= ' Attention: this program creates a file: "Hexagon Minefield Custom Specs.txt"' that you edit with your text editor, if you select that option in the opening screen menu. ' 2019-08-13 Hex Minesweeper Custom and Sound.bas add ogg file sound effects' Public domain .ogg files source' https://bigsoundbank.com/detail-0029-computer-mouse.html' and bomb #6: https://www.mediacollege.com/downloads/sound-effects/explosion/ '2020-02-09 adding Crater Maker effect I devloped for SmallBASIC 2020-02-08 should work even better with QB64.' It does indeed!!!!''2020-02-10 refined Crater Maker to scale to board size and Bombsound time of blast' DEFINT A-ZCONST P2 = 6.28318531'to make things easy set cellR as const at 25CONST cellR = 25 ' which makes the following constantDIM SHARED xspacing!, yspacing!xspacing! = 2 * cellR * COS(_D2R(30)): yspacing! = cellR * (1 + SIN(_D2R(30)))DIM SHARED xmax, ymax, Xarrd, Yarrd, mines 'set all this in customField sub 'sound eventsDIM SHARED ToggleSnd AS LONG, BombSnd AS LONG, ApplauseSnd AS LONG, openSnd AS LONGDIM SHARED SwooshSnd AS LONG _TITLE "Hexagon Minesweeper v3.1W: Customize, Sound Effects and now Crater Maker"DIM ogg$ogg$ = "Ogg Files\" ToggleSnd = _SNDOPEN(ogg$ + "Toggle.ogg")openSnd = _SNDOPEN(ogg$ + "Ticking.ogg")BombSnd = _SNDOPEN(ogg$ + "bomb.ogg")ApplauseSnd = _SNDOPEN(ogg$ + "Applause sm.ogg")SwooshSnd = _SNDOPEN(ogg$ + "Flyby.ogg")'_SNDPLAY SwooshSnd: IF SwooshSnd = 0 THEN PRINT " not loaded." ELSE PRINT "OK loaded.": END'rnd reveal soundsDIM SHARED rndSnd(28) AS LONGrndSnd(0) = _SNDOPEN(ogg$ + "357 shot.ogg")rndSnd(1) = _SNDOPEN(ogg$ + "alarm.ogg")rndSnd(2) = _SNDOPEN(ogg$ + "Apple bite.ogg")rndSnd(3) = _SNDOPEN(ogg$ + "Barkings.ogg")rndSnd(4) = _SNDOPEN(ogg$ + "Bike.ogg")rndSnd(5) = _SNDOPEN(ogg$ + "brake.ogg")rndSnd(6) = _SNDOPEN(ogg$ + "bumble bee.ogg")rndSnd(7) = _SNDOPEN(ogg$ + "creaking.ogg")rndSnd(8) = _SNDOPEN(ogg$ + "crows.ogg")rndSnd(9) = _SNDOPEN(ogg$ + "Ding.ogg")rndSnd(10) = _SNDOPEN(ogg$ + "dinggg.ogg")rndSnd(11) = _SNDOPEN(ogg$ + "Donkey.ogg")rndSnd(12) = _SNDOPEN(ogg$ + "elec phone.ogg")rndSnd(13) = _SNDOPEN(ogg$ + "Fill mug.ogg")rndSnd(14) = _SNDOPEN(ogg$ + "goat.ogg")rndSnd(15) = _SNDOPEN(ogg$ + "hen.ogg")rndSnd(16) = _SNDOPEN(ogg$ + "Horse.ogg")rndSnd(17) = _SNDOPEN(ogg$ + "Kids.ogg")rndSnd(18) = _SNDOPEN(ogg$ + "M scream.ogg")rndSnd(19) = _SNDOPEN(ogg$ + "Male Hilarious.ogg")rndSnd(20) = _SNDOPEN(ogg$ + "Marimba.ogg")rndSnd(21) = _SNDOPEN(ogg$ + "neighing.ogg")rndSnd(22) = _SNDOPEN(ogg$ + "polaris ring.ogg")rndSnd(23) = _SNDOPEN(ogg$ + "pull top can.ogg")rndSnd(24) = _SNDOPEN(ogg$ + "Punch line drum.ogg")rndSnd(25) = _SNDOPEN(ogg$ + "Ring 2.ogg")rndSnd(26) = _SNDOPEN(ogg$ + "Rooster.ogg")rndSnd(27) = _SNDOPEN(ogg$ + "Unlock door.ogg")rndSnd(28) = _SNDOPEN(ogg$ + "whook.ogg")'DIM i 'test load and sounds'FOR i = 10 TO 28' _SNDPLAY (rndSnd(i))' PRINT i;' IF rndSnd(i) = 0 THEN PRINT i; " not loaded." ELSE PRINT' _DELAY 2'NEXT'END customFieldSCREEN _NEWIMAGE(xmax, ymax, 32)_SCREENMOVE (1280 - xmax) / 2 + 60, (760 - ymax) / 2RANDOMIZE TIMERTYPE boardType x AS SINGLE 'pixel location y AS SINGLE 'pixel location dx AS SINGLE 'for Crater making dy AS SINGLE ' ditto id AS INTEGER '0 to 6 neighbor mines reveal AS INTEGER ' 1 for marked, 0 hidden, -1 for revealed mine AS INTEGER '0 or -1END TYPEREDIM SHARED b(0 TO Xarrd + 1, 0 TO Yarrd + 1) AS boardType 'oversize the board to make it easy to count minesDIM SHARED restartDIM gameOver, cc, cr, mbN, s$, sz!_TITLE _TRIM$(STR$(Yarrd * Xarrd - mines)) + " Cells to Free Instructions: Left click Reveals, Right Marks Red"restart = 1WHILE 1 gameOver = 0 WHILE gameOver = 0 IF restart THEN initialize mbN = 0 getCell cc, cr, mbN IF mbN = 1 AND b(cc, cr).reveal = 0 THEN IF b(cc, cr).mine THEN 'ka boom makeCrater cc, cr 's$ = "KA - BOOOMMMM!" 'comment out since post code 'sz! = 1.2 * xmax / LEN(s$) 'cText xmax / 2, ymax / 2, sz!, &HFF000000, s$ 'cText xmax / 2 - 4, ymax / 2 - 4, sz!, &HFFFF0000, s$ 'cText xmax / 2 - 8, ymax / 2 - 8, sz!, &HFFFFFF00, s$ gameOver = -1 _DELAY 4 ELSE b(cc, cr).reveal = -1: showCell cc, cr IF b(cc, cr).id = 0 THEN sweepZeros cc, cr ELSE _SNDPLAY rndSnd(INT(RND * 29)) END IF END IF ELSEIF mbN = 2 THEN _SNDPLAY ToggleSnd IF b(cc, cr).reveal = 1 THEN b(cc, cr).reveal = 0: showCell cc, cr ELSE IF b(cc, cr).reveal = 0 THEN b(cc, cr).reveal = 1: showCell cc, cr END IF END IF IF TFwin THEN s$ = "Good Job!" sz! = 1.2 * xmax / LEN(s$) cText xmax / 2, ymax / 2, sz!, &HFF000000, s$ cText xmax / 2 - 1, ymax / 2 - 2, sz!, &HFF000055, s$ _DELAY 4 _SNDPLAY ApplauseSnd _DELAY 7 gameOver = -1 END IF _LIMIT 60 WEND restart = 1WEND NoOff:DATA 1,0,0,-1,0,1,-1,-1,-1,0,-1,1 xOff:DATA -1,0,0,-1,0,1,1,-1,1,0,1,1 SUB makeCrater (col, row) TYPE Particle x AS SINGLE y AS SINGLE dx AS SINGLE dy AS SINGLE sz AS SINGLE c AS _UNSIGNED LONG type AS INTEGER END TYPE DIM nP, r, c, a!, i, ra!, red!, j, stopper nP = 25 * Xarrd * Yarrd DIM p(nP) AS Particle _SNDPLAY BombSnd _DELAY .500 'need a fairly long delay before actually hear sound LINE (0, 0)-(xmax, ymax), &HFFFFFFFF, BF _DELAY .01 CLS FOR r = 1 TO Yarrd 'show all mines FOR c = 1 TO Xarrd IF b(c, r).mine THEN b(c, r).reveal = -1 showCell c, r a! = _ATAN2(b(c, r).y - b(col, row).y, b(c, r).x - b(col, row).x) b(c, r).dx = .005 * Xarrd * Yarrd * COS(a!) b(c, r).dy = .005 * Xarrd * Yarrd * SIN(a!) NEXT NEXT FOR i = 0 TO nP p(i).x = b(col, row).x + RND * 2 * cellR - cellR p(i).y = b(col, row).y + RND * 2 * cellR - cellR p(i).sz = RND * 6.5 + .1 ra! = RND * P2 p(i).dx = .09 * Xarrd * Yarrd / p(i).sz * COS(ra!) p(i).dy = .09 * Xarrd * Yarrd / p(i).sz * SIN(ra!) red! = RND * 100 p(i).c = _RGB32(red!, .5 * red! + .1 * red! * RND - .05 * red!, .25 * red! + .05 * red! * RND - .025 * red!) p(i).type = INT(RND * 2) NEXT stopper = .5 * nP 'orig .3 FOR i = 1 TO 170 'make a Crater!!! maybe runs to long try 70 from original post 270 CLS FOR r = 1 TO Yarrd 'redraw board with cells moved FOR c = 1 TO Xarrd IF r = row AND c = col THEN ELSE IF i > 70 THEN b(c, r).dx = .9 * b(c, r).dx b(c, r).dy = .9 * b(c, r).dy END IF b(c, r).x = b(c, r).x + b(c, r).dx b(c, r).y = b(c, r).y + b(c, r).dy showCell c, r END IF NEXT NEXT FOR j = 1 TO stopper IF p(j).type THEN fcirc p(j).x, p(j).y, p(j).sz, p(j).c ELSE LINE (p(j).x - .5 * p(i).sz, p(j).y - .5 * p(j).sz)-STEP(p(j).sz, p(j).sz), p(j).c, BF END IF p(j).x = p(j).x + p(j).dx p(j).y = p(j).y + p(j).dy p(j).dx = .97 * p(j).dx ' original post .992 p(j).dy = .97 * p(j).dy NEXT _DISPLAY _LIMIT 35 IF i < 70 THEN stopper = stopper + 80 ' ELSE stopper = stopper + 1 IF stopper > nP THEN stopper = nP NEXT _AUTODISPLAYEND SUB 'set all these 'DIM SHARED xmax, ymax, XarrD, YarrD, minesSUB customField DIM fName$, fe, fLine$, p, inCnt, beenHere, allow$, choice$ fName$ = "Hexagon Minefield Custom Specs.txt" IF _FILEEXISTS(fName$) THEN fe = -1 ELSE fe = 0 allow$ = "12" + CHR$(27) PRINT PRINT " Hexagom Minesweeper options:" PRINT PRINT " 1. Use mine field settings: 10 X 10 cells and 10 mines." PRINT " 2. Customize your own field settings." IF fe THEN PRINT " 3. Use the last customized mine field settings.": allow$ = allow$ + "3" PRINT PRINT " or press esc to quit." choice$ = getChar$(allow$) SELECT CASE choice$ CASE "1": xmax = 800: ymax = 600: Xarrd = 10: Yarrd = 10: mines = 10 CASE "2": GOSUB editCustom CASE "3": GOSUB loadCustom CASE ELSE: SYSTEM END SELECT xmax = (Xarrd + 2.5) * xspacing!: ymax = (Yarrd + 2) * yspacing! EXIT SUB editCustom: IF fe = 0 THEN OPEN fName$ FOR OUTPUT AS #1 PRINT #1, " " PRINT #1, " Custom Field Specs For Your Hexagon Minesweeper Game" PRINT #1, " " PRINT #1, " We will be sizing the screen according to a constant cell radius of 25" PRINT #1, " and then numbers filled in here." PRINT #1, " " PRINT #1, " Please fill out the right side of all Equal signs." PRINT #1, " " PRINT #1, " X dimensions across the screen:" PRINT #1, " Your Max Screen Width (pixels) = " PRINT #1, " Number of Horizontal Cells Across = " PRINT #1, " " PRINT #1, " Y dimensions going down:" PRINT #1, " Your Max Screen Height (pixels) = " PRINT #1, " Number of Cells Down = " PRINT #1, " " PRINT #1, "The percent of mines (8 easy - 15 hard) = " PRINT #1, " " PRINT #1, " To finish, Save the file and then close the editor." CLOSE #1 END IF ' I picked up this shortcut from Ken, normally I would call a text editor that I don't know if you have! SHELL fName$ GOSUB loadCustom RETURN loadCustom: beenHere = beenHere + 1 'we'll give it 5 tries IF beenHere > 5 THEN PRINT "OK we tried 5 times, going with default settings..." xmax = 800: ymax = 600: Xarrd = 10: Yarrd = 10: mines = 10 RETURN END IF inCnt = 0 OPEN fName$ FOR INPUT AS #1 WHILE EOF(1) = 0 ' look to get 5 values from 5 = signs LINE INPUT #1, fLine$ p = INSTR(fLine$, "=") IF p > 0 THEN inCnt = inCnt + 1 SELECT CASE inCnt CASE 1: xmax = VAL(rightOf$(fLine$, "=")) CASE 2: Xarrd = VAL(rightOf$(fLine$, "=")) CASE 3: ymax = VAL(rightOf$(fLine$, "=")) CASE 4: Yarrd = VAL(rightOf$(fLine$, "=")) CASE 5: mines = VAL(rightOf$(fLine$, "=")) * Xarrd * Yarrd / 100 END SELECT IF inCnt = 5 THEN EXIT WHILE END IF WEND CLOSE #1 IF inCnt = 5 THEN 'alternate exit from gosub IF xmax >= (Xarrd + 2.5) * xspacing! THEN IF ymax < (Yarrd + 2) * yspacing! THEN 'all good PRINT "Opps, Screen height is not big enough for Y cells down." ELSE RETURN END IF ELSE PRINT "Opps, Screen width is not big enough for X cells across." END IF ELSE PRINT "We did not get everything filled out by = signs." END IF PRINT: PRINT "Press any to continue.. " SLEEP SHELL fName$ GOTO loadCustomEND SUB SUB initialize () DIM minesPlaced, rx, ry, x, y, nMines, xoffset! CLS _SNDPLAY openSnd restart = 0 REDIM b(0 TO Xarrd + 1, 0 TO Yarrd + 1) AS boardType minesPlaced = 0 WHILE minesPlaced < mines rx = INT(RND * Xarrd) + 1: ry = INT(RND * Yarrd) + 1 IF b(rx, ry).mine = 0 THEN b(rx, ry).mine = -1: minesPlaced = minesPlaced + 1 END IF WEND 'count mines amoung the neighbors FOR y = 1 TO Yarrd IF y MOD 2 = 0 THEN xoffset! = .5 * xspacing! ELSE xoffset! = 0 FOR x = 1 TO Xarrd IF b(x, y).mine <> -1 THEN 'not already a mine '2 sets of neighbors depending if x offset or not IF xoffset! > .1 THEN nMines = b(x - 1, y).mine + b(x, y - 1).mine + b(x, y + 1).mine nMines = nMines + b(x + 1, y - 1).mine + b(x + 1, y).mine + b(x + 1, y + 1).mine ELSE nMines = b(x + 1, y).mine + b(x, y - 1).mine + b(x, y + 1).mine nMines = nMines + b(x - 1, y - 1).mine + b(x - 1, y).mine + b(x - 1, y + 1).mine END IF b(x, y).id = -nMines ELSE b(x, y).id = 0 END IF b(x, y).x = x * xspacing! + xoffset! + .5 * xspacing! b(x, y).y = y * yspacing! + .5 * yspacing! b(x, y).reveal = 0 showCell x, y NEXT NEXTEND SUB SUB showCell (c, r) DIM da, x!, y!, lastx!, lasty!, clr AS _UNSIGNED LONG SELECT CASE b(c, r).reveal CASE -1: IF b(c, r).mine THEN clr = &HFF883300 ELSE clr = &HFFFFFFFF 'revealed white with number of mine neighbors CASE 0: clr = &HFF008800 'hidden green CASE 1: clr = &HFFFF0000 'marked red END SELECT lastx! = b(c, r).x + cellR * COS(_D2R(-30)) lasty! = b(c, r).y + cellR * SIN(_D2R(-30)) FOR da = 30 TO 330 STEP 60 x! = b(c, r).x + cellR * COS(_D2R(da)) y! = b(c, r).y + cellR * SIN(_D2R(da)) LINE (lastx!, lasty!)-(x!, y!), &HFFFF00FF lastx! = x!: lasty! = y! NEXT PAINT (b(c, r).x, b(c, r).y), clr, &HFFFF00FF IF b(c, r).reveal = -1 THEN 'cText b(c, r).x, b(c, r).y, 15, &HFF000000, _TRIM$(STR$(c)) + "," + _TRIM$(STR$(r)) IF b(c, r).id > 0 THEN cText b(c, r).x, b(c, r).y, 35, &HFF000000, _TRIM$(STR$(b(c, r).id)) IF b(c, r).mine = -1 THEN cText b(c, r).x, b(c, r).y, 35, &HFFFFFFFF, "*" END IFEND SUB FUNCTION TFwin DIM c, x, y FOR y = 1 TO Yarrd FOR x = 1 TO Xarrd IF b(x, y).reveal = -1 AND b(x, y).mine = 0 THEN c = c + 1 NEXT NEXT IF c = Xarrd * Yarrd - mines THEN TFwin = -1END FUNCTION SUB getCell (returnCol AS INTEGER, returnRow AS INTEGER, mbNum AS INTEGER) DIM m, mx, my, mb1, mb2, r, c WHILE _MOUSEINPUT: WEND mb1 = _MOUSEBUTTON(1): mb2 = _MOUSEBUTTON(2) IF mb1 THEN mbNum = 1 IF mb2 THEN mbNum = 2 IF mb1 OR mb2 THEN ' get last place mouse button was down WHILE mb1 OR mb2 ' wait for mouse button release as a "click" m = _MOUSEINPUT: mb1 = _MOUSEBUTTON(1): mb2 = _MOUSEBUTTON(2) mx = _MOUSEX: my = _MOUSEY WEND FOR r = 1 TO Yarrd FOR c = 1 TO Xarrd IF ((mx - b(c, r).x) ^ 2 + (my - b(c, r).y) ^ 2) ^ .5 < .5 * xspacing! THEN returnCol = c: returnRow = r: EXIT SUB END IF NEXT NEXT mbNum = 0 'still here then clicked wrong END IFEND SUB SUB sweepZeros (col, row) ' recursive sweep DIM c, r, cMin, cMax, rMin, rMax, x, y, id _SNDPLAY SwooshSnd c = col: r = row 'get copies for recursive sub IF c > 2 THEN cMin = c - 1 ELSE cMin = 1 IF c < Xarrd - 1 THEN cMax = c + 1 ELSE cMax = Xarrd IF r > 2 THEN rMin = r - 1 ELSE rMin = 1 IF r < Yarrd - 1 THEN rMax = r + 1 ELSE rMax = Yarrd FOR y = rMin TO rMax FOR x = cMin TO cMax IF b(x, y).reveal = 0 THEN id = b(x, y).id IF b(x, y).mine = 0 AND id = 0 THEN b(x, y).reveal = -1 'mark played showCell x, y sweepZeros x, y ELSE IF b(x, y).mine = 0 AND id >= 1 AND id <= 8 THEN b(x, y).reveal = -1 showCell x, y END IF END IF END IF NEXT NEXTEND SUB 'center the text around (x, y) point, needs a graphics screen!SUB cText (x, y, textHeight AS SINGLE, K AS _UNSIGNED LONG, txt$) DIM fg AS _UNSIGNED LONG, cur&, I&, mult!, xlen fg = _DEFAULTCOLOR 'screen snapshot cur& = _DEST I& = _NEWIMAGE(8 * LEN(txt$), 16, 32) _DEST I& COLOR K, _RGBA32(0, 0, 0, 0) _PRINTSTRING (0, 0), txt$ mult! = textHeight / 16 xlen = LEN(txt$) * 8 * mult! _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur& COLOR fg _FREEIMAGE I&END SUB FUNCTION rightOf$ (source$, of$) IF INSTR(source$, of$) > 0 THEN rightOf$ = MID$(source$, INSTR(source$, of$) + LEN(of$))END FUNCTION FUNCTION getChar$ (fromStr$) DIM OK AS INTEGER, k$ WHILE OK = 0 k$ = INKEY$ IF LEN(k$) THEN IF INSTR(fromStr$, k$) <> 0 THEN OK = -1 END IF _LIMIT 200 WEND _KEYCLEAR getChar$ = k$END SUB 'from Steve Gold standardSUB fcirc (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG) DIM Radius AS INTEGER, RadiusError AS INTEGER DIM X AS INTEGER, Y AS INTEGER Radius = ABS(R): RadiusError = -Radius: X = Radius: Y = 0 IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB LINE (CX - X, CY)-(CX + X, CY), C, BF WHILE X > Y RadiusError = RadiusError + Y * 2 + 1 IF RadiusError >= 0 THEN IF X <> Y + 1 THEN LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF END IF X = X - 1 RadiusError = RadiusError - X * 2 END IF Y = Y + 1 LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF WENDEND SUB
Navigation
[0] Message Index
Go to full version