Skip to content

Commit 7d9fb75

Browse files
init from hackercorner
0 parents  commit 7d9fb75

11 files changed

Lines changed: 769 additions & 0 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.vscode/
2+
3+
work/

controls/hackercorner/maze.js

Lines changed: 362 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,362 @@
1+
function debug(entry) {
2+
console.log(entry)
3+
};
4+
5+
function fine(entry) {
6+
console.log(entry)
7+
};
8+
9+
function Maze(structure, walls, phrases) {
10+
this.structure = structure;
11+
this.walls = walls;
12+
this.phrases = phrases;
13+
};
14+
15+
16+
Maze.prototype.tryMove = function (direction) {
17+
debug(`trying ${direction}`)
18+
var result
19+
switch (direction) {
20+
case 'up':
21+
result = this._move(this.position, -1, 0);
22+
break
23+
case 'down':
24+
result = this._move(this.position, 1, 0)
25+
break
26+
case 'left':
27+
result = this._move(this.position, 0, -1)
28+
break
29+
case 'right':
30+
result = this._move(this.position, 0, 1)
31+
break
32+
default:
33+
throw new Error("unknown direction");
34+
}
35+
36+
this.position = result.pos
37+
result.direction = direction
38+
return result
39+
}
40+
41+
Maze.prototype.up = function () {
42+
return this.tryMove('up');
43+
}
44+
45+
Maze.prototype.down = function () {
46+
return this.tryMove('down');
47+
}
48+
49+
Maze.prototype.left = function () {
50+
return this.tryMove('left');
51+
}
52+
53+
Maze.prototype.right = function () {
54+
return this.tryMove('right');
55+
}
56+
57+
Maze.prototype._move = function (pos, x, y) {
58+
let newX = pos[0] + x
59+
let newY = pos[1] + y
60+
61+
let thing = this.structure[newX][newY]
62+
63+
// What did we meed
64+
var story = this.phrases[thing]
65+
debug('> ' + story)
66+
67+
// If this is a wall, stay at current position
68+
if (this.walls.includes(thing)) {
69+
fine(`still at: ${pos}`)
70+
this.position = pos
71+
return {
72+
'success': false,
73+
'outcome': story,
74+
'thing': this.look(pos),
75+
'pos': pos
76+
}
77+
}
78+
79+
var newPos = [newX, newY]
80+
fine(`now at: ${newPos}`)
81+
this.position = pos
82+
return {
83+
'success': true,
84+
'thing': this.look(newPos),
85+
'pos': newPos
86+
}
87+
}
88+
89+
90+
Maze.prototype.look = function (pos) {
91+
var x = pos[0]
92+
var y = pos[1]
93+
var thing = this.structure[x][y]
94+
return this.phrases[thing];
95+
}
96+
97+
98+
// Use this function if the output supports Newlines
99+
Maze.prototype.buildMap = function () {
100+
var pos = this.position
101+
var poster = ""
102+
for (var y = 0; y < this.structure.length; y++) {
103+
var line = ""
104+
for (var x = 0; x < this.structure[0].length; x++) {
105+
var char = this.structure[y][x]
106+
if ((y == pos[0]) && x == pos[1]) {
107+
char = 'o'
108+
}
109+
line += char
110+
}
111+
poster += line + "\n"
112+
}
113+
debug("poster:\n" + poster)
114+
return poster
115+
}
116+
117+
// Use this function if the output does NOT supports newlines
118+
Maze.prototype.buildMapAsWrapped = function (linewidth, skipBorders) {
119+
120+
var map = ""
121+
var pos = this.position
122+
for (var y = 0; y < this.structure.length; y++) {
123+
if (!(skipBorders && ((y == 0) || (y == this.structure.length - 1)))) {
124+
var line = ""
125+
for (var x = 0; x < this.structure[0].length; x++) {
126+
var char = this.structure[y][x]
127+
if ((y == pos[0]) && x == pos[1]) {
128+
char = 'o'
129+
}
130+
line += char
131+
}
132+
var left = Math.round((linewidth - line.length) / 2)
133+
var mazeline = line.padStart(left + line.length, "-")
134+
map += mazeline.padEnd(linewidth, "-")
135+
map += " "
136+
}
137+
}
138+
debug("maze map:" + map)
139+
return map
140+
}
141+
142+
Maze.prototype.pickInitialPosition = function (emptyChar) {
143+
if (!emptyChar) emptyChar = ' '
144+
145+
// Ping a random number, on an empty spot
146+
while (true) {
147+
var y = Math.round(Math.random()*(this.structure.length - 2) + 1)
148+
var x = Math.round(Math.random()*(this.structure[0].length - 2) + 1)
149+
fine(`picked x: ${x}, y: ${y}`)
150+
151+
if (this.structure[y][x] == emptyChar) {
152+
fine(`position is clear, storing...`)
153+
return this.setInitialPosition(x, y)
154+
}
155+
}
156+
}
157+
158+
Maze.prototype.setInitialPosition = function (x, y) {
159+
this.position = [y, x]
160+
return this.position
161+
}
162+
163+
164+
//
165+
// Utilities
166+
//
167+
168+
function showSuspens(count, delay, cb, final, initial) {
169+
var counter = 0
170+
if (!initial) initial = ""
171+
var timer = setInterval(function (event) {
172+
var suspens = "...............";
173+
cb(initial + suspens.substring(0, counter + 1));
174+
counter++;
175+
if ((counter >= count) || (counter > 10)) {
176+
clearInterval(timer)
177+
cb(final)
178+
}
179+
}, delay)
180+
}
181+
182+
183+
function isEmail(email) {
184+
// extract from http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
185+
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
186+
return re.test(email);
187+
}
188+
189+
190+
//
191+
// Room Controls
192+
//
193+
const xapi = require('xapi');
194+
195+
196+
function showInstructions(message) {
197+
xapi.command('UserInterface Extensions Widget SetValue', {
198+
WidgetId: 'instructions',
199+
Value: message
200+
})
201+
}
202+
203+
204+
function showOutcome(res, initial) {
205+
if (res.success) {
206+
showSuspens(5, 500, showInstructions, res.thing, initial)
207+
}
208+
else {
209+
showSuspens(5, 500, showInstructions, res.outcome, initial)
210+
}
211+
}
212+
213+
214+
function sendMazeToSpark() {
215+
debug("sending map")
216+
217+
xapi.command('UserInterface Extensions Widget SetValue', {
218+
WidgetId: 'map_placeholder',
219+
Value: game.buildMapAsWrapped()
220+
})
221+
}
222+
223+
function captureSparkEmail() {
224+
225+
// Ask for Spark email
226+
xapi.command('UserInterface Message TextInput Display', {
227+
FeedbackId: 'capture-sparkEmail',
228+
Title: 'Send the map to Cisco Spark',
229+
Text: "Enter your spark email:",
230+
});
231+
232+
xapi.event.on(' UserInterface Message TextInput Response', (event) => {
233+
fine(event)
234+
if (event.FeedbackId == 'capture-sparkEmail') {
235+
var email = event.Text
236+
debug(`check email: ${email}`)
237+
if (!isEmail(email)) {
238+
xapi.command('UserInterface Message Alert Display', {
239+
Title: 'Bad email',
240+
Text: 'Entry does not conform to an email address, aborting...',
241+
Duration: 5
242+
});
243+
244+
return;
245+
}
246+
247+
xapi.command('UserInterface Extensions Widget SetValue', {
248+
WidgetId: 'spark_email',
249+
Value: email
250+
})
251+
}
252+
})
253+
}
254+
255+
256+
function displayMapInAlertPanel() {
257+
xapi.command('UserInterface Message Alert Display', {
258+
Title: 'With a little help from ... the bot',
259+
Text: game.buildMapAsWrapped(51, true),
260+
Duration: 5
261+
});
262+
}
263+
264+
// Displays help on the Touch10 or send the configuration to Cisco Spark
265+
function showHelp() {
266+
// Check what is current the help media
267+
xapi.status.get("UserInterface Extensions Widget")
268+
.then(w => {
269+
var selected = w.filter((widget) => { return widget.WidgetId == 'helper_media' })[0].Value
270+
271+
// Spark is selected
272+
if (selected == 'Spark') {
273+
console.log("sending maze to Spark")
274+
275+
// Post map to the Cloud
276+
sendMazeToSpark()
277+
278+
return
279+
}
280+
281+
// else push to Touch10
282+
console.log("sending maze to Touch10 Alert dialog")
283+
displayMapInAlertPanel()
284+
})
285+
}
286+
287+
288+
function onGui(event) {
289+
if (event.Type == 'clicked') {
290+
if (event.WidgetId == 'directions') {
291+
var direction = event.Value
292+
if (direction == 'center') {
293+
showHelp()
294+
return
295+
}
296+
297+
showInstructions(`moving ${direction}`)
298+
var res = game.tryMove(direction)
299+
showOutcome(res, `moving ${direction}`)
300+
return
301+
}
302+
303+
if (event.WidgetId == 'restart') {
304+
restart()
305+
return
306+
}
307+
308+
// No more event listener
309+
return
310+
}
311+
312+
if (event.Type == 'released') {
313+
if ((event.WidgetId == "helper_media") && (event.Value == "Spark")) {
314+
captureSparkEmail()
315+
return
316+
}
317+
}
318+
}
319+
xapi.event.on('UserInterface Extensions Widget Action', onGui);
320+
321+
322+
function restart() {
323+
console.log('resetting the maze')
324+
325+
var structure = []
326+
structure[0] = ['|', '-', '-', '-', '-', '-', '|']
327+
structure[1] = ['|', '_', 'C', '_', '_', '_', '|']
328+
structure[2] = ['|', '_', '_', 'X', '_', '_', '|']
329+
structure[3] = ['|', '_', 'X', '?', 'X', '_', '|']
330+
structure[4] = ['|', '_', '_', '_', '_', 'X', '|']
331+
structure[5] = ['|', '-', '-', '-', '-', '-', '|']
332+
333+
var walls = ['|', '-', 'X']
334+
335+
var phrases = {}
336+
phrases['|'] = "cannot get there, this a maze border you just hitted"
337+
phrases['-'] = "cannot get there, this a maze border you just hitted"
338+
phrases['|'] = "cannot get there, this a maze border you just hitted"
339+
phrases['X'] = "ouch, you bumped a wall"
340+
phrases['_'] = "nothing here, let's continue exploring."
341+
phrases['C'] = "hello kitty, you look hungry. Are you lost too? Jump in."
342+
phrases['D'] = "WOW, an agressive dog is lying here. Better run away!"
343+
phrases['?'] = "CONGRATS, you found the treasure!!!"
344+
345+
game = new Maze(structure, walls, phrases)
346+
game.pickInitialPosition('_')
347+
348+
showSuspens(10, 200, showInstructions, 'Then here you are: lost in an hostile maze, looking for a treasure. Pick a direction...', 'initializing the Maze')
349+
}
350+
351+
var game;
352+
if (!game) {
353+
// First run:
354+
// - initialize maze
355+
restart()
356+
}
357+
358+
// - select Touch10 help
359+
xapi.command('UserInterface Extensions Widget SetValue', {
360+
WidgetId: 'helper_media',
361+
Value: 'Touch10'
362+
});

0 commit comments

Comments
 (0)