Conway's Game of Life F#Compact game of life implementationConway's Game of Life in F#Optimize Conway's Game...
How would one buy a used TIE Fighter or X-Wing?
Cryptic with missing capitals
Broken patches on a road
Difference between two quite-similar Terminal commands
Solving Fredholm Equation of the second kind
Eww, those bytes are gross
Is there any differences between "Gucken" and "Schauen"?
Quenching swords in dragon blood; why?
How to tag distinct options/entities without giving any an implicit priority or suggested order?
Checking for the existence of multiple directories
Can a person refuse a presidential pardon?
How to prevent users from executing commands through browser URL
The effects of magnetism in radio transmissions
Does Windows 10's telemetry include sending *.doc files if Word crashed?
Why don't American passenger airlines operate dedicated cargo flights any more?
How do I say "Brexit" in Latin?
Can an insurance company drop you after receiving a bill and refusing to pay?
Groups acting on trees
Why do members of Congress in committee hearings ask witnesses the same question multiple times?
How to deal with an incendiary email that was recalled
Can we use the stored gravitational potential energy of a building to produce power?
How to acknowledge an embarrassing job interview, now that I work directly with the interviewer?
How to explain planetary rings pulsating?
Book where aliens are selecting humans for food consumption
Conway's Game of Life F#
Compact game of life implementationConway's Game of Life in F#Optimize Conway's Game of LifeImplementing Conway's Game of LifeConway's Game of Life simulationGame of life in F#Conway's Game of LifeConway's Game of Life pythonSDL2.0 Conway's Game Of LifeConway's Game of Life classPython Conway's Game of life
$begingroup$
I am a C# developer learning F#. Would appreciate any suggestions on how this code can be improved. Main points I am interested in:
- Functional style of the code, absense of imperative style(C#) artifacts
- F# collection data types and functions usage
- General code(not algorithm) efficiency
Code style, naming etc.
let life board =
let flatten = Seq.cast<int> >> Seq.toArray
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.mapi (fun i el -> (i <> 4, el))
|> Array.filter fst |> Array.map snd
|> Array.filter ((=) 1) |> Array.length
let expandBoard board =
let N = Array2D.length1 board
array2D [|
yield [| yield board.[N - 1, N - 1]; yield! board.[N - 1, *]; yield board.[N - 1, 0] |]
for i in [0..N - 1] do yield [| yield board.[i, N - 1]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N - 1]; yield! board.[0, *]; yield board.[N - 1, 0] |]
|]
let getNextBoard board =
let eBoard = expandBoard board
board |> Array2D.mapi (fun i j elem ->
match neighboursCount eBoard j i with
| 2 -> elem
| 3 -> 1
| _ -> 0)
let isGameOver board prevBoards =
board |> flatten |> Array.forall ((=) 0) || List.contains board prevBoards
let rec lifeRec board prevBoards =
printfn "%A n" board
if isGameOver board prevBoards
then ()
else getNextBoard board |> lifeRec <| board::prevBoards
lifeRec board []
let N = 5
let rnd = System.Random()
Array2D.init N N (fun _ _ -> rnd.Next 2) |> life
f# game-of-life
$endgroup$
bumped to the homepage by Community♦ 13 hours ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
$begingroup$
I am a C# developer learning F#. Would appreciate any suggestions on how this code can be improved. Main points I am interested in:
- Functional style of the code, absense of imperative style(C#) artifacts
- F# collection data types and functions usage
- General code(not algorithm) efficiency
Code style, naming etc.
let life board =
let flatten = Seq.cast<int> >> Seq.toArray
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.mapi (fun i el -> (i <> 4, el))
|> Array.filter fst |> Array.map snd
|> Array.filter ((=) 1) |> Array.length
let expandBoard board =
let N = Array2D.length1 board
array2D [|
yield [| yield board.[N - 1, N - 1]; yield! board.[N - 1, *]; yield board.[N - 1, 0] |]
for i in [0..N - 1] do yield [| yield board.[i, N - 1]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N - 1]; yield! board.[0, *]; yield board.[N - 1, 0] |]
|]
let getNextBoard board =
let eBoard = expandBoard board
board |> Array2D.mapi (fun i j elem ->
match neighboursCount eBoard j i with
| 2 -> elem
| 3 -> 1
| _ -> 0)
let isGameOver board prevBoards =
board |> flatten |> Array.forall ((=) 0) || List.contains board prevBoards
let rec lifeRec board prevBoards =
printfn "%A n" board
if isGameOver board prevBoards
then ()
else getNextBoard board |> lifeRec <| board::prevBoards
lifeRec board []
let N = 5
let rnd = System.Random()
Array2D.init N N (fun _ _ -> rnd.Next 2) |> life
f# game-of-life
$endgroup$
bumped to the homepage by Community♦ 13 hours ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
$begingroup$
I am a C# developer learning F#. Would appreciate any suggestions on how this code can be improved. Main points I am interested in:
- Functional style of the code, absense of imperative style(C#) artifacts
- F# collection data types and functions usage
- General code(not algorithm) efficiency
Code style, naming etc.
let life board =
let flatten = Seq.cast<int> >> Seq.toArray
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.mapi (fun i el -> (i <> 4, el))
|> Array.filter fst |> Array.map snd
|> Array.filter ((=) 1) |> Array.length
let expandBoard board =
let N = Array2D.length1 board
array2D [|
yield [| yield board.[N - 1, N - 1]; yield! board.[N - 1, *]; yield board.[N - 1, 0] |]
for i in [0..N - 1] do yield [| yield board.[i, N - 1]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N - 1]; yield! board.[0, *]; yield board.[N - 1, 0] |]
|]
let getNextBoard board =
let eBoard = expandBoard board
board |> Array2D.mapi (fun i j elem ->
match neighboursCount eBoard j i with
| 2 -> elem
| 3 -> 1
| _ -> 0)
let isGameOver board prevBoards =
board |> flatten |> Array.forall ((=) 0) || List.contains board prevBoards
let rec lifeRec board prevBoards =
printfn "%A n" board
if isGameOver board prevBoards
then ()
else getNextBoard board |> lifeRec <| board::prevBoards
lifeRec board []
let N = 5
let rnd = System.Random()
Array2D.init N N (fun _ _ -> rnd.Next 2) |> life
f# game-of-life
$endgroup$
I am a C# developer learning F#. Would appreciate any suggestions on how this code can be improved. Main points I am interested in:
- Functional style of the code, absense of imperative style(C#) artifacts
- F# collection data types and functions usage
- General code(not algorithm) efficiency
Code style, naming etc.
let life board =
let flatten = Seq.cast<int> >> Seq.toArray
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.mapi (fun i el -> (i <> 4, el))
|> Array.filter fst |> Array.map snd
|> Array.filter ((=) 1) |> Array.length
let expandBoard board =
let N = Array2D.length1 board
array2D [|
yield [| yield board.[N - 1, N - 1]; yield! board.[N - 1, *]; yield board.[N - 1, 0] |]
for i in [0..N - 1] do yield [| yield board.[i, N - 1]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N - 1]; yield! board.[0, *]; yield board.[N - 1, 0] |]
|]
let getNextBoard board =
let eBoard = expandBoard board
board |> Array2D.mapi (fun i j elem ->
match neighboursCount eBoard j i with
| 2 -> elem
| 3 -> 1
| _ -> 0)
let isGameOver board prevBoards =
board |> flatten |> Array.forall ((=) 0) || List.contains board prevBoards
let rec lifeRec board prevBoards =
printfn "%A n" board
if isGameOver board prevBoards
then ()
else getNextBoard board |> lifeRec <| board::prevBoards
lifeRec board []
let N = 5
let rnd = System.Random()
Array2D.init N N (fun _ _ -> rnd.Next 2) |> life
f# game-of-life
f# game-of-life
edited Dec 13 '18 at 10:33
Andrew Boklashko
asked Nov 17 '18 at 20:23
Andrew BoklashkoAndrew Boklashko
412
412
bumped to the homepage by Community♦ 13 hours ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
bumped to the homepage by Community♦ 13 hours ago
This question has answers that may be good or bad; the system has marked it active so that they can be reviewed.
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
$begingroup$
This is a most elegant solution. I have two small improvements:
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.indexed
|> Array.sumBy (fun (i, n) -> if i <> 4 then n else 0)
let expandBoard board =
let N = (Array2D.length1 board) - 1
array2D [|
yield [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
|]
Here is N
set to (Array2D.length1 board) - 1
because that's the value you're using through out the function.
$endgroup$
add a comment |
$begingroup$
Review for the updated version (because there are no answers yet, I think you can still remove the first version).
I really like your implementation. Especially the idea of expanding the board instead of calculating the opposide indices as i did). That makes the code much more readable / understandable. I also like the way you imlemented the neighboursCount
function - the combination of mapi
, filter
and map
is a good example for functional programming.
In fact, I don't see much room for improvement.
Maybe you could rename neighboursCount
into countNeighbours
an move the board
to the end of the argument list so it can be used like: eBorad |> countNeighbours j i
Within the isGameOver
function, I think I would prefer writing prevBoards |> List.contains board
over List.contains board prevBoards
.
Thanks for sharing your solution :).
$endgroup$
$begingroup$
I believeneighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.
$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207879%2fconways-game-of-life-f%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
This is a most elegant solution. I have two small improvements:
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.indexed
|> Array.sumBy (fun (i, n) -> if i <> 4 then n else 0)
let expandBoard board =
let N = (Array2D.length1 board) - 1
array2D [|
yield [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
|]
Here is N
set to (Array2D.length1 board) - 1
because that's the value you're using through out the function.
$endgroup$
add a comment |
$begingroup$
This is a most elegant solution. I have two small improvements:
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.indexed
|> Array.sumBy (fun (i, n) -> if i <> 4 then n else 0)
let expandBoard board =
let N = (Array2D.length1 board) - 1
array2D [|
yield [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
|]
Here is N
set to (Array2D.length1 board) - 1
because that's the value you're using through out the function.
$endgroup$
add a comment |
$begingroup$
This is a most elegant solution. I have two small improvements:
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.indexed
|> Array.sumBy (fun (i, n) -> if i <> 4 then n else 0)
let expandBoard board =
let N = (Array2D.length1 board) - 1
array2D [|
yield [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
|]
Here is N
set to (Array2D.length1 board) - 1
because that's the value you're using through out the function.
$endgroup$
This is a most elegant solution. I have two small improvements:
let neighboursCount (board: int[,]) x y =
board.[y..y+2, x..x+2]
|> flatten
|> Array.indexed
|> Array.sumBy (fun (i, n) -> if i <> 4 then n else 0)
let expandBoard board =
let N = (Array2D.length1 board) - 1
array2D [|
yield [| yield board.[N, N]; yield! board.[N, *]; yield board.[N, 0] |]
for i in [0..N] do yield [| yield board.[i, N]; yield! board.[i, *]; yield board.[i, 0] |]
yield [| yield board.[0, N]; yield! board.[0, *]; yield board.[N, 0] |]
|]
Here is N
set to (Array2D.length1 board) - 1
because that's the value you're using through out the function.
answered Jan 30 at 14:19
Henrik HansenHenrik Hansen
7,49511128
7,49511128
add a comment |
add a comment |
$begingroup$
Review for the updated version (because there are no answers yet, I think you can still remove the first version).
I really like your implementation. Especially the idea of expanding the board instead of calculating the opposide indices as i did). That makes the code much more readable / understandable. I also like the way you imlemented the neighboursCount
function - the combination of mapi
, filter
and map
is a good example for functional programming.
In fact, I don't see much room for improvement.
Maybe you could rename neighboursCount
into countNeighbours
an move the board
to the end of the argument list so it can be used like: eBorad |> countNeighbours j i
Within the isGameOver
function, I think I would prefer writing prevBoards |> List.contains board
over List.contains board prevBoards
.
Thanks for sharing your solution :).
$endgroup$
$begingroup$
I believeneighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.
$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
add a comment |
$begingroup$
Review for the updated version (because there are no answers yet, I think you can still remove the first version).
I really like your implementation. Especially the idea of expanding the board instead of calculating the opposide indices as i did). That makes the code much more readable / understandable. I also like the way you imlemented the neighboursCount
function - the combination of mapi
, filter
and map
is a good example for functional programming.
In fact, I don't see much room for improvement.
Maybe you could rename neighboursCount
into countNeighbours
an move the board
to the end of the argument list so it can be used like: eBorad |> countNeighbours j i
Within the isGameOver
function, I think I would prefer writing prevBoards |> List.contains board
over List.contains board prevBoards
.
Thanks for sharing your solution :).
$endgroup$
$begingroup$
I believeneighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.
$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
add a comment |
$begingroup$
Review for the updated version (because there are no answers yet, I think you can still remove the first version).
I really like your implementation. Especially the idea of expanding the board instead of calculating the opposide indices as i did). That makes the code much more readable / understandable. I also like the way you imlemented the neighboursCount
function - the combination of mapi
, filter
and map
is a good example for functional programming.
In fact, I don't see much room for improvement.
Maybe you could rename neighboursCount
into countNeighbours
an move the board
to the end of the argument list so it can be used like: eBorad |> countNeighbours j i
Within the isGameOver
function, I think I would prefer writing prevBoards |> List.contains board
over List.contains board prevBoards
.
Thanks for sharing your solution :).
$endgroup$
Review for the updated version (because there are no answers yet, I think you can still remove the first version).
I really like your implementation. Especially the idea of expanding the board instead of calculating the opposide indices as i did). That makes the code much more readable / understandable. I also like the way you imlemented the neighboursCount
function - the combination of mapi
, filter
and map
is a good example for functional programming.
In fact, I don't see much room for improvement.
Maybe you could rename neighboursCount
into countNeighbours
an move the board
to the end of the argument list so it can be used like: eBorad |> countNeighbours j i
Within the isGameOver
function, I think I would prefer writing prevBoards |> List.contains board
over List.contains board prevBoards
.
Thanks for sharing your solution :).
answered Dec 12 '18 at 8:57
JanDotNetJanDotNet
6,9131339
6,9131339
$begingroup$
I believeneighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.
$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
add a comment |
$begingroup$
I believeneighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.
$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
$begingroup$
I believe
neighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
$begingroup$
I believe
neighboursCount
came from my OO background, where you name object properties like that. Also that is a bit unusual that I can use piping where it seems to be unneded, but in fact version with piping is much more readable, so I accept your point.$endgroup$
– Andrew Boklashko
Dec 13 '18 at 10:29
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f207879%2fconways-game-of-life-f%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown