PLAYING GAMES WITH HUBIVUE
Took me a little more than a full day to create this 2-player Tic Tac Toe simulator. I wanted to showcase the ever-growing toolbox of hubiVue features – like conditional style overrides – while also making maximum use of Rule Machine (see “Actions”, below), Hub Variables and Maker API behind the scenes, on the Hubitat side.
THE DESIGN
The game board is an ultraTile™ whose grid comes from a separate 4-column Dash. That dashboard is populated with the 9 game board Tiles, outlined in white, plus two borderless Tiles serving as game controls. Setup was greatly aided by the Copy-Paste feature in hubiVue; after perfecting the first Tile, the other eight required only minor tweaks. I went from design to a usable layout in less than 10 minutes!
GAME PLAY
Clicking RESET clears the board and it becomes X’s turn to play. Each subsequent “Tap” event silently executes an “Open URL” (with its pop-up notification suppressed). HubiVue is passing via Maker API the “Device Command” for a Hub Variable Connector called “Move” using a URL of the form:
[HE_IP]/apps/api/#/devices/[Dev_ID]/[Cmd]/[Val]?access_token=xxx
which sets its value (e.g. Val == “B2”) according to which tile was tapped.
HUB LOGIC
On the receiving end, Rule Machine triggers its Tic Tac Toe rule whenever the value of “Move” changes, then processes the game board. The values submitted thus far were “B2” for X, “A3” for O, “B3”, “A1” and finally “C2” again for Player X. The red X’s and blue O’s are simply icons turned on by conditional overrides; the actual underlying hub var values are hidden.
RM MAGIC
RM does all the heavy lifting here. As game play progresses, it keeps track of alternating turns, and updates an HVC called “Game Status” for display inside the Device Tile titled “Tic-Tac-Toe”. That tile uses an Attribute Override in lieu of a fixed Middle Label, allowing live text like “O’s turn” or “X won!” to appear there.
WE HAVE A WINNER
Game play continues until RM – through a series of conditionals (see “Actions” below) – determines that three-in-a-row has occurred, whereupon it declares the winner. To highlight the winning squares, RM appends a pre-determined letter (“D” through “K” representing all 8 possible patterns) to the HVC linked to the game squares, causing Conditional Overrides to alter the appearance of those three Tiles.
For example, in this completed game, since the winning X’s happen to line up along the middle row (“A2”, “B2”, “C2”), RM appends the letter “E”. In turn, the styling of those three Tiles changes to include a custom border color and glow effect, both triggered by the condition “Variable contains E”.
PLEASE SHARE
Grant, you are welcome to share this pet project with any audience you like, with or without attribution. It’s my way of thanking you for creating such an awesome dashboard app. HubiVue provides users with the most oft-requested features, without the steep learning curve. Its ease-of-use and approachable interface have set the bar high. Kudos!!
BEHIND THE SCENES
I spent the greater part of the day crafting and perfecting this rule in Rule Machine. This exercise wound up being a much-needed foray into the finer points of RM generally, UX design, and game logic in particular.
Actions for TicTacToe
IF (Variable TTT_Move(wait) ≠ 'wait'(F) [FALSE]) THEN
IF (Variable TTT_Move(wait) = 'reset'(F) [FALSE]) THEN
// RESET GAME BOARD
Set TTT_Board to 'A-1B-1C-1A-2B-2C-2A-3B-3C-3'
Set A1 to '-'
•••
Set C3 to '-'
Set Positions to '---------'
Set Previous to '---------'
Set Player to 'X'
Set Move to ' '
Set TTT_Move to 'wait'
Set TTT_Status to 'X starts'
Set Win to 'N'
Set Winning to '---'
Exit Rule
END-IF
IF (Variable Win(N) = 'N'(T) [TRUE]) THEN
IF (NOT Variable TTT_Board(A-1B-1C-1A-2B-2C-2A-3B-3C-3) *contains* TTT_Move(wait)(T) [TRUE]) THEN
Set TTT_Status to '*Invalid*'
Set TTT_Status to '%Player%'s turn(X's turn)' --> delayed: 0:00:02
ELSE
// PROCESS PLAYER'S MOVE
Set Move to '%TTT_Move%(wait)'
Remove '-' from Move
Replace '%TTT_Move%(wait)' from TTT_Board(A-1B-1C-1A-2B-2C-2A-3B-3C-3) with '%Move%%Player%( X)'
// UPDATE GAME BOARD
IF (Variable Move( ) = 'A1' FALSE) Set A1 to '%Player%(X)'
•••
IF (Variable Move( ) = 'C3' FALSE) Set C3 to '%Player%(X)'
Set Positions to '%A1%%B1%%C1%%A2%%B2%%C2%%A3%%B3%%C3%(---------)'
IF (Variable Positions(---------) ≠ Previous(---------)(F) [FALSE]) THEN
// CHECK FOR WIN OR DRAW
Set Winner to '%Player%%Player%%Player%(XXX)'
Set Winning to '%A1%%B1%%C1%(---)'
IF (Variable Winner(XXX) = Winning(---) FALSE) Set Win to 'D' Set Winning to '%A2%%B2%%C2%(---)'
•••
Set Winning to '%A3%%B2%%C1%(---)'
IF (Variable Winner(XXX) = Winning(---) FALSE) Set Win to 'K'
IF (NOT Variable Positions(---------) *contains* '-' FALSE) Set Win to 'DEF'
IF (Variable Win(N) ≠ 'N'(T) [TRUE]) THEN
Set TTT_Board to '%TTT_Board%%Win%(A-1B-1C-1A-2B-2C-2A-3B-3C-3N)'
Set TTT_Status to '%Player% won!(X won!)'
IF (Variable Win(N) = 'DEF' FALSE) Set TTT_Status to '❰❰Draw❱❱'
Exit Rule
// END OF GAME
END-IF
IF (Variable Player(X) = 'O'(F) [FALSE]) THEN
// OTHER PLAYER'S TURN
Set Player to 'X'
ELSE
Set Player to 'O'
END-IF
Set TTT_Status to '%Player%'s turn(X's turn)'
Set Previous to '%Positions%(---------)'
END-IF
// END OF TURN
END-IF
Set TTT_Move to 'wait'
ELSE
// WAIT FOR VALID MOVE OR RESET
END-IF
END-IF
STRETCH GOALS
I’m thinking about adding a “Play CPU” toggle to this game board, along with a few extra lines of “Tic Tac Toe AI” code in Rule Machine that will permit the hub to act as robo-Player O.