Keeping it simple, and keeping in mind this is just for illustrating the concept, I'd break it down as follows. I'm using javascript, since I haven't used python in a while, and please note I have not tested or run this. With those caveats in mind...
You have turtles, which are a color and an x, y position. A turtle can advance forward by a certain amount (a pure function, no side effects or mutation):
Code:
function advanceTurtle(distance, turtle) {
return {
x: turtle.x + distance,
y: turtle.y,
color: turtle.color
}
}
You also have a race, which consists of two turtles, and a finish line position. I'm going to use 0 as a start position for convenience, since the specific numbers in the original code are purely a view concern (ie, they matter only to the code which renders the race to the screen, so you can translate them at that point):
Code:
// example race object, at races start
const freshRace = {
turtle1: {x: 0, y: 0, color: 'red'},
turtle2: {x: 0, y: 0, color: 'blue'},
finishLine: 100
}
Now we need a function to advance a race from one state to the next, and a function to tell you if the race is over:
Code:
function advanceRace(t1Inc, t2Inc, race) {
return {
turtle1: advanceTurtle(t1Inc, race.turtle1),
turtle2: advanceTurtle(t2Inc, race.turtle2),
finishLine: race.finishLine
}
}
function isOver(race) {
return race.turtle1 >= race.finishLine ||
race.turtle2 >= race.finishLine
}
Everything is still pure up to now. Now we're going to contain our mutating state and other impurities (ie, the rng) in one place. Using streams would be a nice way to implement this, but I'm not going to do that because it'll just obsure the main of this post, which does not depend on streams or anything else. And just to show one of the benefits of this approach, we'll save every state of the race, so we'd get stuff like rewind and replay for free:
Code:
var raceStates = [freshRace]
// the last entry in the array of states
const currentRaceState = () => raceStates.slice(-1)
// impure (can easily make a pure version for testing)
const randomJump = () => 3 + Math.floor(Math.random() * 7)
while (!isOver(currentRaceState())) {
// do something here with the current state,
// like render it to a view
//
// perhaps pause x milliseconds between jumps
//
const nextState = advanceRace(randomJump(), randomJump(), currentRaceState())
raceStates.push(nextState) // only 1 line of mutation
}
Last edited by gaming_mouse; 06-13-2017 at 11:10 PM.