1+ /* ********************************************************************
2+ Scott Peters
3+ Random Walk
4+ https://advancedsqlpuzzles.com
5+ Last Updated: 07/25/2022
6+
7+ This script is written in SQL Server's T-SQL
8+
9+ ---------------------------------------------------------------------
10+
11+ The following solves a random walk for the following problem:
12+
13+ You are the dinner host of a weekly gathering of 8 friends (including yourself).
14+ You want to determine who hosts the next dinner party using the following scheme:
15+
16+ After dinner, the guests sit around a round table. You (the current host) flip a fair coin.
17+ If it comes up heads, you pass it to the person on your right, and if it comes up tails, you pass it to person on your left.
18+ The person who receives the coin repeats the procedure, flipping it and passing it right or left, depending on the outcome of the flip.
19+ This process keeps going until all but one dinner guest has held the coin.
20+ The last member who has not yet touched the coin is then declared the winner and must host the next dinner party.
21+
22+ **********************************************************************/
23+ SET NOCOUNT ON ;
24+
25+ -- -------------------
26+ -- -------------------
27+ -- Tables used in script
28+ DROP TABLE IF EXISTS #Numbers;
29+ DROP TABLE IF EXISTS #ParticipantsASC;
30+ DROP TABLE IF EXISTS #ParticipantsDESC;
31+ DROP TABLE IF EXISTS #Participants;
32+ DROP TABLE IF EXISTS #CoinFlipResults;
33+ DROP TABLE IF EXISTS #WinnerResults;
34+ DROP TABLE IF EXISTS #WinnerResultsHistory;
35+ GO
36+
37+ -- -------------------
38+ -- -------------------
39+ -- Create #WinnerResultsHistory table
40+ CREATE TABLE #WinnerResultsHistory
41+ (
42+ Iteration INTEGER IDENTITY (1 ,1 ) PRIMARY KEY ,
43+ Participant INTEGER NOT NULL ,
44+ CoinFlips INTEGER NOT NULL
45+ );
46+ GO
47+
48+ -- ----------------------
49+ -- ----------------------
50+ -- ----------------------
51+ -- Create #Numbers table
52+ CREATE TABLE #Numbers
53+ (
54+ Number INTEGER IDENTITY (0 ,1 ) PRIMARY KEY , -- Begin at 0 and increate by 1
55+ InsertDate DATETIME NOT NULL
56+ );
57+ GO
58+
59+ INSERT INTO #Numbers(InsertDate) VALUES (GETDATE ());
60+ GO 300
61+
62+ -- ----------------------
63+ -- ----------------------
64+ -- ----------------------
65+ -- Create #ParticipantsASC table
66+ CREATE TABLE #ParticipantsASC
67+ (
68+ CoinFlipSum INTEGER IDENTITY (0 ,1 ) PRIMARY KEY , -- Begin at 0 and increase by 1
69+ Participant INTEGER
70+ );
71+ GO
72+
73+ -- Create ###ParticipantsDESC table
74+ CREATE TABLE #ParticipantsDESC
75+ (
76+ CoinFlipSum INTEGER IDENTITY (- 1 ,- 1 ) PRIMARY KEY , -- Begin at -1 and increate by -1
77+ Participant INTEGER
78+ );
79+ GO
80+
81+ -- Create #Participants table
82+ CREATE TABLE #Participants
83+ (
84+ CoinFlipSum INTEGER NOT NULL ,
85+ Participant INTEGER NOT NULL
86+ );
87+ GO
88+
89+ -- ----------------------
90+ -- ----------------------
91+ -- ----------------------
92+ -- Create and populate the #Participants table
93+ -- For simplicity, I create seperate sequences and tables
94+ DROP SEQUENCE IF EXISTS dbo .MySequenceASC ;
95+ DROP SEQUENCE IF EXISTS dbo .MySequenceDESC ;
96+ GO
97+
98+ -- Start with 0, increment by 1
99+ CREATE SEQUENCE dbo .MySequenceASC AS INTEGER
100+ START WITH 0
101+ INCREMENT BY 1
102+ MINVALUE 0
103+ MAXVALUE 7 -- ---------------Set to number of participants!
104+ CYCLE;
105+ GO
106+
107+ -- Start with 7, increment by -1
108+ CREATE SEQUENCE dbo .MySequenceDESC AS INTEGER
109+ START WITH 7
110+ INCREMENT BY - 1
111+ MINVALUE 0
112+ MAXVALUE 7 -- ---------------Set to number of participants!
113+ CYCLE;
114+ GO
115+
116+ INSERT INTO #ParticipantsASC (Participant)
117+ SELECT (NEXT VALUE FOR dbo .MySequenceASC ) AS Participant;
118+ GO 300
119+
120+ INSERT INTO #ParticipantsDESC (Participant)
121+ SELECT (NEXT VALUE FOR dbo .MySequenceDESC ) AS Participant;
122+ GO 300
123+
124+ INSERT INTO #Participants (CoinFlipSum, Participant)
125+ SELECT CoinFlipSum, Participant FROM #ParticipantsASC
126+ UNION ALL
127+ SELECT CoinFlipSum, Participant FROM #ParticipantsDESC;
128+ GO
129+
130+ -- ----------------------
131+ -- ----------------------
132+ -- ----------------------
133+ -- Perform an evaluation of the #Participants and #Numbers table
134+ -- Ensure you have enough records in the #Participants and #Numbers tables
135+ IF ((SELECT COUNT (* ) FROM #Participants) < (SELECT COUNT (* ) FROM #Numbers))
136+ BEGIN
137+ PRINT (' #Participants record count is less than #Numbers' )
138+ RETURN ;
139+ END ;
140+ GO
141+ -- ----------------------
142+ -- ----------------------
143+ -- ----------------------
144+ -- Create table #CoinFlipResults
145+ CREATE TABLE #CoinFlipResults
146+ (
147+ StepNumber INTEGER PRIMARY KEY ,
148+ WindowSum INTEGER
149+ );
150+ GO
151+
152+ -- ----------------------
153+ -- ----------------------
154+ -- ----------------------
155+ -- Create table #WinnerResults
156+ CREATE TABLE #WinnerResults
157+ (
158+ Participant INTEGER PRIMARY KEY ,
159+ StepNumberFirstTouched INTEGER
160+ );
161+ GO
162+
163+ -- ----------------------
164+ -- ----------------------
165+ -- ----------------------
166+ -- Set the number of iterations
167+ DECLARE @Iterations INTEGER = 1000 ;
168+
169+ -- ----------------------
170+ -- ----------------------
171+ -- ----------------------
172+ -- Perform the random walk
173+ WHILE @Iterations >= 1
174+ BEGIN
175+
176+ SET @Iterations = @Iterations - 1 ;
177+
178+ TRUNCATE TABLE #CoinFlipResults;
179+ TRUNCATE TABLE #WinnerResults;
180+
181+ -- ----------------------
182+ -- ----------------------
183+ -- ----------------------
184+ -- Insert into #CoinFlipResults table
185+ ;WITH cte_RandomNumber AS
186+ (
187+ SELECT Number AS StepNumber
188+ ,ABS (CHECKSUM (NEWID ()) % 2 ) + 1 AS RandomNumber
189+ FROM #Numbers
190+ WHERE Number > 0
191+ ),
192+ cte_Pass AS
193+ (
194+ SELECT StepNumber
195+ ,(CASE RandomNumber WHEN 1 THEN - 1 WHEN 2 THEN 1 END ) AS PassDetermination
196+ FROM cte_RandomNumber
197+ )
198+ INSERT INTO #CoinFlipResults
199+ SELECT StepNumber
200+ ,SUM (PassDetermination) OVER (ORDER BY StepNumber) AS WindowSum
201+ FROM cte_Pass
202+ ORDER BY StepNumber;
203+
204+ -- ----------------------
205+ -- ----------------------
206+ -- ----------------------
207+ -- Insert into #WinnerResults table
208+ WITH cte_ResultsView AS
209+ (
210+ SELECT A.* , ' ----' AS ID, B.*
211+ FROM #CoinFlipResults a LEFT OUTER JOIN
212+ #Participants b on a .WindowSum = b .CoinFlipSum
213+ )
214+ INSERT INTO #WinnerResults
215+ SELECT Participant,
216+ MIN (StepNumber) AS StepNumberFirstTouched
217+ FROM cte_ResultsView
218+ GROUP BY Participant
219+ ORDER BY 2 DESC ;
220+
221+ -- ----------------------
222+ -- ----------------------
223+ -- ----------------------
224+ -- Insert into #WinnerResultsHistory table
225+ INSERT INTO #WinnerResultsHistory (Participant, CoinFlips)
226+ SELECT
227+ (SELECT TOP 1 Participant FROM #WinnerResults WHERE Participant <> 0 ORDER BY StepNumberFirstTouched DESC ),
228+ (SELECT TOP 1
229+ StepNumberFirstTouched
230+ FROM #WinnerResults
231+ WHERE StepNumberFirstTouched < (SELECT MAX (StepNumberFirstTouched) FROM #WinnerResults)
232+ ORDER BY StepNumberFirstTouched DESC );
233+
234+ END -- END LOOP
235+ GO
236+
237+ -- ----------------------
238+ -- ----------------------
239+ -- ----------------------
240+ -- Display summary statistics of the results
241+ SELECT Participant,
242+ COUNT (* ) AS Count ,
243+ MIN (CoinFlips) AS Min ,
244+ MAX (CoinFlips) AS Max ,
245+ AVG (CoinFlips) AS Avg ,
246+ MAX (CoinFlips) - MIN (CoinFlips) AS Range ,
247+ STDEV (CoinFlips) AS StandardDeviation
248+ FROM #WinnerResultsHistory
249+ GROUP BY Participant
250+ UNION
251+ SELECT 99999 AS Participant,
252+ COUNT (* ) AS Count ,
253+ MIN (CoinFlips) AS Min ,
254+ MAX (CoinFlips) AS Max ,
255+ AVG (CoinFlips) AS Avg ,
256+ MAX (CoinFlips) - MIN (CoinFlips) AS Range ,
257+ STDEV (CoinFlips) AS StandardDeviation
258+ FROM #WinnerResultsHistory;
259+ GO
0 commit comments