KnotLogo-Hubnet

No preview image

1 collaborator

Uri_dolphin3 Uri Wilensky (Author)

Tags

hubnet 

Tagged by Reuven M. Lerner over 11 years ago

Model group CCL | Visible to everyone | Changeable by group members (CCL)
Model was written in NetLogo 3D Preview 5 • Viewed 416 times • Downloaded 25 times • Run 0 times
Download the 'KnotLogo-Hubnet' modelDownload this modelEmbed this model

Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)


VERSION

$Id: KnotLogo-Hubnet.nlogo 40114 2008-06-12 23:22:32Z tisue $

WHAT IS IT?

This Hubnet model is based off of the KnotOrNot3D NetLogo model, which is a microworld for playing with rope, thinking and learning about knots and knot theory, as well as creating virtual rope-based art and artifacts. This Hubnet version of it provides a shared virtual space where a class can interact together to engage in these activities.

HOW IT WORKS

Students have more limited control than they do in the "solo" KnotOrNot environment. They also have a different method of navigating their snakes. In the "solo" world, everything was snake-centric. In the Hubnet version, students choose absolute directions for their snake's movement (North, South, East, West, Up, and Down), and are limited to orthogonal movement (although the snake's body will still curve nicely around behind). The reason for this change is twofold.

1) I think it's good for students to have to think in multiple representations -- both from the perspective of individual agents, and from the perspective of the environment. Or, from a totally mathematical perspective, we are making them think in two different coordinate spaces.

2) In the "solo" model, each student could move the camera and position it such that they had a good view of their turtle, and could figure out which direction it was facing. In this Hubnet version, there is only one global camera, controlled by the teacher, and so viewing your turtle's heading is more difficult. It should be easier to spotting your turtle's location, and using the direction labels on the boundaries of the world, choose an appropriate direction to move.

HOW TO USE IT

The teacher should push SETUP, then GO. DON'T push SETUP again after the model is running!

Students should log in. They will each be assigned a color of snake based on their order of logging in, and they will be told (on their client screens) what color they are. Currently there are only different colors, so more than 8 clients will cause repeated colors -- and probably some confusion. More colors can be added easily by changing the COLORS and COLOR-NAMES lists that are initialized in the SETUP procedure. The trick is in choosing lots of good colors that contrast with each other.

The RESET-SNAKES button makes all the snakes only one segment long, and moves them all to the center of the world.

If desired, the teacher can also set the CAMERA-ORBIT button going, so that the viewing angle on the world will slowly rotate around. This may be useful for making the world seem more 3D, as well as moving closer and farther away from various students.

If the class creates a neat rope configuration that they'd like to save, the teacher can use the SAVE-TO-VRML button.

THINGS TO NOTICE

The student's snake bodies are limited to 40 units in length in this Hubnet version, to prevent any student from getting too carried away. Furthermore, the model runs more slowly the more segments there are in the world, and the Hubnet version in particular can really come to a crawl when the world is crowded. Thus limiting the length of snakes should be helpful for that.

THINGS TO TRY

This is a fairly open-ended participatory simulation. In general, it might work to let the class choose the direction of the activity. That said, sometimes they need more structure and guidance, so here are some ideas:

1) Can the class pair up and tie simple knots with each other?

2) Can the class form a long chain, by having each snake bite its own tail through the rings created by two other snakes?

3) Can the class cooperatively spell out a message using the snake bodies?

EXTENDING THE MODEL

Make a slider for the teacher that controls the maximum segment length for any snake.

Try adding support for teacher-controlled snakes. Or give the teacher more controls for manipulating the student's snakes.

What about giving client interfaces inputboxes, so students can ask their snakes to run any code they want? Is this safe? Probably not, students who are sufficiently savvy with NetLogo can find ways to break the model. Even so, it still could be a lot of fun, and the benefits might outweigh the drawbacks.

RELATED MODELS

KnotOrNot3D -- the solo version.

CREDITS AND REFERENCES

Model authored by Forrest Stonedahl, for an LS 426 Final Project at Northwestern University.

The basic rope simulation is adapted from the "follow the leader" algorithm proposed in this paper:

Brown, J. Latombe, J. & Montgomery, K. (2004), 'Real-time knot-tying simulation', The Visual Computer 20(2), 165--179.

Comments and Questions

