0

I have this code in Visual Basic that randomly changes wallpaper on the first boot of the day:

Dim objRandom As New System.Random(CType(System.DateTime.Now.Ticks Mod System.Int32.MaxValue, Integer))
    Sub Main()
        Dim WallpaperNumNew As Integer
        Dim WallpaperCurrent As Integer
        Dim WallpaperLastChgDate As Date
        Dim LoopNum As Integer
        On Error Resume Next 'if neither key exists, ignore error. They will get created at program end.
        WallpaperLastChgDate = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Nothing) 'get the date the wallpaper was last changed
        WallpaperCurrent = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperNumber", Nothing) 'get current wallpaper number
        On Error GoTo 0
        If WallpaperLastChgDate = Today() Then Exit Sub 'prevent changing wallpaper on every reboot during the day
        Do
            WallpaperNumNew = GetRandomNumber(1, 7)
            LoopNum = LoopNum + 1
            If LoopNum > 20 Then Exit Do 'prevent infinite loop
        Loop While WallpaperNumNew = WallpaperCurrent 'if current and new are the same, loop until they are not
        Select Case WallpaperNumNew
            Case 1
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper1.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 2
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper2.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 3
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper3.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 4
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper4.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 5
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper5.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 6
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper6.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 7
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper7.jpg", "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg",
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case Else
                Exit Sub 'do nothing
        End Select
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperNumber", WallpaperNumNew) 'write new wallpaper number to registry
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Today()) 'write new wallpaper change date to registry
    End Sub
    Public Function GetRandomNumber(Optional ByVal Low As Integer = 1, Optional ByVal High As Integer = 100) As Integer
        ' Returns a random number between the optional Low and High parameters
        ' from: http://www.developerfusion.com/code/3940/random-numbers-that-work/
        Return objRandom.Next(Low, High + 1)
    End Function

The program is set to run via Task Manager and works great, but since it is random, I often get the same wallpaper two or three days later. Can anyone think of a way of randomly cycling though the seven available wallpapers so that there are no duplicates in the series?

I'm not looking for actual code but just some way of tracking what wallpapers have previously been chosen and then eliminating those from the available pool until all seven have been selected. (Yeah, the last would not be random.)

I have written another program that can select a specific wallpaper based on the day of the week, but then I'd get the same wallpaper on each day, (i.e. every Monday would be the same wallpaper), which would be kind of boring.

Any ideas would be welcome. Thanks

Edit: I think I may have thought of a solution. The first time the code runs it generates a list of seven random numbers of values 1 - 7, say: 4, 7, 3, 1, 5, 2, 6 and stores them in a registry setting as: 4731526. Then each time the code runs (once a day) it retrieves another value stored in the registry that indicate what cycle number it's on, uses that position number from the random string, and then increments the cycle number. So in my example above, on the first day it uses wallpaper 4, then 7, then 3, etc. When it gets to 6 (the 7th value), it generates a new set of random numbers, stores it in the registry and sets the cycle number back to one, and the cycle start over with a new, different random string.

If this works, I'll post it as an answer as well as the code.

EDIT 2: I believe I have the code to accomplish what I'm after. I have run it once, and it has generated a seven-digit random number. I just need to wait until day eight to see if the code generates a new list of randomly arranged seven digits.
Mark Buffalo
  • 766
  • 1
  • 10
  • 25
BillDOe
  • 101
  • 7

3 Answers3

1

This should work for you:

Sub Main()
    Dim WallpaperLastChgDate = Today()
    Dim WallpaperCurrent = -1
    On Error Resume Next 'if neither key exists, ignore error. They will get created at program end.
    WallpaperLastChgDate = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Nothing) 'get the date the wallpaper was last changed
    WallpaperCurrent = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperNumber", Nothing) 'get current wallpaper number
    On Error GoTo 0
    If WallpaperLastChgDate = Today() Then Exit Sub 'prevent changing wallpaper on every reboot during the day
    WallpaperCurrent += 1
    Dim objRandom As New System.Random(0)
    Dim Images = { "Wallpaper1.jpg", "Wallpaper2.jpg", "Wallpaper3.jpg", "Wallpaper4.jpg", "Wallpaper5.jpg", "Wallpaper6.jpg", "Wallpaper7.jpg" }
    Dim Shuffled = Enumerable.Range(0, 1000).SelectMany(Function (n) Images.OrderBy(Function (i) objRandom.NextDouble())).ToArray()
    My.Computer.FileSystem.CopyFile(Shuffled(WallpaperCurrent), "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg", FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
    My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperNumber", WallpaperCurrent) 'write new wallpaper number to registry
    My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Today()) 'write new wallpaper change date to registry
End Sub

The key here is to avoid all that junk about true random numbers. What you need is a good shuffle, but an entirely predicable stream of numbers. By starting with New System.Random(0) you ensure you will compute the same numbers each time.

So then I just computed an array of 1000 x 7 images with each series of 7 images shuffled. Then I'm just keeping track of what index you're at each day, and increment to get the next image. So my approach will work for about 19.1 years.

This still has the issue that the last image of the run of seven could be the first of the next run. It wouldn't be hard to use the .Zip operator to prune out these duplicates.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172
  • 1
    I'll have to give this a try. One shortcoming I realized my approach has is that it won't work if I have > 9 wallpapers. It looks like this will work with has many wallpapers has one has. – BillDOe Oct 05 '15 at 05:19
0

Your requirements are provably impossible. If you have seven wallpapers, and you require that in any seven days no wallpaper appears more than once, then obviously you must repeat the same seven-wallpaper sequence ad infinitum.

Proof: After any six days, the only available wallpaper is the one that has not appeared in the previous six days -- that is, the one that appeared exactly seven days ago.

