Skip to content

Instantly share code, notes, and snippets.

@samdphillips
Last active August 10, 2021 19:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samdphillips/c3441b66d5610304a6ece3f2a52b6b05 to your computer and use it in GitHub Desktop.
Save samdphillips/c3441b66d5610304a6ece3f2a52b6b05 to your computer and use it in GitHub Desktop.
Another rhombus experiment

Rhombus Sheepdogs

This is an incomplete implementation of a sheep and sheepdog agent simulation in Rhombus.

NOTE The Rhombus proposal is not stable. This example should be considered a point in time example. I may or may not update this to reflect newer versions of the proposal.

#lang rhombus
import:
r = racket/base:
rename:
#{null?} 'to' is_null
#{inexact->exact} 'to' exact
#{vector-ref} 'to' vector_ref
#{vector-set!} 'to' vector_set
l = racket/list
struct Posn(x,y)
struct Sheep(p :: Posn)
struct Sheepdog(p :: Posn)
struct World(width :: Integer, height :: Integer, agents)
val sheep_view: 10
val sheepdog_view: 25
operator (a ^ b):
'stronger_than': * / + - <=
'associativity': 'right'
r.expt(a, b)
operator (a % b):
'weaker_than': * /
'stronger_than': + -
r.modulo(a, b)
expr.macro ?(when ??test ... { ??body ... } ??tail ...):
values(?(if ??test ... { | { ??body ... } | { r.void() }}),
tail)
// make_world :: width height num_sheep num_sheepdogs -> World
fun make_world(width :: Integer,
height :: Integer,
num_sheep :: Integer,
num_sheepdogs :: Integer):: World:
val sheep: make_sheep(num_sheep, width, height)
val sheepdogs: make_sheepdogs(num_sheepdogs, width, height)
World(width, height, r.append(sheep, sheepdogs))
// make_things :: make num_things width height -> Listof thing
fun make_things(make,
num_things :: Integer,
width :: Integer,
height :: Integer):
fun make_random(i):
val w: r.random(0, width)
val h: r.random(0, height)
make(Posn(w, h))
// XXX: this begs the question: what does `for` syntax look like in Rhombus.
// The shrubbery proposal has some possible `for` syntax.
r.map(make_random, l.range(num_things))
// make_sheep :: num_sheep width height -> Listof Sheep
fun make_sheep(num_sheep :: Integer,
width :: Integer,
height :: Integer):
make_things(fun(p): Sheep(p), num_sheep, width, height)
// make_sheepdogs :: num_sheepdogs width height -> Listof Sheepdog
fun make_sheepdogs(num_sheepdog :: Integer,
width :: Integer,
height :: Integer):
make_things(fun(p): Sheepdog(p), num_sheepdog, width, height)
val d: r.list(Posn(-1,-1), Posn(0, -1), Posn(1, -1),
Posn(-1, 0), Posn(0, 0), Posn(1, 0),
Posn(-1, 1), Posn(0, 1), Posn(1, 1))
fun distance(width, height, Posn(x0, y0), Posn(x1, y1)):
fun step(d, cur_distsq, cur_dx, cur_dy):
cond:
| r.is_null(d):
val dist: r.sqrt(cur_distsq)
values(dist,
r.exact(r.round(cur_dx / dist)),
r.exact(r.round(cur_dy / dist)))
| 'else':
val Posn(wdx, wdy): r.car(d)
val dx: (x1 + wdx * width) - x0
val dy: (y1 + wdy * height) - y0
val distsq: dx ^ 2 + dy ^ 2
if r.not(cur_distsq) || distsq < cur_distsq:
| step(r.cdr(d), distsq, dx, dy)
| step(r.cdr(d), cur_distsq, cur_dx, cur_dy)
step(d, #false, #false, #false)
val width: 100
val height: 100
val entity: Sheep(Posn(50, 50))
val sight: match entity { | { Sheep(_): { sheep_view } }
| { Sheepdog(_): { sheepdog_view } }}
val posn: match entity { | { Sheep(p): { p } } | { Sheepdog(p): { p } } }
val scores: r.vector(0, 0, 0, 0, 0, 0, 0, 0, 0)
fun update_score(dx, dy, v):
val i: dx + 1 + 3 * (dy + 1)
val v0: r.vector_ref(scores, i)
r.vector_set(scores, i, v0 + v)
fun calculate_scores(others):
cond
| r.is_null(others): scores
| 'else':
val (dist, dx, dy, score):
match r.car(others):
| Sheep(p):
val (dist, dx, dy): distance(width, height, posn, p)
values(dist, dx, dy, 1)
| Sheepdog(p):
val (dist, dx, dy): distance(width, height, posn, p)
values(dist, dx, dy, -1)
when dist <= sight:
update_score(dx, dy, score)
calculate_scores(r.cdr(others))
val World(_w, _h, es): make_world(100,100,100,100)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment