Skip to content

Instantly share code, notes, and snippets.

@kenwebb
Created Nov 12, 2021
Embed
What would you like to do?
Beach Comber
Beach Comber
For use with Island Game.
An Avatar that stays within the current stretch of Coast.
/**
Ken Webb
Learning Express.
October 25, 2021
see Xholon workbook: Express - web framework for node
3ede7991936fe5281657c494f8a92caf
(base) ken@ken-HP-ZBook-15-G2:~/nodespace/express01$ node app.js
Example app listening at http://localhost:3000
http://localhost:3000/add/1/99
result: 1 + 99 = 100
see also: ~/gwtspace/Xholon/Xholon/module/moduleAvatar2Server.xml
Performance
-----------
see: https://expressjs.com/en/advanced/best-practice-performance.html
To set NODE_ENV to “production”, enter this command in the Linux/Ubuntu terminal window, before running node:
export NODE_ENV=production
This is temporary, and is only active for that terminal window.
*/
const express = require('express')
const cors = require('cors') // KSW added this
const {ftest, random, random4, random8, nesw, bchcmr} = require('./functions') // Procedural Memory
const {stest, sinsert, squery} = require('./storage') // Declarative Memory
const app = express()
const port = 3000
// enable CORS for all origins
app.use(cors());
app.use(express.json()) // for parsing application/json
app.get('/', (req, res) => {
res.send('Hello World!')
})
// KSW test
app.get('/test1', (req, res) => {
res.send('Testing 1.')
})
// KSW test
app.get('/test2', (req, res) => {
res.send('Testing 2.')
})
app.get('/test2/:one', (req, res) => {
res.send('Testing 2: ' + req.params.one)
})
app.get('/add/:one/:two', (req, res) => {
res.send(`${req.params.one} + ${req.params.two} = ` + (0 + Number(req.params.one) + Number(req.params.two)))
})
/**
* Return a random direction for a Xholon agent to move to (0 1 2 3). Grid: (N S E W) or Tree: (parent first next prev).
*/
app.get('/moveto', (req, res) => {
res.send("" + random4())
})
/**
* Working Memory.
* @param {Request} req A Perception or similar Request.
* @param {Response} res A Motor command or similar Response.
*/
app.post('/nesw', (req, res) => {
sinsert(req.body)
res.send("" + nesw(req.body))
})
app.get("/squery", (req, res) => {
res.send(squery())
})
/**
* Beach Comber
* @param {Request} req A Perception or similar Request.
* @param {Response} res A Motor command or similar Response.
*/
app.post('/bchcmr', (req, res) => {
res.send("" + bchcmr(req.body))
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
console.log(ftest())
console.log(stest())
console.log("NODE_ENV: " + process.env.NODE_ENV)
})
/**
Ken Webb
October 31, 2021
functions.js
Functions for use with app.js
Decision Engine - Procedural Long-term Memory
*/
const ftest = () => "Hello out there from FTest!"
/**
* Various functions that generate random integers within specified ranges.
*/
const random = max => () => Math.floor(Math.random() * max)
const random4 = random(4)
const random8 = random(8)
/**
* Process a NESW JavaScript Object.
* @param {Object} obj ex: { me: 'LandCell', n: 'CoastCell', e: 'LandCell', s: 'LandCell', w: 'LandCell' }
* @return {Number} A direction to move to a random neighboring non-OceanCell gridCell.
*/
const nesw = obj => {
const neswArr = Object.entries(obj).reduce((prev, curr) => {
if ((curr[0] !== "me") && (curr[1] !== "OceanCell")) {
prev.push(curr[0])
}
return prev
}, [])
const moveto = neswArr[random(neswArr.length)()]
const movetoNum = moveto === "n" ? 0
: moveto === "e" ? 1
: moveto === "s" ? 2
: 3
//console.log(obj, neswArr, moveto, movetoNum)
return movetoNum
}
/**
* Process a Beach Comber JavaScript Object.
* @param {Object} obj ex: { me: 'CoastCell', n: 'CoastCell', e: 'LandCell', s: 'CoastCell', w: 'OceanCell' }
* @return {Number} A direction to move to a random neighboring CoastCell gridCell.
*/
const bchcmr = obj => {
const arr = Object.entries(obj).reduce((prev, curr) => {
if ((curr[0] !== "me") && (curr[1] === "CoastCell")) {
prev.push(curr[0])
}
return prev
}, [])
const moveto = arr[random(arr.length)()]
const movetoNum = moveto === "n" ? 0
: moveto === "e" ? 1
: moveto === "s" ? 2
: 3
//console.log(obj, arr, moveto, movetoNum)
return movetoNum
}
module.exports = {ftest, random, random4, random8, nesw, bchcmr};
<?xml version="1.0" encoding="UTF-8"?>
<!--
Xholon Avatar that moves within the Island Game world, always staying within the current stretch of coast.
Ken Webb
November 12, 2021
~/gwtspace/Xholon/Xholon/module/ava2srv/mBeachComber.xml
based on mAva2SrvPostNesw.xml
See Xholon workbook: Express - web framework for node
Copy and paste, or drag, this entire text into a running Xholon app.
-->
<XholonModule>
<XholonMap>
<Attribute_String roleName="ih"><![CDATA[
<_-.XholonClass>
<BeachComber superClass="Avatar"/>
<Talk2Server superClass="Script"/>
</_-.XholonClass>
]]></Attribute_String>
<Attribute_String roleName="cd"><![CDATA[
<xholonClassDetails>
<BeachComber><Color>purple</Color></BeachComber>
<Talk2Server><DefaultContent>
const REQ_REMOTE = true;
var me, ava, request, beh = {
postConfigure: function() {
me = this.cnode;
ava = me.parent().parent();
if (!ava["subtrees"]) {
ava.action("param subtrees true");
}
ava.action("param transcript false");
const url = ["http://127.0.0.1:3000/bchcmr", "http://192.168.0.39:3000/bchcmr"];
request = new Request(url[0]);
me.msg(101, "Sending me ...");
},
processReceivedMessage(msg) {
this.doRequest(this.prepData(ava.parent()));
},
prepData: function(pava) {
return {
me: pava.xhc().name(),
n: pava.port(0).xhc().name(),
e: pava.port(1).xhc().name(),
s: pava.port(2).xhc().name(),
w: pava.port(3).xhc().name()
}
},
doRequest: function(jso) {
if (REQ_REMOTE) {
this.doRequestRemote(jso);
}
else {
this.doRequestLocal(jso);
}
},
doRequestRemote: function(jso) {
fetch(request, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(jso)
})
.then((res) => res.text())
.then((responseText) => {
this.moveto(responseText);
me.msg(101, "Sending me againR ...");
return null;
});
},
doRequestLocal: function(obj) {
// this is the same code used in the Server functions.js
const arr = Object.entries(obj).reduce((prev, curr) => {
if ((curr[0] !== "me") &amp;&amp; (curr[1] === "CoastCell")) {
prev.push(curr[0])
}
return prev
}, [])
const random = max => () => Math.floor(Math.random() * max)
const moveto = arr[random(arr.length)()]
const movetoNum = moveto === "n" ? 0
: moveto === "e" ? 1
: moveto === "s" ? 2
: 3
this.moveto(movetoNum);
me.msg(101, "Sending me againL ...");
},
moveto: function(direction) {
ava.action("go " + direction); // go 0|1|2|3 OK
}
}
//# sourceURL=Talk2Serverbehavior.js
</DefaultContent></Talk2Server>
</xholonClassDetails>
]]></Attribute_String>
<Attribute_String roleName="csh"><![CDATA[
<_-.csh>
<!-- I can create additional instances of BeachComber, by dragging in just the following subtree -->
<BeachComber>
<BehaviorsST>
<Talk2Server/>
</BehaviorsST>
</BeachComber>
</_-.csh>
]]></Attribute_String>
</XholonMap>
</XholonModule>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment