WEBVTT 00:00.390 --> 00:02.980 We are now at the second video of this section. 00:03.040 --> 00:09.600 State design pattern in the previous video we looked at visitor design pattern in this video we are 00:09.600 --> 00:18.180 going to develop a very simple game that uses F S M St. patterns are directly related to FSM as an FSM 00:18.360 --> 00:24.030 in very simple terms is something that has one or more states and travels between them to execute some 00:24.030 --> 00:24.960 behaviors. 00:25.260 --> 00:32.730 Let's see how the states pattern helps us to define F S M a light switch as a common example of an FSM. 00:32.730 --> 00:38.670 It has two states on and off one state can transit to the other and vice versa. 00:38.730 --> 00:41.510 The way that the state pattern works is similar. 00:41.580 --> 00:44.940 We have a state interface and an implementation of each state. 00:45.000 --> 00:46.490 We want to achieve. 00:46.500 --> 00:51.610 There is also usually a context that holds cross information between the states with FSM. 00:51.660 --> 00:56.320 We can achieve very complex behaviors by splitting their scope between states. 00:56.340 --> 01:02.760 This way we can model pipelines of execution based on any kind of inputs or create event driven software 01:02.970 --> 01:06.540 that responds to particular events in specified ways. 01:06.570 --> 01:11.920 The main objective of the state's pattern is to develop FSM as listed here. 01:12.150 --> 01:18.480 First of all to have a type that alters its own behavior when some internal things have changed and 01:18.480 --> 01:24.660 modeled complex graphs and pipelines can be upgraded easily by adding more states and rerouting their 01:24.660 --> 01:26.180 output states. 01:26.280 --> 01:29.960 We are going to develop a very simple game that uses FSM. 01:29.970 --> 01:32.190 This game is a no guessing game. 01:32.190 --> 01:33.240 The idea is simple. 01:33.240 --> 01:39.370 We will have to get some number between 0 and 10 and we have just a few attempts or we'll lose. 01:39.570 --> 01:44.520 We will give the player to choose the level of difficulty by asking how many tries the user has before 01:44.520 --> 01:45.480 losing. 01:45.480 --> 01:50.850 Then we will ask the player for the correct number and keep asking if they don't get it or if the number 01:50.850 --> 01:52.950 of tries reaches zero. 01:53.160 --> 01:58.560 For this simple game we have 5 acceptance criteria that basically describes the mechanics of the game 01:59.070 --> 02:03.960 first the game will ask the player how many tries they will have before losing the game. 02:04.110 --> 02:08.030 Next the number to guess must be between zero and 10. 02:08.160 --> 02:14.010 Then every time a player enters a number to guess the number of retried drops by 1 and if the number 02:14.010 --> 02:17.110 of retry is reached 0 and the number is still incorrect. 02:17.250 --> 02:19.710 The game finishes and the player has lost. 02:20.430 --> 02:24.760 Lastly if the player guesses the number the player wins. 02:24.770 --> 02:28.060 Now we move on to the implementation of state pattern. 02:28.070 --> 02:34.130 The idea of unit tests is quite straightforward in state pattern so we will spend more time explaining 02:34.130 --> 02:38.920 in detail the mechanism to use it which is a bit more complex than usual. 02:38.930 --> 02:43.760 First of all we need the interface to represent the different states and the game context to store the 02:43.760 --> 02:46.250 information between states for this game. 02:46.250 --> 02:51.560 The context needs to store the number of retrials if the user has one or not the secret number to guess 02:51.740 --> 02:53.200 and the current state. 02:53.390 --> 02:59.000 The state will have an execute state method that accepts one of these contexts and returns true if the 02:59.000 --> 03:03.040 game is finished or false if not I've already written the code. 03:03.050 --> 03:05.660 We are going to use in state DOT go file. 03:05.810 --> 03:07.850 I will explain it step by step. 03:08.270 --> 03:13.790 So as I mentioned previously I have defined the interface game states and the integers secret number 03:13.850 --> 03:16.840 and retrials and the boolean one. 03:16.850 --> 03:23.110 Next we defined the type start state struct as described and acceptance criteria 1. 03:23.180 --> 03:27.110 The player must be able to introduce the number of retrials they want. 03:27.140 --> 03:33.940 This will be achieved by a state called Start state also the start state struct must prepare the game. 03:34.010 --> 03:36.980 Setting the context to its initial value before the player. 03:37.460 --> 03:40.400 So here's the piece of code for this task. 03:40.490 --> 03:46.910 First of all the start state struct implements the game state structure because it has the execute state 03:46.910 --> 03:50.600 context method of boolean type on its structure. 03:50.900 --> 03:57.080 At the beginning of this state it sets the only state possible after executing this one the ask state 03:57.080 --> 04:03.200 state the ask state struct is not declared yet but it will be the state where we ask the player for 04:03.200 --> 04:06.380 a number to guess in the next two lines. 04:06.410 --> 04:11.290 We use the rand package of go to generate a random number in the first line. 04:11.360 --> 04:18.050 We feed the random generator with in 64 type number returned by the current moment so we ensure a random 04:18.050 --> 04:20.000 feed in each execution. 04:20.000 --> 04:26.210 So if you put a constant number here the randomize it will also generate the same number to the rand 04:26.210 --> 04:31.700 dot in the end method returns an integer number between 0 and the specified number. 04:31.700 --> 04:38.960 So here we cover acceptance criteria to next a message asking for a number of re tries to set precedes 04:38.990 --> 04:46.130 the F empty dot f scan f method a powerful function where you can posit an IO dot reader which is the 04:46.130 --> 04:51.500 standard input of the console a format that is number and an interface to store the contents of the 04:51.500 --> 04:52.380 reader. 04:52.430 --> 04:55.890 In this case the re tries field of the context. 04:55.910 --> 05:00.700 Finally we return true to tell the engine that the game must continue. 05:00.890 --> 05:05.560 Let us see the ask state struct which we have used at the beginning of the function. 05:05.600 --> 05:12.320 So here's the ask state struct they ask state struct also implements the game state as you have probably 05:12.320 --> 05:13.560 guessed already. 05:13.670 --> 05:19.580 This state starts with a message for the player asking them to insert a new number in the next three 05:19.580 --> 05:20.180 lines. 05:20.180 --> 05:25.480 We create a local variable to store the contents of the number that the player will introduce. 05:25.490 --> 05:31.850 We use the F empty dot f scan f method again as we did in start state struct to capture the player's 05:31.850 --> 05:38.420 input and store it in the variable and then we have 1 retry less in our counter. 05:38.420 --> 05:43.660 So we have to subtract 1 to the number of is represented in the retry field. 05:43.730 --> 05:48.370 Then there are two checks one that checks if the user has entered the correct number. 05:48.440 --> 05:56.990 In which case the context field 1 is set to true and the next state is set to the finished state struct. 05:57.170 --> 06:03.080 The second check is controlling the number of retrials has not reached 0 in which case it won't let 06:03.080 --> 06:08.510 the player ask again for a number and it will send the player to the Finnish state struct directly. 06:08.600 --> 06:14.270 After all we have to tell the game engine again that the game must continue by returning true in the 06:14.330 --> 06:16.310 execute state method. 06:16.310 --> 06:19.430 Finally we have defined the finish date struct. 06:19.640 --> 06:21.890 It controls the exit status of the game. 06:21.980 --> 06:28.460 Checking the contents of the one field in the context object the finished state struct also implements 06:28.460 --> 06:32.650 the game state by having execute state method in its structure. 06:32.660 --> 06:38.200 The idea here is very simple if the player has won the Finnish state structure will print the message. 06:38.210 --> 06:40.220 Congrats you won. 06:40.220 --> 06:44.810 If the player has not won the Finnish state prints the message you lose. 06:44.810 --> 06:48.860 Remember that the zero value of the boolean variable is false. 06:48.980 --> 06:56.110 In this case the game can be considered finished so we return false to say that the game must not continue. 06:56.180 --> 06:58.690 We just need the main method to play our game. 06:58.700 --> 07:01.960 So we have our main method over here. 07:01.970 --> 07:04.220 Well yes it can't be simpler. 07:04.220 --> 07:10.250 The game must begin with the start method although it could be abstracted more outside in case the game 07:10.250 --> 07:12.400 needs more initialization in the future. 07:12.500 --> 07:14.780 But in our case it is fine. 07:14.780 --> 07:20.220 Then we create a context where we set the next state as pointer to the start variable. 07:20.270 --> 07:24.940 So the first state that will be executed in the game will be the start state. 07:25.130 --> 07:29.000 The last line of the main function has a lot of things just there. 07:29.000 --> 07:32.490 We create a loop without any statement inside it. 07:32.570 --> 07:36.700 As with any loop it keeps looping after the condition is not satisfied. 07:37.010 --> 07:41.210 The condition we are using is the return value of the game state structure. 07:41.210 --> 07:41.750 True. 07:41.780 --> 07:43.780 As soon as the game is not finished. 07:43.850 --> 07:50.470 So the idea is simple we execute the state in the context passing a pointer to the context to it. 07:50.690 --> 07:56.510 Each state returns true until the game has finished and the finished state struct will return false. 07:57.020 --> 08:03.530 So our for loop will keep looping waiting for a false condition sent by the finished state struct to 08:03.530 --> 08:05.390 end the application. 08:05.510 --> 08:08.240 Now save the file and navigate to the terminal. 08:09.080 --> 08:14.140 Now let's play once it asks to introduce a number say 5. 08:14.180 --> 08:16.170 Now let's introduce 8. 08:16.280 --> 08:18.770 Now the third one say 2. 08:18.920 --> 08:20.390 Are we 1. 08:20.420 --> 08:21.470 Let's do it again. 08:21.530 --> 08:32.210 So let's introduce first for next 3 7 9 and the last one say 2 we lost. 08:32.210 --> 08:34.510 We set the number of retrials to 4. 08:34.520 --> 08:38.810 Then we kept inserting numbers trying to guess the secret number. 08:38.810 --> 08:41.470 We entered 3 7 9 and 2. 08:41.540 --> 08:43.490 But it wasn't any of them. 08:43.490 --> 08:45.870 I don't even know what the correct number was. 08:46.040 --> 08:52.550 Let's fix this go to the definition of the finished state struct and change the line where it says you 08:52.550 --> 08:55.570 lose and replace it in the way I do. 08:55.860 --> 08:56.710 Fine. 08:56.900 --> 08:59.010 Now it will show the correct number. 08:59.010 --> 09:05.840 Let's play again before you move to the terminal save the file go run state DOT go. 09:06.110 --> 09:11.710 Let's give 3 6 2 and one. 09:11.710 --> 09:12.910 We again lose. 09:12.970 --> 09:15.380 And the correct number was 8. 09:15.520 --> 09:20.820 This time we make it a little harder by setting only three tries and we lost again. 09:20.920 --> 09:24.790 I entered 6 2 and one the correct number was 8. 09:24.800 --> 09:25.920 Let's play it again. 09:26.080 --> 09:35.230 5 3 4 5 6 8 we lose again. 09:35.340 --> 09:44.300 Let's give it a last try 9 6 14 3 6 and 1. 09:44.300 --> 09:45.050 Great. 09:45.230 --> 09:49.990 This time we lowered the difficulty allowing up to 9 tries and we won. 09:50.030 --> 09:54.110 We even had four more tries left but we guessed the number on the fifth try. 09:54.110 --> 10:01.290 After entering 6 14 3 and 6 the correct number was 1 which was my fifth try. 10:01.340 --> 10:07.370 Have you realized that we could have a winning and a lose state instead of printing the messages directly 10:07.370 --> 10:09.320 in the finished state struct. 10:09.320 --> 10:14.810 This way we could for example check some hypothetical scoreboard in the wind section to see if we have 10:14.810 --> 10:16.250 set a record. 10:16.290 --> 10:18.500 Let's refactor our game. 10:18.530 --> 10:22.430 First we need a win state and they lose state struct. 10:22.430 --> 10:27.870 So let's open the states dots go file which I've created in the same folder above. 10:27.890 --> 10:31.940 The main method I have added the wind state and the loop state. 10:31.940 --> 10:34.150 These two new states have nothing new. 10:34.220 --> 10:39.680 They contain the same messages that were previously in the finished state that by the way must be modified 10:39.680 --> 10:41.710 to use these new states. 10:41.710 --> 10:47.940 Let us modify the Finnish state now the Finnish state doesn't print anything. 10:47.940 --> 10:53.620 And instead delegates this to the next state in the chain the wind state structure. 10:53.850 --> 10:59.940 If the user has won and lose state struct if not remember that the game does not finish on the Finnish 10:59.940 --> 11:00.660 state struct. 11:00.660 --> 11:07.260 Now we must return true instead of false to notified to the engine that it must keep executing states 11:07.380 --> 11:08.650 in the chain. 11:08.820 --> 11:13.270 You must be thinking now that you can extend this game forever with new states. 11:13.290 --> 11:14.490 And it's true. 11:14.640 --> 11:20.820 The power of the state pattern is not only the capacity to create complex FSM but also the flexibility 11:20.820 --> 11:22.520 to improve it as much as you want. 11:22.620 --> 11:28.350 By adding new states and modifying some old states to point to the new ones without affecting the rest 11:28.350 --> 11:35.150 of the FSM in this video we have learned about the state design pattern in the next video. 11:35.200 --> 11:38.080 We will dive into mediator design pattern.