Canyon Escape - a Power Automate Game
Tags: powerplatform, powerautomate, gamedev, lowcode
Published: 2023-09-25 06:54:24

Welcome to Canyon Escape, you are an intrepid explorer in the model of Indian Jones, while exploring the deepest jungle in Peru you stumble into a canyon. With no way back you trek through, hoping to find an escape, and maybe a lost treasure or two,

![game video](https://i.imgur.com/6n3qBDJ.gif)

> Want to play, just 
> email: Canyon_escape@outlook.com
> subject: canyonEscape _(case sensitive)_

_Please note this is running off a dev tenant and will be deleted soon. Additionally the free Outlook account may get banned for spam if over used, so sorry if it stops working. Also this is an outlook trigger so occasionally can take 5 minutes + to get response_

---

In case you didn't know, I like to set myself weird challenges. I find the best way to learn is to do something challenging. 
Unfortunately Power Platform work is enterprise focus, so less variation than I hope for in my day job, that's where random self challenges come in. I've been wanting to make a Power Automate game for a while, but couldn't quite think of something, then I read an interesting article on a game called [Zork](https://en.wikipedia.org/wiki/Zork). It was a text-based adventure game created in the 70s. Though it was before my time, it then reminded me of [Pirate Island](https://en.wikipedia.org/wiki/Pirate_Adventure), a BBC Micro game I did play.

![zork](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0lp7n7hlkd14cyxymvkg.png)

![pirate island](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qwjmnwqxqok5jrce74wb.png)

So my idea is to make a kind of hybrid Zork / Pirate Island inspired text based Power Automate game.

The challenges/areas of game I needed to decide on were:

1. Interface/UI
2. Design
3. Gameplay
4. Setup
5. The Flow

---

## 1. Interface/UI
Obviously, Power Automate has no UI, but it has connectors, so in theory it can work with any UI. But to keep it in the spirit of the challenge I considered 3:

- SharePoint
- Approvals
- Outlook

**SharePoint** would have to be a list, or even a text file (triggered on save). The list wasn't practical, but the text file would definitely work.

**Approvals** would be good because I could pass simple text, read comments and stay within one flow run.

**Outlook** was the most flexible, I could use with options for one flow run, or emails for full flexibility.

In the end I went with Outlook, it kind of felt a little retro, and allowed anyone (not just people on my org) to use the game.

## 2. Design
In my mind I had 2 approaches, a single flow run, or multi flow. Single was a lot easier, as I could store progress and player status in the flow. But this limited the interaction, as with Outlook that would require `Email with Options`, and I wanted this to be text not button based. So that left multi flow, the problem with this is the benefits of single, how do I track the progress of the game. The easy way would be a SharePoint list, each game would be a row in the list, but this didn't feel right to me, it wasn't scalable and wasn't very innovative. So I came up with a different approach, what if I treated the subject of the email like an API call, I could pass the position in the game and the status of the player as parameters. The flow wouldn't need to remember anything, just take the input and return an output.

`TriggerCondition?levelID&leftHand&rightHand&status
`

## 3. Gameplay 
I started with a 10 by 10 board, so 100 squares, well no I had 1 edge square so it ended up 8 by 8 (64 squares, perfect number for a retro game).
The navigation was simple, North, East, South West, but to make sure it wasn't to dull I decided on a chess queen approach. So you don't move one square you move until you hit the next square with something in it.
To make the game a little interesting I decided on some additional actions then just moving.

- Pick up
- Use
- Drop
- Speak
- Answer

On certain squares you could do these actions and you can only hold 2 items at once.

The items can be used in 2 ways:

- Heal/Save life
- Unlock square(s)

As you have guessed there are squares you can die on, with some the ability to survive, others straight death. The survivable squares have a puzzle to solve, with the Heal/Save life item a clue or answer.

I also added puzzles at some key elements to progress too, this is to either get information or items you need to progress.

The unlock squares works by your status, so using an item will change your status, having right status allows you to access square e.g.
`Use boat to set status to sailing to access water square`

## 4. Setup
The story and details to the game are key, but so is how they are setup, as I want to be able to make the story dynamic. First of all this is going to be in Excel and not my usual SharePoint list. This is for 3 reasons:

1. To be different/learn
2. I'm using Outlook and not Outlook O365 as this is linked to a temp developer tenant, 
3. It's actually easier to use Excel as I can also use it for the map

The map is the 10 by 10 grid in a Excel tab, here I plan out all the locations.

![excel map](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jfs2qpiilv3ha08i70o.png)

Next I transfer this to a table which will be looked up during the game, each column is used for different things:

| Column     | Used For                                            | Example                                     |
|------------|-----------------------------------------------------|---------------------------------------------|
| Square     | Description                                         | Jungle                                      |
| Co-ord     | Grid Reference                                      | D4                                          |
| ID         | GUID for subject                                    | 1                                           |
| Text       | Text returned when step into square                 | You enter the cave, it's very dark          |
| North      | Row ID of Square to North or message if blocked     | 8                                           |
| East       | Row ID of Square to East or message if blocked      | The wall is too high to climb               |
| South      | Row ID of Square to South or message if blocked     | 16                                          |
| West       | Row ID of Square to West or message if blocked      | You fall off the cliff and die. Game Over   |
| Item       | Item available to pick up                           | Crossbow                                    |
| Use        | Item that can be used                               | Anti-crossbow spray                         |
| Person     | The response to speaking to a person                | I can't believe you shot me with a crossbow |
| Puzzle     | The response if you get the challenge/survive right | You use the crossbow to defeat the baddie   |
| Incorrect  | The response if you get the challenge/survive wrong | You die you wimp, Game Over                 |
| Answer     | Answer to the challenge/survive puzzle              | To get to the other side                    |
| Attachment | Attachment sent when pick up item                   | crossbow.jpg                                |
| Need       | The status you need to enter this square            | Sailing                                     |


![excel table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/txwgiv6wmwrfzbi8ysda.png)

Finally there is an item table, this is used to get information when using an item.

| Column | Used For                                                                        | Example                              |
|--------|---------------------------------------------------------------------------------|--------------------------------------|
| Item   | Item name (linked to Item column in Map)                                        | Crossbow                             |
| Action | Status it gives (linked to the required column in Map and the status parameter) | Fighting                             |
| Give   | Custom message for when the item is used                                        | The crossbow made you big and strong |

### 4. The Flow
This is the interesting bit, in this case our flow is basically  logic tree, all we are going to do is pass in our inputs, check some parameters and return a value, simple.

I hate nesting and I hate using conditions as branching, so you are going to see the [Direct Methodology](https://dev.to/wyattdave/power-automate-the-direct-methodology-32mf) approach with escape conditions.

```
->condition
    -true
        action
        terminate
->condition
    -true
        action
        terminate
->condition
    -true
        action
        terminate
```
Each time we check a condition, if true we do something then terminate. If false we skip the condition for the next condition (the false are empty).

![flow condition](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/98dmmagzdco85u4a23i2.png)

As example the subject expression for picking up an item is:
```
if(not(equals(outputs('Get_a_row_current_Sq')?['body/Item'],'')),
    if(equals(outputs('Extract_Query')[1],'empty'),
        concat(
            'canyonEscape?'
		,
			outputs('Extract_Query')[0]
        ,
            '&'
        ,
            outputs('Get_a_row_current_Sq')?['body/Item']
        ,
            '&'
        ,
            outputs('Extract_Query')[2]
        ,
            '&'
        ,
            outputs('Extract_Query')[3]
        ,
            '&'
        ,
        triggerOutputs()?['body/Id']
        )	
    ,
        concat(
            'canyonEscape?'			
        ,
			outputs('Extract_Query')[0]
		,
            '&'
        ,
             outputs('Extract_Query')[1]
        ,
            '&'
        ,
            outputs('Get_a_row_current_Sq')?['body/Item']
        ,
            '&'
        ,
            outputs('Extract_Query')[3]
        ,
            '&'
        ,
            triggerOutputs()?['body/Id']
        )
	)
,
    replace(triggerOutputs()?['body/Subject'],'RE:','')
)
```
The conditions are:
- Pick up
- Use
- Can't Use
- Speak
- Can't Speak
- Challenge Correct
- Challenge Failed
- Condition Survive
- Condition Die
- Drop
- Path not Valid
- Path Blocked by Status
- Path Move

And a bonus condition for Start and Cheating (see later).

So we get our current position in the game from the subject and we use condition tree to return next step in the game, how do we convert the subject parameters.

First we split the subject (with a literal split) to get each parameter. 

```
split(
    split(
        triggerOutputs()?['body/Subject']
    ,
        '?'
    )[1]
,
    '&'
)
```

![do until flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8bfxiqbqcihflpn5tba.png)

Next we loop over all of our actions and check if the body contains it (I use a Do_until loop as that can stop once found and save it to a variable - stop condition variable not blank). We have an object array that has the possible value and the output e.g.
take is same as pick up, so we want to set the variable to the same as pick up, in this case our condition looks for PickUp.

![logic array](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ovdjqxvgfmha16zbk59o.png)

We now have our text (action and variable) status, items and our location. But the location is just an id, we use that id to look up at row in our Excel file map table, getting all the key information.

We use the same table to get the next squares detail (North/East/South/West id returns the row and its detail, like required).

There's a couple of wildcards to add:
**Start**
We use a trigger condition, but what happens on the first stage when we don't have any parameters. Well here I'm using exception handling as a logic. If we fail out split because of missing parameters, then we catch that as a run after failed and send the start email.

![start exception flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oc1tpxjhwrztnd9vemy4.png)

**Cheating**
We know everyone likes to cheat, so how do I stop people just replying to an email 100 times until they get it right, well this is the clever bit. We use the last email as a life, this email is deleted, so if we reply twice, it will fail as we can't delete the email twice. How do I know the email message ID, well I just add it as a parameter to our subject. But what If I want to cheat, well we can add a cheat code, this condition checks if the email body contains the code and skips the delete email.

![delete](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1gc1jgmtyku20eh6vu1i.png)

The full flow is a bit of a monster and pushes the limit of what I normally put in one flow, but it works, and there isn't actually that many actions (just conditions, lots of conditions 😎 )

![full flow](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cwazk4ej4ni2pt8bj5kt.png)

![flow from autoreview](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a1wzcfmb9dcrpgljnhyk.png)

---

## Key Learnings
So what did I learn from building Canyon Escape,

- Excel is a great config/lookup connector, not far off SharePoint
- Using Outlook/OneDrive/Excel is just as good as their 365 alternatives, so automating your personal life is just as easy as work life.
- Power Automate can do logic tress OK, though it definitely has a limit
- Exception logic works well and though not recommend has its place

---

Want to make your own, flows and files [here](https://github.com/wyattdave/Power-Platform/tree/main/Canyon%20Escape), just:
- Setup free outlook account
- Upload the map.xlsx and attachment files to that accounts OneDrive root. 
- Edit the map then transfer to the data table and item table