HoGo

Welcome to the HoGo Fitness Academy, or so it says on the plaque. What is known about this academy is that there are 52 students, and they belong to one of four houses. They are the Clubs, Hearts, Spades and Diamonds.

Each student has an invisible smart card printed on the back of their hand giving them access to their house.  Each house teaches differently from passive to aggressive.

After every semester it’s time for the students for a Home Going for a period with the Unfits (UFs), where they are not allowed to share HoGo secrets. The students Board the Puffing Billy, which has four carriages, one for each house, in the order of Aces first, followed by the number cards and the Kings last.

You, the Academy Keeper, supervises the boarding of the train with 28 students already queued up but shambolically. The other students are waiting in the Next room.

The queue must be arranged in order of Aces to Kings, but also in alternating house colours, to avoid favouritism, to allow the students to board the train. If a student emerges from the Next room and is next in line on their carriage, they may board the train without queueing up first.

This procedure has not changed since ancient times and is meant to bring good fortune and ward off evil spirits.

Each semester four students graduate, and four new students are taken on. They are interviewed and sorted into their houses by the four House Masters wearing their old handed down hats emblazened with their ornate house symbols.

I hope you will manage to get all the students on to the train. Good luck!

Here is the graphical arrangement of the academy.

HoGo Start Page

 

Option Explicit

Sub MoveCards()

'This is the Move_Cards module

Dim strCard As String
Dim intRow As Integer
Dim intCol As Integer
Dim intCardOne As Integer
Dim intCardTwo As Integer
Dim intDiff As Integer
Dim intCardColOne As Integer
Dim intCardColTwo As Integer
Dim intLoop As Integer
Dim intCards As Integer
Dim intTrainCard As Integer

    'A card on the train is selected

    If [J16] <> "" Then

        MsgBox "A train card is to be put back in the queue"

        'Check the spot below is empty for the card

        intRow = Selection.Row
        intCol = Selection.Column

        If Cells(intRow + 1, intCol) <> "" Then

            MsgBox "The spot below this is not empty"
            Exit Sub

        End If

        'Check the card fits below the chosen spot
        'First get the on the spot card number

        intCardTwo = FindCardPosition(Cells(intRow, intCol))

        'Now get the difference to another suit viz intDiffOne and intDiffTwo

        FindDiffs (intCardTwo)

        'Compare the train card with the selected card

        If [J16] = intCardTwo + intDiffOne - 1 Or [J16] = intCardTwo + intDiffTwo - 1 Then

            Cells(intRow + 1, intCol) = Cells(2, [L16])
            Cells(2, [L16]) = varSuitsUnsorted([J16] - 1)
            [J16] = ""
            [J6] = ""

        End If

        Exit Sub

    End If

    If Not Intersect(Selection, Range("B2:E2")) Is Nothing Then

        [L16] = ""
        intTrainCard = FindCardPosition(Selection)

        If intTrainCard = -1 Then Exit Sub

        [L16] = Selection.Column
        If Mid(Selection, 2, 2) <> "A" And Mid(Selection, 2, 2) <> "2" And _
        Mid(Selection < 2, 2) <> "Q" Then MsgBox "OK"

        [J16] = FindCardPosition(Selection)
        [J6] = Cells(2, [L16])
        Exit Sub

    End If

    'Check for K to an empty column

    If Right([J6], 1) = "K" Then

        If Selection <> "" Or Selection.Row <> 3 Then

            MsgBox "King can't go there"
            [J6] = ""
            Exit Sub

        End If

    End If

    If Selection = "" And [J6] = "" Then

        MsgBox "Need to select a card"
        [J6] = ""
        Exit Sub

    End If

    strCard = Selection
    intRow = Selection.Row
    intCol = Selection.Column

'    Check if more cards below and they cascade correctly

    If Cells(intRow + 1, intCol) <> "" And Selection.Address <> "$G$2" Then

        intCards = 1

        For intLoop = intRow To 30

            'Get number of this card
            intCardColOne = FindCardPosition(Cells(intLoop, intCol))

            If Cells(intLoop + 1, intCol) = "" Then

                Exit For

            Else

                'Get number of next card
                intCardColTwo = FindCardPosition(Cells(intLoop + 1, intCol))
                FindDiffs (intCardColTwo)

                'Compare this next card with the one above
                If intCardColOne = intCardColTwo + intDiffOne + 1 Or intCardColOne = intCardColTwo + intDiffTwo + 1 Then
                    'MsgBox "OK"
                Else
                    MsgBox "Not cascading"
                    [J6] = ""
                    Exit Sub
                End If

            End If

            intCards = intCards + 1

        Next intLoop

    End If

    'If this is the first card then record it and exit

    If [J6] = "" Then

        [J6] = strCard

        ApplyColor ("J6")

        [K14] = intRow
        [L14] = intCol

        Exit Sub

    End If