Perhaps I have misunderstood your requirements. If so, please put me right.

TonyK
  • 16,761
  • 4
  • 37
  • 72
  • You're right that the last wallpaper will always be the one not previously chosen, as I note in my original question. Here's an example of what I'm trying to accomplish: Series 1: 1, 4, 2, 7, 3, 5, 6; series 2: 4, 1, 5, 6, 7, 2, 3; series 3: 7, 1, 3, 2, 5, 4, 6; etc. I don't want to repeat the same series again and again; I could just do a Select Case on Weekday in that case. – BillDOe Sep 20 '15 at 22:32
  • But then you get wallpaper 7 on day twelve and again, just three days later, on day fifteen. Do you see the problem now? – TonyK Sep 20 '15 at 23:42
  • Of course wallpaper 7 is going to appear in each series of seven. I just want it so that in one set it is, say, 3rd, then 4th, then 7th, then 2nd, etc. – BillDOe Sep 21 '15 at 00:32
0

I have my solution and have tested it. I create a 7-digit random string and store a cycle number in the registry (among other things). When my program runs, it gets the cycle number and random string from the registry and then uses the MID function to get the appropriate wallpaper number, e.g. MID(String, CycleNumber, 1). I then use a standard Select Case statement to copy the desired .jpg file to Window's TranscodedWallpaper file. If I wanted to get rid of the descriptive file names (e.g. Frontyard_Liquidamber.jpg) and change them all to Wallpaper1.jpg, Wallpaper2.jpg, etc., I could get rid of the Select Case statement and use PathName & Wallpaper Number & ".jpg". Here's the code:

Module Module1
        Sub Main()
        Dim WallpaperNumberNew As Integer
        Dim WallpaperNumberNewString As String
        Dim WallpaperLastChgDate As Date
        Dim WallpaperRandomList As String
        Dim WallpaperCycleNumber As Integer
        Dim CopyToLocation As String
        Dim NumberOfWallpapers As Integer
        Dim LoopNum As Integer
        NumberOfWallpapers = 8
        If My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperRandomList", Nothing) Is Nothing Then
            WallpaperRandomList = GetRandomList(NumberOfWallpapers)
            My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperRandomList", WallpaperRandomList)
            My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperCycleNumber", 1)
        End If
        WallpaperRandomList = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperRandomList", Nothing)
        WallpaperCycleNumber = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperCycleNumber", Nothing)
        WallpaperLastChgDate = My.Computer.Registry.GetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Nothing)
        If WallpaperLastChgDate = Today() Then Exit Sub 'prevent changing wallpaper on every reboot during the day
        If WallpaperCycleNumber = NumberOfWallpapers + 1 Then
            WallpaperNumberNewString = Mid(WallpaperRandomList, WallpaperCycleNumber - 1, 1)
            WallpaperCycleNumber = 1
            Do
                WallpaperRandomList = GetRandomList(NumberOfWallpapers)
                LoopNum = LoopNum + 1
                If LoopNum > 20 Then Exit Do
            Loop While Left(WallpaperRandomList, 1) = WallpaperNumberNewString 'prevent first digit of new string from repeating last digit of old string
            My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperRandomList", WallpaperRandomList)
        End If
        WallpaperNumberNewString = Mid(WallpaperRandomList, WallpaperCycleNumber, 1)
        WallpaperNumberNew = CInt(WallpaperNumberNewString)
        CopyToLocation = "C:\Users[username]\AppData\Roaming\Microsoft\Windows\Themes\TranscodedWallpaper.jpg"
        Select Case WallpaperNumberNew
            Case 1
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper1.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 2
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper2.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 3
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper3.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 4
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper4.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 5
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper5.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 6
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper6.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 7
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper7.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case 8
                My.Computer.FileSystem.CopyFile("C:\Windows\Web\WallPaper\MyWallPaper\JPEGs\Wallpaper8.jpg", CopyToLocation,
                FileIO.UIOption.OnlyErrorDialogs, FileIO.UICancelOption.DoNothing)
            Case Else
                Exit Sub 'do nothing
        End Select
        WallpaperCycleNumber = WallpaperCycleNumber + 1
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperCycleNumber", WallpaperCycleNumber) 'write cycle number to registry
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperLastUpdate", Today()) 'write new wallpaper change date to registry
        My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Control Panel\Desktop", "WallpaperNumber", WallpaperNumberNew)
    End Sub
    Public Function GetRandomList(Optional ByVal High As Integer = 100) As String
        Dim StringDigit(High) As Integer
        Dim NewString As String
        Dim RndArray As Integer
        Dim temp As Integer
        For i = 1 To High
            StringDigit(i) = i
        Next i
        Randomize() 'intialize random number generator
        For i = 1 To High
            RndArray = Int((UBound(StringDigit) * Rnd() + 1)) 'generate random number and store as variable RndArray
            temp = StringDigit(i) 'temporarily store array element i to a variable called temp
            StringDigit(i) = StringDigit(RndArray) 'set array element i equal to random array element StringDigit
            StringDigit(RndArray) = temp 'set array element StringDigit to old value of array element i stored as temp
        Next i
        NewString = Nothing 'initialize variable NewString
        For i = 1 To High
            NewString = NewString & StringDigit(i) 'convert array into string NewString
        Next i
        Return NewString
    End Function
End Module


One nice side-effect to this is that it copies your jpeg, presumably with minimal compression, directly to Window's TranscodedWallpaper.jpg file, which sidesteps the aggressive compression Windows applies to your BMP file when it converts it into your chosen wallpaper. While investigating possible solutions to my issue, I discovered this was an annoyance to many users.
BillDOe
  • 101
  • 7