recursion - How to recursively identify cells of specific type in grid? -


i'm learning f# , i'm building minesweeper app. part of that, i'm trying have method detonates adjacent mines if mine detonated, recursively. if have grid like:

     |  0  |  1  |  2  | ------------------------   0  | e-1 |  m  | e-2 |   1  | e-2 | e-4 |  m  |   2  |  m  | e-3 |  m  | 

and detonate mine in 0,1, in turn detonate mine in 1,2 , in turn detonate mine in 2,2. mine in 2,0 not detonate because isn't adjacent of others.

at point i've implemented field list:

module cellcontents =   type t =      | empty of int     | mine     | crater  module location =   type t = { row: int; column: int }  module cell =   type t =      { content : cellcontents.t       location : location.t }  module field =   type t = cell.t list 

what i'm having trouble how start cell 0,1 , end list of mines adjacent. so, need list (showing coordinates):

let minestodetonate = [ {row=0;column=1};{row=1;column=2};{row=2;column=2} ] 

i have no trouble getting adjacent mines specific location , determining mines group.

what i'm having trouble with getting recurse somehow , go until there no mines found adjacent, giving me master list mines need detonate.

once master list of mines, can detonate them , build updated field mines becoming craters.

update @kevin's answer worked, had hard time understanding it. in case others have hard time, i'm adding function below, comments , couple of changes.

let detonateproximity (field:t) (start:cell.t) =     let rec inner cells m acc =         match cells         | [] -> acc         | x::xs ->              match x.content             |mine ->               match proximity m.location x.location               // continue don't accumulate               | self -> inner xs m acc               | near ->                    // see if current cell has been found                   match acc |> list.tryfind (fun t -> t = x)                   // if has, we're done. pass out                   // empty list ends recursion.                   |some _ -> []                    // if wasn't found (this parts hurts brain)...                   // calls function once rest field ,                   // using new starting point on whole field.                   // efficient @ all?                   |none -> list.concat [(inner xs m (x::acc));(inner field x (x::acc))]               // don't accumulate, continue rest of mines.               | far -> inner xs m acc             // not mine, keep going, don't accumulate             |_ -> inner xs m acc      // set ensures no duplicates     set.oflist (inner field start []) 

the proximity function (not shown) wraps logic determines if tested mine reference mine, close or far it. e.g. self returned if distance between current cell , mine 0 {row=0, column=0}.

this return set of detonated cells including 1 started chain reaction.

module location =   type t = {row: int; column: int }    let subtract l1 l2 =       {row=l1.row - l2.row;column=l1.column-l2.colum  let detonate (field:field.t) (start:cell.t) =   let rec inner cells m acc =     match cells     | [] -> acc     | x::xs -> match x.content                |mine ->match subtract m.location x.location                        |{row = 0;column = 0} -> inner xs m acc                        |loc when abs (loc.row) < 2 && abs (loc.column) < 2 ->                            match acc |> list.tryfind (fun t -> t = x)                           |some _ -> []                            |none -> list.concat [(inner xs m (x::acc));(inner field x (x::acc))]                        | _ -> inner xs m acc                |_ -> inner xs m acc   set.oflist (inner field start []) 

if want list of locations in question easy convert so:

detonate board {content=mine;location={row=0;column=1}}   |> set.map (fun t -> t.location)   |> set.tolist 

Comments

Popular posts from this blog

facebook - android ACTION_SEND to share with specific application only -

python - Creating a new virtualenv gives a permissions error -

javascript - cocos2d-js draw circle not instantly -