'We're at the second card

'Check there is a card above

    If Cells(intRow, intCol) = "" And intRow <> 3 Then
        MsgBox "Need to select a cell with a card"
        Exit Sub
    End If

    'Need to check it's one less in the oppposite color suit
    'Get the first card

    intCardOne = FindCardPosition([J6])
    If intCardOne = -1 Then

        MsgBox "Can't find this card"
    Exit Sub

    End If

    'Might not need this
    [J14] = intCardOne

    If Selection <> "" Then

        intCardTwo = FindCardPosition(Selection)
        'Might not need this
        [J15] = intCardTwo

    End If

    'Record position of card 2
    [K15] = intRow
    [L15] = intCol

    'Exit if card two is the same color as card one

    If Selection <> "" Then

        If [J6].Font.Color = Selection.Font.Color Then

        MsgBox "Can't be the same color"
        [J6] = ""
        Exit Sub

        End If
    End If

    'Now get the equivalent position in the opposite color suits

    If Selection <> "" Then FindDiffs (intCardTwo)

    'Is the card one less in the other color suit?

    intDiff = 0

     'intDiff is set for the presence of the King


    If intCardOne = intCardTwo + intDiffOne - 1 Or _
        intCardOne = intCardTwo + intDiffTwo - 1 Or Selection = "" Then

        Application.ScreenUpdating = False

        If Selection.Row = 3 And Right([J6], 1) = "K" Then intDiff = 0 Else intDiff = 1

        If Selection.Row = 3 And Selection = "" And Right([J6], 1) <> "K" Then
            MsgBox "Only king can go there"
            Exit Sub
        End If

        If Cells([K14], [L14]).Address <> "$G$2" Then
            '[K16] = intDiff
            Range(Cells([K14], [L14]), Cells([K14] + 12, [L14])).Copy
            Cells(([K15] + intDiff), [L15]).PasteSpecial Paste:=xlPasteValues
            Application.CutCopyMode = False
            Range(Cells([K14], [L14]), Cells([K14] + 12, [L14])).ClearContents

            For intLoop = [K15] To [K15] + 12
                ApplyColor Cells(intLoop, [L15]).Address
                Next intLoop
                [K3].Select

        Else

            Cells(intRow + intDiff, intCol) = Cells([K14], [L14])

        End If

        ApplyColor Cells(intRow + intDiff, intCol).Address

        'If it's the Next cell then advance the pointer in the array

        If Cells([K14], [L14]).Address = "$G$2" Then

            varSuits(intNextCard) = varSuits(intCard)
            intCard = intCard + 1
    NextCard

    Else
   
        Cells([K14], [L14]) = ""

    End If

    Else

    MsgBox "The card to move is not one less"

    End If

    [J6] = ""
    Application.ScreenUpdating = True

End Sub

 

Sometimes the selection needs to be cancelled and that's what the (c) button does.

 

Option Explicit

Sub CancelSelection()

    'This is the Cancel_Selection module

    procFinished
    [J6] = ""
    [G2].Select

End Sub

 

The procFinished procedure checks that all the cards are lined up in columns B to E and the carriage cards are all of the same value.
If that is so, click the (c) button and they will board the train automatically.

Ready to board

 

Option Explicit

Sub procFinished()

'This is the Finished module

Dim intRow As Integer
Dim intCol As Integer
Dim intFinished As Integer
Dim intLoop As Double
Dim intHouseCol As Integer

    For intRow = 2 To 30
        For intCol = 3 To 5

            If Right(Cells(intRow, intCol), 1) <> Right(Cells(intRow, intCol - 1), 1) Then

                'Exit if the cards are not lined up properly
                Exit Sub

            End If

        If intFinished < 1 And Cells(intRow, intCol) = "" Then

            intFinished = intRow - 1

        End If

        Next intCol
    Next intRow

    'All ok so march the cards into the carriages

    For intRow = intFinished To 3 Step -1
        For intCol = 2 To 5

            intHouseCol = InStr(1, Left([B2], 1) + Left([C2], 1) _
            + Left([D2], 1) + Left([E2], 1), Left(Cells(intRow, intCol), 1)) + 1

            Cells(2, intHouseCol) = Cells(intRow, intCol)
            Cells(intRow, intCol) = ""

            Dim EndTime As Double
            EndTime = Timer + 0.05

            Do While Timer < EndTime
                DoEvents 'Keeps Windows responsive
            Loop

        Next intCol
    Next intRow

End Sub