Please start the discussion about this model! (You'll first need to log in.)

Click to Run Model

extensions [ vrml ]
globals [ 
  headlist 
  jigglers
  jiggler-patches
  first-mover ; for keeping track of which snakesegment initiates motion, 
              ; whenever a snake movement occurs
              
  colors
  color-names
  ]
breed [snakesegments snakesegment]
snakesegments-own [ 
  prev
  next
  snake-id 
  
  tempdx
  tempdy
  tempdz 
]
; for hubnet handling
breed [students student]
students-own
[
  my-hubnet-id
  my-snake-id
  move-snake?
]

to startup
  hubnet-set-client-interface "COMPUTER" []
  hubnet-reset
  setup-vars
end 
;; initialize global variables

to setup-vars
  set colors      (list red brown green yellow
                        violet (sky + 1) pink (blue - 1))
  set color-names ["red" "brown" "green" "yellow"
                   "purple" "light blue" "pink" "dark blue"]
end 

to-report get-color [ id ]
  report (item (id mod (length colors)) colors)
end 

to-report get-color-name [ id ]
  report (item (id mod (length color-names)) color-names)
end 

to setup
  clear-patches
  reset-perspective
  set headlist []
  set first-mover nobody
  ask patch 0 0 (max-pzcor - 2) [ set plabel "UP" ]
  ask patch 0 0 (min-pzcor + 2) [ set plabel "DOWN" ]
  ask patch 0 (max-pycor - 2) 0 [ set plabel "NORTH" ]
  ask patch 0 (min-pycor + 2) 0 [ set plabel "SOUTH" ]
  ask patch (max-pxcor - 2) 0 0 [ set plabel "EAST" ]
  ask patch (min-pxcor + 2) 0 0 [ set plabel "WEST" ]
  orbit-down 45
  orbit-left 30
  zoom 20
end 

to go
  listen-clients
  forward-all 0.1
end 

to reset-snakes
  ask snakes [ 
    repeat 39 [ snake-shrink ]
    setxyz 0 0 0
    set heading 360 * snake-id / (count snakes)
  ]
end 

to update-appearance
  ifelse (is-head? and not looped?)
  [
    set shape "default"
    set size 2
  ]
  [
    set shape "circle"
    set size 1
  ]
  set color (get-color snake-id) - 1
  if (is-head?)
    [ set color color + 2 ]
end 

to-report snake [ n ]
 if (n < 0 or n >= length headlist or (item n headlist) = nobody )
 [ 
   user-message (word "Snake " n " doesn't exist!")  
   report nobody
 ] 
 report item n headlist 
end 

to-report snakes
  report turtle-set headlist
end 

to-report is-head?
  report self = snake snake-id 
end 

to-report is-tail?
 report (next = nobody) or ([is-head?] of next)
end 

to-report get-head
  report (snake snake-id)
end 

to-report get-tail
  ifelse (is-tail?)
  [ report self ]
  [ report [get-tail] of next ]
end 

to-report make-snake [ x y z ]
  if (not is-list? headlist )
    [  set headlist [] ]
  let nextid position nobody headlist   ; reuse snake-ids
  if (nextid = false)
    [ set nextid length headlist ]
  let temp nobody
  create-snakesegments 1 
  [
    setxyz x y z
    set pitch random 360
    set prev nobody
    set next nobody
    set temp self
    set snake-id nextid
  ]
  ifelse (nextid = length headlist)
  [ set headlist lput temp headlist ]
  [ set headlist replace-item nextid headlist temp ]
  ask temp [ update-appearance ]
  report temp
end 

to snake-grow
  ; impose a limit of 40 segments, to prevent any student
  ; from going too crazy about snake-length.
  if (count snakesegments with [ snake-id = [snake-id] of myself ] < 40)
  [
    let temp next
    hatch 1 [
      set next temp
      set prev myself
      set temp self
      update-appearance
    ]
    if (not is-tail?)
    [ 
      ask next
        [ set prev temp ]
    ]
    set next temp
    fd 0.55
  ]
end 

to snake-shrink
  ask get-head [
    if (not is-tail?)
    [
      let temp self
      face next
      move-to next
      rt 180
      ask next
      [ 
        if (next != nobody)
        [
          ask next
          [ 
            set prev temp
            set temp self
          ]
        ]
        die
      ]
      set next temp
    ]
  ]
end 

to snake-die
   ask snakesegments with [ snake-id = [snake-id] of myself ]
   [
     die 
   ]
end 

to-report looped?
  report [ prev != nobody ] of get-head
end 

to snake-loop
  ask get-head
  [
    let mytail get-tail
    set prev mytail
    ask mytail [ set next myself ]
    face mytail
    update-appearance
  ]
end 

to snake-unloop
  ask get-head
  [
    let mytail get-tail
    set prev nobody
    ask mytail [ set next nobody ]
    face next
    rt 180
    update-appearance
  ]
end 

to snake-reverse
 ask get-head 
 [
   snake-reverse-helper
   update-appearance
 ]
end 

to snake-reverse-helper
  let temp next
  set next prev
  set prev temp 
  ifelse (prev = nobody or ([is-head?] of prev))
  [ 
    set headlist replace-item snake-id headlist self
    update-appearance
    if (not is-tail?)
    [ face next ]
    right 180
  ]
  [
    ask prev [ snake-reverse-helper]
  ]
end 
; neat little utility function, to get every snakesegment
; in the snake to run some code.

to snake-map [ str ]
  run str
  if (not is-tail?)
  [
    ask next [ snake-map str ]
  ]
end 

to snake-move [ dist ]
  let distprev world-width ; big number
  let mystep dist
  
  ifelse (self = first-mover)
  [
    fd dist
  ]
  [ 
    face prev
    set distprev (distance prev)
    ; we allow them to step up to 25% farther than the
    ; head moved, to allow them to "catch up" if necessary
    ; we don't allow them to move *too* close to
    ; the snakesegment ahead of them.
    set mystep min list (dist * 1.25)  (distprev - 0.55)
    
    if (mystep != 0 )
    [
      fd mystep
    ]
  ]
  if (next != nobody and next != first-mover)
  [
    ask next [ snake-move dist ]  
  ]
end 

to snake-move-bk [ dist ]
  let distnext world-width ; big number
  let mystep dist
 
  ifelse (self = first-mover)
  [
      fd dist
  ]
  [ 
    face next
    set distnext (distance next)
    ; we allow them to step up to 25% farther than the
    ; head moved, to allow them to "catch up" if necessary
    ; we don't allow them to move *too* close to
    ; the snakesegment ahead of them.
    set mystep min list (dist * 1.25)  (distnext - 0.55)
    
    if (mystep != 0 )
    [
      fd mystep
    ]
  ]
  if (prev != nobody and prev != first-mover)
  [
    ask prev [ snake-move-bk dist ]  
  ]
end 

to snake-forward [ dist ]
  if ([move-snake?] of one-of students with [ my-snake-id = [snake-id] of myself ])
  [
    repeat round (dist / 0.1)
    [
      ; even if you ask a snakesegment in the middle
      ; of the snake to move, we move the head anyway
      ask get-head
      [ 
        update-appearance
        set first-mover self
        ifelse (looped?)
        [
            face prev
            snake-move 0.1
        ]
        [
          snake-move 0.1
        ]
      ]
      collision-detection
      display
    ]
  ]
end 

to snake-step
  snake-forward 1
end 

to forward-all [ dist ] 
  repeat round (dist / 0.1)
  [
    ask snakes 
    [ 
      if ([move-snake?] of one-of students with [ my-snake-id = [snake-id] of myself ])
      [
        set first-mover self
        ifelse (looped?)
        [
          face prev
          snake-move 0.1
        ]
        [
          snake-move 0.1
        ]
      ]
    ]
    collision-detection
    display
  ]
end 

to collision-detection
  let clist []
  ask snakesegments
  [
    set tempdx 0
    set tempdy 0
    set tempdz 0
    let pushx 0
    let pushy 0
    let pushz 0
    let myx xcor
    let myy ycor
    let myz zcor
    let nearbys snakesegments in-radius 1.0
    set nearbys nearbys with [prev != myself and next != myself and self != myself]
;    print count nearbys
    if (any? nearbys)
    [
      ask nearbys [
        let dist distance myself
        if (dist = 0)
          [ fd 0.001 set dist 0.001  ]
        let push (1.0 - dist) / 2 + 0.02
        let ddx myx - xcor
        if (ddx < 0 - world-width / 2)
         [ set ddx ddx + world-width ]
        if (ddx > world-width / 2)
         [ set ddx ddx - world-width ]
        let ddy myy - ycor
        if (ddy < 0 - world-height / 2)
         [ set ddy ddy + world-height ]
        if (ddy > world-height / 2)
         [ set ddy ddy - world-height ]
        let ddz myz - zcor
        if (ddz < 0 - world-depth / 2)
         [ set ddz ddz + world-depth ]
        if (ddz > world-depth / 2)
         [ set ddz ddz - world-depth ]
        set pushx pushx + ddx / dist * push
        set pushy pushy + ddy / dist * push
        set pushz pushz + ddz / dist * push
      ]
      set tempdx pushx / count nearbys + random-float 0.01
      set tempdy pushy / count nearbys + random-float 0.01
      set tempdz pushz / count nearbys + random-float 0.01
      set clist fput self clist
      ;show (list tempdx tempdy tempdz)
      
;      show (list tempdx tempdy tempdz)
;    if (tempdx != 0)
;    [ print word "moo: " (list tempdx tempdy tempdz) ]
    ]          
  ]
  foreach clist [
    ask ? [
      set xcor xcor + tempdx
      set ycor ycor + tempdy
      set zcor zcor + tempdz
      
    ]
  ]
end 

to tighten-all
  ask snakes [ snake-reverse ]
  forward-all 0.5
  ask snakes [ snake-reverse ]
  forward-all 0.5
end 

to snake-tighten
  snake-reverse
  snake-forward 0.5
  snake-reverse
  snake-forward 0.5
end 

to jiggle-snakes
  if (not is-list? jigglers or member? nobody jigglers or random 100 < 1)
  [ set jigglers [self] of (n-of 2 snakesegments)
    set jiggler-patches [self] of (n-of 2 patches ) 
  ]
  (foreach jigglers jiggler-patches
  [
    let j ?1
    let jp ?2
    ask j
    [
      ;let nearbys (snakesegments in-radius 2.0) with [prev != myself and next != myself and self != myself]
      ;ifelse any? nearbys
      ;[ face one-of nearbys ]
      ;[ face one-of patches ]
      face jp
      set first-mover self
      forward 0.05      
      if (next != nobody)
      [ ask next [ snake-move 0.1 ] ]
      if (prev != nobody)
      [ ask prev [ snake-move-bk 0.1 ] ]
    ]
  ])
  collision-detection
  display
end 

to save-to-vrml 
  let filename user-new-file 
  if (filename != false)
  [
    vrml:clear-scene
    ask snakesegments [
      let mycolor extract-rgb color
      ; make the head the same color as the body
      ; in the vrml export
      if (is-head?)
        [ set mycolor extract-rgb (color - 2) ]
      vrml:set-color (item 0 mycolor) (item 1 mycolor) (item 2 mycolor)
      vrml:add-sphere xcor ycor zcor 0.5
    ]
    vrml:save-scene filename
  ]
end 
; returns the head of the most recently created snake

to-report newest-snake
  report snake ((length headlist) - 1)
end 

;;; HUBNET procedures
;; determines which client sent a command, and what the command was

to listen-clients
  while [ hubnet-message-waiting? ]
  [
    hubnet-fetch-message
    ifelse hubnet-enter-message?
    [ create-new-student ]
    [
      ifelse hubnet-exit-message?
      [ remove-student ]
      [
        ask students with [ my-hubnet-id = hubnet-message-source ]
          [ execute-command hubnet-message-tag ]
      ]
    ]
  ]
end 

to execute-command [command]
  if command = "move-snake?"
  [
    set move-snake? hubnet-message
    stop
  ]
  if command = "north"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch 0 set heading 0 ] stop ]
  if command = "south"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch 0 set heading 180 ] stop ]
  if command = "east"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch 0 set heading 90 ] stop ]
  if command = "west"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch 0 set heading 270 ] stop ]
  if command = "up"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch 90 ] stop ]
  if command = "down"
  [ ask snake my-snake-id [ rt 90 fd 0.03 set pitch -90 ] stop ]
  ask snake my-snake-id [ 
    run command 
    stop
  ]
end 

to create-new-student
  let newsnake (make-snake random-pxcor random-pycor random-pzcor)
  create-students 1
  [
    ht
    set my-hubnet-id hubnet-message-source
    set my-snake-id [snake-id] of newsnake
    set move-snake? false
    hubnet-send my-hubnet-id "my-snake-color" get-color-name my-snake-id
  ]
end 

to remove-student
  ask students with [my-hubnet-id = hubnet-message-source]
  [
    ask snake my-snake-id [ snake-die ]
    die
  ]
end 

There is only one version of this model, created over 14 years ago by Uri Wilensky.

Attached files

No files

This model does not have any ancestors.

This model does not have any descendants.