Application MineHunt
2004-06-02 - 22:39
MineHunt
-- MineHunt main handlers
-- To do:
-- make a routine to discover islands left, x to the right, y up.
-- Parameters
-- ==========
constant cCellSize = 20 -- width and height of a field cell
constant cTopInfoHeight = 20 -- minimum space for the indicator fields at the top
constant cBottomInfoHeight = 40 -- minimum space for the buttons and fields at the bottom
constant cTitleBbarHeight = 20 -- title bar is sometimes counted, sometimes not...
constant cGridMargin = 20 -- minimum space between grid and surrounding objects
constant cOutlineMargin = 10 -- minimum space between outline field and surrounding objects
constant cBottomRow = 0 -- distance of interface objects from bottom of window
constant cDefaultNrLivesDesired = 5 -- number of lives given at startup or after resizing the grid
constant cStateCovered=-1, cStateUncovered=-2, cStateFlagged=-3, cStateSuspected=-4, cStateWronglyFlagged=-5
-- Data Structures
-- ===============
-- Interface
-- ---------
global gGridWidth -- width of playing grid in number of cells
global gGridHeight -- height of playing grid in number of cells
global gGridLeftMargin -- distance between left side of window and centre of left column cells
global gGridTopMargin -- distance between top of window and centre of top row cells
global gNrOfLivesDesired -- last setting by the player
global gGameInProgress -- true after first cell has been touched; reset when game is over
global gColours -- the different colours in use
global gSoundOn -- whether illegal moves are signalled with a beep
global gFreeLevel -- proportion of free cells over cells holding bombs (inverse of bomb density)
-- Bookkeeping
-- -----------
-- grid-size arrays:
global gSpaces -- an empty array used to blank out other arrays.
global gBombs -- cells holding a bomb
global gBombCounts -- the number of bombs surrounding each cell
global gCellStates -- the states of the cells; one of the constants whose names start with "cState"
-- counters:
global gNrStillCovered -- the number of cells still covered
global gNrBombsLeftToIdentify -- number of bombs not having a flag yet
global gNrOfLivesLeft -- number of lives left
lock messages; lock screen
InitialiseGlobals
send "OpenSize" to stack "MineHunt" in 1 second
-- for some reason the stack size does not come up right, so we set it here:
set the width of stack "MineHunt" to 200; set the height of stack "MineHunt" to 260
ResizeStack 200,260
send "menupick ""e&"Medium""e to button "Level"
-- Interface
put 0 into gGridWidth; put 0 into gGridHeight; put 0 into gGridLeftMargin; put 0 into gGridTopMargin
put 0 into gNrBombsLeftToIdentify
put cDefaultNrLivesDesired into gNrOfLivesDesired
put false into gGameInProgress
put "133,166,112" into gColours["Outline" ]
put "120,120,120" into gColours["GridLines" ]
put "120,120,120" into gColours["Numbers" ]
put " 80, 80, 80" into gColours["Covered" ]
put "250,250,250" into gColours["Uncovered" ]
put "180,100,100" into gColours["Flagged" ]
put "180,180,100" into gColours["Suspected" ]
put "255, 0, 0" into gColours["Bomb" ]
put "100,255,100" into gColours["WronglyFlagged"]
put true into gSoundOn; put 5 into gFreeLevel
-- Bookkeeping - arrays
put "" into gBombs; put "" into gBombCounts; put "" into gCellStates; put 0 into gNrStillCovered; put "" into gSpaces
hide field "Message"
-- cells have a one-pixel border, the borders of neighbouring cells should overlap,
-- so the distance between cell centres is cCellsize-1
lock screen
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
put "C"&(D2(iX)&D2(iY)) into lfieldName
create field lfieldName
set the width of field lfieldName to cCellSize
set the height of field lfieldName to cCellSize
set the loc of field lfieldName to (iX-1)*(cCellSize-1)+gGridLeftMargin,(gGridHeight-iY)*(cCellSize-1)+gGridTopMargin
set the threeD of field lfieldName to "false"
set the traversalon of field lfieldName to "false"
set the locktext of field lfieldName to "true"
set the showfocusborder of field lfieldName to "false"
set the borderwidth of field lfieldName to 1
set the foregroundcolor of field lfieldName to gColours["GridLines"]
set the backgroundcolor of field lfieldName to gColours["Covered" ]
set the bordercolor of field lfieldName to gColours["GridLines"]
set the pCell of field lfieldName to "true"
set the pCoordinates of field lfieldName to iX,iY
set the script of field lfieldName to "on MouseUp"&return&"CellClick"&return&"end MouseUp"
set the layer of field "Message" to 100000
lock screen
-- fill the cell state array:
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
put cStateCovered into gCellStates[iX,iY]
repeat with iCell=the number of fields down to 1
if the pCell of field iCell = "true" then
set the backgroundcolor of field iCell to gColours["Covered" ]
put "" into field iCell
-- take all cells off the board
lock screen
repeat with iCell=the number of fields down to 1
if the pCell of field iCell = "true" then
delete field iCell
-- fW is the stack window width, but fH is the height of the stack minus the height of the title bar,
-- i.e. the height of the drawable area. However, y starts at the top of the title bar.
RemoveCells
put the topleft of this stack into lTopLeft -- need to set this back later, otherwise stack moves on screen.
-- restrict the size of the playing grid: at least 8x8 cells and at most 20x20 cells
put ( 8*cCellSize + cGridMargin*2) into lMinimumWidth
put (20*cCellSize + cGridMargin*2) into lMaximumWidth
put ( 8*cCellSize + cTopInfoHeight + cBottomInfoHeight + cGridMargin*2) into lMinimumHeight
put (20*cCellSize + cTopInfoHeight + cBottomInfoHeight + cGridMargin*2) into lMaximumHeight
if fW<lMinimumWidth then put lMinimumWidth into fW
if fW>lMaximumWidth then put lMaximumWidth into fW
if fH<lMinimumHeight then put lMinimumHeight into fH
if fH>lMaximumHeight then put lMaximumHeight into fH
set the width of this stack to fW; set the height of this stack to fH; set the topleft of this stack to lTopLeft
-- decide the grid size:
-- cells have a one-pixel border, the borders of neighbouring cells should overlap, so the distance between cell
-- centres is cCellsize-1
put (fW - cGridMargin*2) div (cCellSize-1) into gGridWidth
put (fH - cTopInfoHeight - cBottomInfoHeight - cGridMargin*2) div (cCellSize-1) into gGridHeight
-- centre the grid:
-- the slack is:
put fW - gGridWidth * (cCellsize-1) +1 into lWidthSlack
put fH - gGridHeight * (cCellsize-1) +1 - cTopInfoHeight - cBottomInfoHeight into lHeightSlack
put lWidthSlack div 2 + cCellSize div 2 into gGridLeftMargin
put cTitleBbarHeight + cTopInfoHeight + cCellSize div 2 + lHeightSlack div 2 into gGridTopMargin
put gGridWidth&" x "&gGridHeight&" = "&gGridWidth*gGridHeight&" cells" into field "GridSize"
-- Position Interface Objects
set the width of graphic "MineFieldOutline" to fW-2*cOutlineMargin
set the height of graphic "MineFieldOutline" to fH-cTopInfoHeight-cBottomInfoHeight-2*cOutlineMargin
set the left of graphic "MineFieldOutline" to cOutlineMargin
set the top of graphic "MineFieldOutline" to cTitleBbarHeight+cTopInfoHeight+cOutlineMargin
set the loc of field "GridSize" to 70,cTopInfoHeight+cTitleBbarHeight
set the loc of field "NumberOfBombs" to (the width of me)-65,cTopInfoHeight+cTitleBbarHeight
set the loc of field "hNumberOfBombs" to (the width of me)-35,cTopInfoHeight+cTitleBbarHeight
set the loc of button "NewGame" to 45,fH-cBottomRow
set the loc of graphic "UpButton" to 120,fH-cBottomRow-12; set the layer of graphic "UpButton" to 1
set the loc of graphic "DownButton" to 120,fH-cBottomRow+12; set the layer of graphic "DownButton" to 1
set the loc of field "NumberOfLives" to 93,fH-cBottomRow
set the loc of field "hLives" to 120,fH-cBottomRow
set the loc of button "Solve" to (the width of me)-35,fH-cBottomRow
set the loc of field "Message" to (the width of me) div 2,(the height of me) div 2
LayoutTheGrid
-- set or reset globals:
-- fill the blank array:
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
put " " into gSpaces[iX,iY]
put gSpaces into gBombs; put gSpaces into gBombCounts
put cDefaultNrLivesDesired into gNrOfLivesDesired
-- start the game:
send "MouseUp" to button "NewGame"
put gSpaces into gBombs
put (gGridWidth*gGridHeight) into lNrSquares
put lNrSquares div gFreeLevel into gNrBombsLeftToIdentify
put gNrBombsLeftToIdentify into field "NumberOfBombs"
--DoFixedSet
--exit SprinkleBombs
repeat with iBomb=1 to gNrBombsLeftToIdentify
repeat
put random(lNrSquares) into lThisBomb
put (lThisBomb div gGridWidth)+1 into lY
put (lThisBomb mod gGridWidth) into lX
if lX=0 then
put gGridWidth into lX; subtract 1 from lY
if gBombs[lX,lY] is not "*" then
put "*" into gBombs[lX,lY]
exit repeat
-- fill gBombCounts with the bombcounts
put gBombs into gBombCounts
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
-- count the number of bombs around this cell
if gBombs[iX,iY] = "*" then next repeat
put 0 into lNrBombsAround
if gBombs[iX-1,iY-1] = "*" then add one to lNrBombsAround
if gBombs[iX ,iY-1] = "*" then add one to lNrBombsAround
if gBombs[iX+1,iY-1] = "*" then add one to lNrBombsAround
if gBombs[iX-1,iY ] = "*" then add one to lNrBombsAround
if gBombs[iX+1,iY ] = "*" then add one to lNrBombsAround
if gBombs[iX-1,iY+1] = "*" then add one to lNrBombsAround
if gBombs[iX ,iY+1] = "*" then add one to lNrBombsAround
if gBombs[iX+1,iY+1] = "*" then add one to lNrBombsAround
put lNrBombsAround into gBombCounts[iX,iY]
-- this one is for the human player:
put "Normal" into lClickType
if the optionkey is down then put "PlantFlag" into lClickType
if the shiftkey is down then put "PlantSuspect" into lClickType
put the short name of the target into lThisCell
put item 1 of the pCoordinates of field lThisCell into lX; put item 2 of the pCoordinates of field lThisCell into lY
ClickOnCell lClickType,lx,ly
on ClickOnCell fClickType,fX,fY |
|
-- and this one is for both the human and the machine:
put "C"&D2(fX)&D2(fY) into lThisCell
switch gCellStates[fX,fY]
-- ---------------------------------------------------------------------- U N C O V E R E D
-- ---------------------------------------------------- refuse to do anything if cell is already uncovered
case cStateUncovered
switch fClickType
case "Normal"
break
case "PlantFlag"
break
case "PlantSuspect"
break
AlertPlayer
exit ClickOnCell
break
-- ---------------------------------------------------------------------- C O V E R E D
case cStateCovered
switch fClickType
case "Normal"
if gBombs[fX,fY] = "*" then
-- ---------------------------------------------------- NORMAL: die if a bomb
AlertPlayer
put cStateUncovered into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Bomb"]
subtract one from field "NumberOfBombs"
subtract one from gNrBombsLeftToIdentify
subtract one from gNrStillCovered
subtract 1 from gNrOfLivesLeft; put gNrOfLivesLeft into field "NumberOfLives"
if gNrOfLivesLeft=0 then
DisplayAllBombs
else
-- ---------------------------------------------------- NORMAL: show bombcount
put gBombCounts[fX,fY] into lThisSurround
if lThisSurround>0 then
put lThisSurround into field lThisCell
put cStateUncovered into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Uncovered"]
subtract one from gNrStillCovered
else -- uncover all connected free terrain
UncoverFreeTerrain fX,fY
break
case "PlantFlag"
-- ---------------------------------------------------- FLAG: plant flag
if field "NumberOfBombs" = 0 then -- can't plant more flags than there are bombs!
AlertPlayer
exit ClickOnCell
put cStateFlagged into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Flagged"]
subtract one from field "NumberOfBombs"
subtract one from gNrStillCovered
if gBombs[fX,fY] = "*" then
subtract one from gNrBombsLeftToIdentify
break
case "PlantSuspect"
-- ---------------------------------------------------- SUSPECT: consider still among covered cells
put cStateSuspected into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Suspected"]
break
break
-- ---------------------------------------------------------------------- F L A G G E D
case cStateFlagged
switch fClickType
case "Normal"
-- ---------------------------------------------------- NORMAL: disallowed
AlertPlayer
exit ClickOnCell
break
case "PlantFlag"
-- ---------------------------------------------------- FLAG: remove flag
put cStateCovered into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Covered"]
add one to field "NumberOfBombs"
add one to gNrStillCovered
if gBombs[fX,fY] = "*" then
add one to gNrBombsLeftToIdentify
break
case "PlantSuspect"
-- ---------------------------------------------------- SUSPECT: remove flag then suspect
add one to field "NumberOfBombs"
add one to gNrStillCovered
if gBombs[fX,fY] = "*" then
add one to gNrBombsLeftToIdentify
put cStateSuspected into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Suspected"]
break
break
-- ---------------------------------------------------------------------- S U S P E C T E D
case cStateSuspected
switch fClickType
case "Normal"
-- ---------------------------------------------------- NORMAL: disallowed
AlertPlayer
exit ClickOnCell
break
case "PlantFlag"
-- ---------------------------------------------------- FLAG: plant flag
put cStateFlagged into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Flagged"]
subtract one from field "NumberOfBombs"
subtract one from gNrStillCovered
if gBombs[fX,fY] = "*" then
subtract one from gNrBombsLeftToIdentify
break
case "PlantSuspect"
-- ---------------------------------------------------- SUSPECT: remove suspect
put cStateCovered into gCellStates[fX,fY]
set the backgroundcolor of field lThisCell to gColours["Covered"]
break
break
if gNrBombsLeftToIdentify = 0 and gNrStillCovered = 0 then
DisplayMessage "Congratulations,"&return&"you won!"
put false into gGameInProgress
else
put true into gGameInProgress
on UncoverFreeTerrain fX,fY |
|
--
-- Cell fX,fY has a zero. Start with a blank field, mark this position with "0".
-- Then: for any zero, replace it with "x" and copy the bombcounts of its neighbours that are blank.
-- Repeat this until no more zeroes found. This leaves a mixture of numbers, "x"s and blank positions.
-- Uncover all non-blank positions.
--
put gSpaces into lMarks
put "0" into lMarks[fX,fY]
repeat
put false into lZeroFound
repeat with iX=1 to gGridWidth
repeat with iY=1 to gGridHeight
if lMarks[iX,iY] is "0" then
if lMarks[iX-1,iY-1] = " " then put gBombCounts[iX-1,iY-1] into lMarks[iX-1,iY-1]
if lMarks[iX ,iY-1] = " " then put gBombCounts[iX ,iY-1] into lMarks[iX ,iY-1]
if lMarks[iX+1,iY-1] = " " then put gBombCounts[iX+1,iY-1] into lMarks[iX+1,iY-1]
if lMarks[iX-1,iY ] = " " then put gBombCounts[iX-1,iY ] into lMarks[iX-1,iY ]
put "x" into lMarks[iX,iY]
if lMarks[iX+1,iY ] = " " then put gBombCounts[iX+1,iY ] into lMarks[iX+1,iY ]
if lMarks[iX-1,iY+1] = " " then put gBombCounts[iX-1,iY+1] into lMarks[iX-1,iY+1]
if lMarks[iX ,iY+1] = " " then put gBombCounts[iX ,iY+1] into lMarks[iX ,iY+1]
if lMarks[iX+1,iY+1] = " " then put gBombCounts[iX+1,iY+1] into lMarks[iX+1,iY+1]
put true into lZeroFound
if not lZeroFound then exit repeat
-- uncover:
repeat with iX=1 to gGridWidth
repeat with iY=1 to gGridHeight
put lMarks[iX,iY] into lMark
if lMark is not space then
put "C"&D2(iX)&D2(iY) into lCellName
switch gCellStates[iX,iY]
case cStateCovered
subtract one from gNrStillCovered
break
case cStateUncovered
break
case cStateFlagged
add one to field "NumberOfBombs"
break
case cStateSuspected
break
put cStateUncovered into gCellStates[iX,iY]
set the backgroundcolor of field lCellName to gColours["Uncovered"]
if lMark = "x" then
put "" into field lCellName
else
put lMark into field lCellName
repeat with iX=1 to gGridWidth
repeat with iY=1 to gGridHeight
if gBombs[iX,iY] is "*" then
if gCellStates[iX,iY] is not cStateFlagged then
put "C"&D2(iX)&D2(iY) into lCellName
set the backgroundcolor of field lCellName to gColours["Bomb"]
else
if gCellStates[iX,iY] is cStateFlagged then
put "C"&D2(iX)&D2(iY) into lCellName
set the backgroundcolor of field lCellName to gColours["WronglyFlagged"]
DisplayMessage "Sorry,"&return&"you did not make it..."
put false into gGameInProgress
on DisplayMessage fMessage |
|
show field "Message"
put return&fMessage into field "Message"
if fi<10 then
return "0"&fi
else
return fi
if gSoundOn then beep
-- Debugging
put \
"* * ** * * "&return&\
" * * * * "&return&\
" * "&return&\
" * * "&return&\
" * * * "&return&\
" * "&return&\
" * "&return&\
" * * " into lbombs
repeat with iX=1 to 13
repeat with iY=1 to 8
if char iX of line (9-iY) of lBombs = "*" then put "*" into gBombs[iX,iY]
on PutSomeGrid fName,fGrid |
|
global gDebug
put gSpaces into gDebug
repeat with y=1 to gGridHeight
repeat with x=1 to gGridWidth
put fGrid[x,y] into item x of line (gGridHeight - y+1) of gDebug
put return&return&"["&fName&"]"&return&gDebug after msg
button NewGame
global gNrBombs, gNrOfLivesDesired, gNrOfLivesLeft, gGameInProgress, gNrStillCovered
global gGridWidth, gGridHeight
hide field "Message"
CoverAndEmptyAllCells
SprinkleBombs
SetBombCounts
put gNrOfLivesDesired into gNrOfLivesLeft
put gNrOfLivesLeft into field "NumberOfLives"
put gGridWidth*gGridHeight into gNrStillCovered
put false into gGameInProgress
button Solve
-- Button "Solve"
-- Coordinate system: origin in bottom left, x to the right, y up.
-- Parameters
-- ==========
constant cStateCovered=-1, cStateUncovered=-2, cStateFlagged=-3, cStateSuspected=-4, cStateWronglyFlagged=-5
-- Data Structures
-- ===============
-- Interface
-- ---------
global gGridWidth -- width of playing grid in number of cells
global gGridHeight -- height of playing grid in number of cells
global gGridLeftMargin -- distance between left side of window and centre of left column cells
global gGridTopMargin -- distance between top of window and centre of top row cells
global gNrOfLivesDesired -- last setting by the player
global gGameInProgress -- true after first cell has been touched; reset when game is over
global gColours -- the different colours in use
global gSoundOn -- whether illegal moves are signalled with a beep
global gFreeLevel -- proportion of free cells over cells holding bombs (inverse of bomb density)
-- Bookkeeping
-- -----------
-- grid-size arrays:
global gSpaces -- an empty array used to blank out other arrays.
global gBombs -- cells holding a bomb
global gBombCounts -- the number of bombs surrounding each cell
global gCellStates -- the states of the cells; one of the constants whose names start with "cState"
-- counters:
global gNrStillCovered -- the number of cells still covered
global gNrBombsLeftToIdentify -- number of bombs not having a flag yet
global gNrOfLivesLeft -- number of lives left
global gBoardState -- what this algorithm can see.
put gCellStates into gBoardState
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
if gBoardState[iX,iY] = cStateUnCovered then
put gBombCounts[iX,iY] into gBoardState[iX,iY]
--PutSomeGrid "Board state",gBoardState
function UncoveredASea fBoardState |
|
put 0 into lSeaCount
repeat with iY=1 to gGridHeight
repeat with iX=1 to gGridWidth
if fBoardState[iX,iY] = 0 then
add 1 to lSeaCount
if lSeaCount>0 then
return true
else
return false
function CoordinatesOfSurroundingCells fX,fY |
|
put empty into lResult; put 0 into ll
if fX>1 and fY<gGridHeight then
add 1 to ll; put (fX-1,fY+1) into line ll of lResult
if fY<gGridHeight then
add 1 to ll; put (fX ,fY+1) into line ll of lResult
if fX<gGridWidth and fY<gGridHeight then
add 1 to ll; put (fX+1,fY+1) into line ll of lResult
if fX>1 then
add 1 to ll; put (fX-1,fY ) into line ll of lResult
if fX<gGridWidth then
add 1 to ll; put (fX+1,fY ) into line ll of lResult
if fX>1 and fY>1 then
add 1 to ll; put (fX-1,fY-1) into line ll of lResult
if fY>1 then
add 1 to ll; put (fX ,fY-1) into line ll of lResult
if fX<gGridWidth and fY>1 then
add 1 to ll; put (fX+1,fY-1) into line ll of lResult
return lResult
function CoordinatesOfSurroundingDiags fX,fY |
|
put empty into lResult; put 0 into ll
if fX>1 and fY<gGridHeight then
add 1 to ll; put (fX-1,fY+1) into line ll of lResult
if fX<gGridWidth and fY<gGridHeight then
add 1 to ll; put (fX+1,fY+1) into line ll of lResult
if fX>1 and fY>1 then
add 1 to ll; put (fX-1,fY-1) into line ll of lResult
if fX<gGridWidth and fY>1 then
add 1 to ll; put (fX+1,fY-1) into line ll of lResult
return lResult
send "Mouseup" to button "NewGame"
DisplayMessage "Not implemented yet"
exit mouseup
-- at the start we click at random.
-- There are three possible results:
-- a bomb, a number, a sea.
-- if it is a bomb, try again:
repeat
put random(gGridWidth) into lX; put random(gGridHeight) into lY
ClickOnCell "Normal",lX,lY
GetBoardState
if gBoardState[lX,lY] "*" then
exit repeat
if gNrOfLivesLeft=0 then exit mouseup
repeat
-- if it is a sea, then we go intelligent...
if UncoveredASea(gBoardState) then
put "YAHOOOOOO!"; exit mouseup
else if gBoardState[lX,lY] = "1" then -- we try to find a sea by taking one of its diagonals:
repeat
put CoordinatesOfSurroundingDiags(lX,lY) into lSurroundingDiags
put line random(the number of lines of lSurroundingDiags) of lSurroundingDiags into lCellToClick
put item 1 of lCellToClick into lX; put item 2 of lCellToClick into lY
ClickOnCell "Normal",lX,lY
if gNrOfLivesLeft=0 then exit mouseup
GetBoardState
if UncoveredASea(gBoardState) then exit mouseup
if gBoardState[lX,lY] "1" then exit repeat
else -- click again at random
put random(gGridWidth) into lX; put random(gGridHeight) into lY
ClickOnCell "Normal",lX,lY
GetBoardState
if gNrOfLivesLeft=0 then exit mouseup
exit mouseup
global gNumberOfLives, gDefaultNumberOfLives, gGameInProgress
if gGameInProgress then
beep
exit MouseUp
-- solve the puzzle
/*
Border constraints: the cells at the borders of the field have fewer than 8 surrounding cells.
The set of surrounding cells of cell x,y is:
A B C
D E
F G H
They exist if: and the coordinates are:
A if x>1 and y<gGridHeight x-1,y+1
B if y<gGridHeight x ,y+1
C if x<gGridWidth and y<gGridHeight x+1,y+1
D if x>1 x-1,y
E if x<gGridWidth x+1,y
F if x>1 and y>1 x-1,y-1
G if y>1 x ,y-1
H if x<gGridWidth and y>1 x+1,y-1
Keep the set of still covered cells in gCovered.
Keep the set of uncovered cells in gUncovered, just for speed.
Keep the set of known bombs in gKnownBombs
Uncovered cells have a certain probability to harbour a bomb.
Naively this is the number of unknown bombs divided by the number of uncovered cells.
However, the numbers in the uncovered cells give us more info:
Say a cell displays a number of
n surrounding bombs, it is surrounded by
p uncovered cells,
q covered ones and
r covered but known bombs.
Clearly r<=n and p+q+r = 8.
If r=n then the probability that any of the q covered cells has a bomb is zero.
if r<n then there must be n-r unknown bombs in the q covered cells and, without any other
information, the probability of any of the q covered cells having a bomb is (n-r)/q.
If (n-r)/q = 1 then the number of unknown bombs equals the number of covered neighbours
and therefore they are all bombs and can be marked accordingly.
There is only ambiguity if q>(n-r) i.e. more uncovered cells than unknown bombs. In this case
we need info from neighbouring cells or, if not possible, a guess.
We could try all configurations of the remaining bombs in the uncoverd squares of the board,
and eleminate those that are in conflict with the known numbers.
The remaining configurations together may show possible inambiguities. Think of it as placing
all the configurations on transparent sheets and putting all sheets on top of each other:
1) if any cell does not appear as a possible bomb in any of the configurations, it is impossible
that it holds a bomb and it can be uncovered. (you can see through it in the stack of sheets).
2) if any cell has a bomb in all configurations, it can be flagged as a bomb. (it is a very
opaque cell in the stack of sheets).
3) if there are no cells conforming to 1) or 2), then only a guess remains. The best guess
corresponds to a cell that has fewest bombs in the set of configurations.
However, to compute all the configurations takes a very large amount of time.
A strategy which is "next-best" may be to compute configurations only for the cells close to the
area that we have already uncovered, i.e. the cells at the "frontier" of what we know.
A cell is a frontier cell if it has at least one uncovered neighbour.
Keep the set of frontier cells in gFrontier.
We know there are b bombs remaining to be identified. Try to place them in the frontier region.
If all configurations require all bombs to be placed, then all of the non-frontier region can be
uncovered!
*/
global gGridWidth, gGridHeight, gBombs, gNumbers, gSpaces, gKnown
global gNoMoreSimpleMovesPossible
put gSpaces into gKnown
repeat
put false into gNoMoreSimpleMovesPossible
repeat
DoASimpleMove
if gNoMoreSimpleMovesPossible then exit repeat
DoARandomMove
--
global gGridWidth, gGridHeight, gBombs, gNumbers, gSpaces, gKnown
global gNoMoreSimpleMovesPossible
repeat with iX=1 to gGridWidth
repeat with iY=1 to gGridHeight
put char iX of line iY of gKnown into lThisCell
if lThisCell is in "12345678" then -- examine this cell
-- count the surrounding blank cells:
put 0 into lSurroundingBlanks
if char iX-1 of line iY-1 of gKnown is space then add one to lSurroundingBlanks
if char iX of line iY-1 of gKnown is space then add one to lSurroundingBlanks
if char iX+1 of line iY-1 of gKnown is space then add one to lSurroundingBlanks
if char iX-1 of line iY of gKnown is space then add one to lSurroundingBlanks
if char iX+1 of line iY of gKnown is space then add one to lSurroundingBlanks
if char iX-1 of line iY+1 of gKnown is space then add one to lSurroundingBlanks
if char iX of line iY+1 of gKnown is space then add one to lSurroundingBlanks
if char iX+1 of line iY+1 of gKnown is space then add one to lSurroundingBlanks
if lThisCell is lSurroundingBlanks then
/*
*/
global gGridWidth, gGridHeight, gBombs, gSpaces
put (gGridWidth*gGridHeight) into lNrSquares
put random(lNrSquares) into lThisBomb
put (lThisBomb div gGridWidth)+1 into lY
put (lThisBomb mod gGridWidth) into lX
if lX=0 then
put gGridWidth into lX; subtract 1 from lY
if char lX of line lY of gBombs is not "*" then
put "*" into char lX of line lY of gBombs
exit repeat
button File
button Edit
button Sound
global gSoundOn
if fWhich = "Sound Off" then
put false into gSoundOn
set the text of button "Sound" to "Sound On"
else
put true into gSoundOn
set the text of button "Sound" to "Sound Off"
button Level
global gFreeLevel
go to card "PlayingField"
if fWhich = "Easy" then
put 10 into gFreeLevel
set the text of button "Level" to "!cEasy"&return&"!nMedium"&return&"!nHard"
set the backgroundcolor of this card to "200,255,180"
set the backgroundcolor of graphic "MineFieldOutline" to "150,230,100"
else if fWhich = "Medium" then
put 5 into gFreeLevel
set the text of button "Level" to "!nEasy"&return&"!cMedium"&return&"!nHard"
set the backgroundcolor of this card to "180,200,255"
set the backgroundcolor of graphic "MineFieldOutline" to "100,150,230"
else if fWhich = "Hard" then
put 3 into gFreeLevel
set the text of button "Level" to "!nEasy"&return&"!nMedium"&return&"!cHard"
set the backgroundcolor of this card to "255,200,180"
set the backgroundcolor of graphic "MineFieldOutline" to "230,150,100"
send "MouseUp" to button "NewGame"
button Help
if fWhich = "Rules" then
go to card "Rules"
else if fWhich = "How to" then
go to card "HowTo"
else if fWhich = "About" then
go to card "About"
button
field GridSize
field NumberOfLives
field hLives
field NumberOfBombs
field hNumberOfBombs
field C0101
CellClick
field C0201
CellClick
field C0301
CellClick
field C0401
CellClick
field C0501
CellClick
field C0601
CellClick
field C0701
CellClick
field C0801
CellClick
field C0102
CellClick
field C0202
CellClick
field C0302
CellClick
field C0402
CellClick
field C0502
CellClick
field C0602
CellClick
field C0702
CellClick
field C0802
CellClick
field C0103
CellClick
field C0203
CellClick
field C0303
CellClick
field C0403
CellClick
field C0503
CellClick
field C0603
CellClick
field C0703
CellClick
field C0803
CellClick
field C0104
CellClick
field C0204
CellClick
field C0304
CellClick
field C0404
CellClick
field C0504
CellClick
field C0604
CellClick
field C0704
CellClick
field C0804
CellClick
field C0105
CellClick
field C0205
CellClick
field C0305
CellClick
field C0405
CellClick
field C0505
CellClick
field C0605
CellClick
field C0705
CellClick
field C0805
CellClick
field C0106
CellClick
field C0206
CellClick
field C0306
CellClick
field C0406
CellClick
field C0506
CellClick
field C0606
CellClick
field C0706
CellClick
field C0806
CellClick
field C0107
CellClick
field C0207
CellClick
field C0307
CellClick
field C0407
CellClick
field C0507
CellClick
field C0607
CellClick
field C0707
CellClick
field C0807
CellClick
field C0108
CellClick
field C0208
CellClick
field C0308
CellClick
field C0408
CellClick
field C0508
CellClick
field C0608
CellClick
field C0708
CellClick
field C0808
CellClick
field Message
hide me
( end application MineHunt)