J1P70

              The main danger from creating a simple and 
              self-sufficient computer science textbook 
              is that it may suit for bots training.

### THREE WALES AGAIN

##  SPIRAL

Me dunt wanna learn just everything, und only then use it. Me want to know just small enough to start building something. I'll grow my brain muscles up in process. Actually this idea is not mine, i found it here*.

------
*) A long time ago, german philosopher Georg Wilhelm Friedrich Hegel wrote: "Nothing is lost or destroyed but raised up and preserved as in a spiral.".

  https://www.marxists.org/reference/archive/hegel/help/easy.htm
------


##  LAYERS

When programmer stands in front of huge bunch of source codes (buggy but "good enough", she_or_he compares:

  How long would it take to understand every line of this code?
    
with:

  How long would it take to write from scratch only NEEDED features, that are already buried somewhere deep inside this huge existing source texts?
  
Obvious answer should sound like: "we have to build it from scratch". Usually Boss doesn't like it because she_or_he believes in a hidden (invisible from inside) potential of programmer (Cleo and Mark tale*)

------
*) IMDB. Antony and Cleopatra 1972, 2015
------


##  USE WHAT CAN BE USED.

Go to desert, dig a well (fountain if you feel lucky), build a cave, invent the technology, build a spaceship.. Seems nice (when i'm alone i'm still shy.. of my own body) but it takes too long. 

So.. use libraries even in your first 'Hello World' applications :)


### LEVEL 0
-----------

Theory:

  1. Variables
  2. Operations
  3. Flow Control

Practice:

  Build it with Chrome (JavaScript)
  
We need Google Chrome and Notepad++.

The first movements in Chrome.  (Windows)

  1. Open a blank page: URL [ about:blank ]
  
  2. Open the WEB console: ctrl+shift+j  or
     "Hamburger" -> More tools -> Developer Tools -> Console
    
  3. Save the console session: RCLICK -> Save As ..
  
  4. Copy existing code to console: Copy-Paste. (ctrl+c..ctrl+v)
  
  5. The dot after the object name calls autocomplete dropdown list.
  
  6. (Level 1, Windows). To bypass CORS (Cross-Origin Resource Sharing):
   
    + Open the Windows Start Menu
    
    + Type windows+R or open "Run"

    + Execute the following command:

        chrome.exe --user-data-dir="C://Chrome dev session" \
                   --disable-web-security
                   
        google-chrome --disable-web-security (for Linux)
  
That's enough for a moment.


# 1. VARIABLES

Define

  var my_variable;  // Old scope
  let my_variable;  // Block scope

Types

  string   
  
    'string content'
    "double trouble"
    
  number
  
     555
     1.234
     
  boolean
  
     true
     false
     
  array (simple object)
  
    ['two', 'six', true, 'one', 21, 5, false];
  
  array -- it's like a street name: one name but many houses (indexes). Each house may hold one variable.
  
  var sa = ['red', 'green', 'blue'];
  var na = [10, 100, 5];


# OPERATIONS

With numbers:

  op. name       example
  --------------------------
  +   see here*  5 + 2 = 7
  -              5 - 2 = 3
  *              5 * 2 = 10
  /              5 / 2 = 2.5
  %   remainder  5 % 2 = 1
  
*) Alice Cooper. Schools out, 1972

With bits:

"Conceptually, the bitwise logical operators work as follows: The operands are converted to thirty-two-bit integers and expressed by a series of bits (zeros and ones). Numbers with more than 32 bits get their most significant bits discarded."*

------
*) https://developer.mozilla.org/en-US/docs/Web/JavaScript
     /Guide/Expressions_and_Operators#Bitwise
------

  &  -- bitwise AND   10 & 5 = 1010 & 0101 = 0000 =  0
  |  -- bitwise OR    10 | 5 = 1010 | 0101 = 1111 = 15
  ^  -- bitwise XOR   10 ^ 7 = 1010 ^ 0111 = 1101 = 13
  ~  -- bitwise not   
  
         10987654321098765432109876543210
   10 =  00000000000000000000000000001010
  ~10 =  11111111111111111111111111110110
       + 00000000000000000000000000000000

With strings:

  +   concatenate

There are more operators in JavaScript. We'll come back to them on the next levels.


# FLOW CONTROL

Task 1:

   1. Fill an array with 8 random integers with values from 0 to 100
   2. Sort the array from low to high
   3. document.write <array_name>

Solution:

  var a = [];
  var n;
  
  for ( n = 0; n < 8; n++)
    a[n] = Math.floor( Math.random() * 100);
    
  a.sort((x,y)=>(x-y));
  document.close();
  document.write(a);
  
Task 2: Turtle Graphics

  URL: turtle.html

  var N = 12;
  for(var i=0; i<N; i++) {
    forward(200);
    right(180);
    forward(200);
    right(180+360/N);
  }
  
Note. To play with turtle, we need better understanding of school math. Turtle programming is rather trivial, still we may separate list of things turtle knows:

  Level 0:              Level 1:          Level 2:   ..

    forward(distance)   colour(r,g,b,a)   reset()
    right(angle)        left(angle)       clear()
    penup()             width(width)      ..
    pendown()

Task 3. Going 3D. Even before Logo in late 196x-s, Decartes/Cartesius used xyz plan to determine point location*.

------
*) The invention of Cartesian coordinates in the 17th century by Rene Descartes (Latinized name: Cartesius) revolutionized mathematics by providing the first systematic link between Euclidean geometry and algebra.

  https://en.wikipedia.org/wiki/Cartesian_coordinate_system
------

I still believe Seymour Papert would like cylindrical coordinates*.

Thurtles doesn't fly or this is not a flight simulator. Moving the Point_of_View from God to a jet pilot is too cruchy. Cylindrical coordinates modification seems to be the best decision for Turtle3D:

  forward N (always horisontal)
  right/left phi (always horisontal)
  up/down N (elevator)
  climb/descent theta (head, glance)
 
------
*) https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
------

====================================

### FUNCTIONS

Sometimes we need to run some part of our code by firing a single command. Suppose, the code we have is (turtle3D):

  for (var x=-160; x<=160; x+=20) {
     moveto(x, 20, 0);
     drop(egg.SPHERE);
     moveto(0, 20, x);
     drop(egg.SPHERE);
  }

Let's create a new variable "go" to store this code:

  var go = function() {
    for (var x=-160; x<=160; x+=20) {
       moveto(x, 20, 0);
       drop(egg.SPHERE);
       moveto(0, 20, x);
       drop(egg.SPHERE);
    }
  }

1. Save this code as go.js in to the folder with our turtle script:
 
     go.js, ex.html, three.html, OrbitControls.js
     
2. Include go.js into ex.html

    07  <body>
    08    <script src="three.js"></script>
    09    <script src="OrbitControls.js"></script>
    10    
    11    <script src="go.js"></script>
    12    
    13    <script>
    14      var scene, camera, renderer, mesh;
    ..
    
3. Run this code from Chrome's console:

     > go();
     
     
# DEFAULT ARGUMENTS

We already created some function named "go". Now we need to vary the size of the cross it draws, by changing number of eggs and distance between them. If we do not enter this arguments, we should have everything like before (old code)

  var go = function(a=8, s=20) {
    for (var x=-a*s; x<=a*s; x+=s) {
       moveto(x, 20, 0);
       drop(egg.SPHERE);
       moveto(0, 20, x);
       drop(egg.SPHERE);
    }
  }
  
# HOW THE FOR LOOP IS WORKING EXACTLY?

  12  var f = function() {
  13    for (console.log('INIT'), i=0;
  14         console.log('CHECK IS i<3? '+i+'<3'), i<3;
  15         console.log('STEP'), i++
  16        )
  17    {
  18      console.log('BODY i='+i);
  19    }
  20  }
  
Output

  > f();
  02.js:13 INIT
  02.js:14 CHECK IS i<3? 0<3
  02.js:18 BODY i=0
  02.js:15 STEP
  02.js:14 CHECK IS i<3? 1<3
  02.js:18 BODY i=1
  02.js:15 STEP
  02.js:14 CHECK IS i<3? 2<3
  02.js:18 BODY i=2
  02.js:15 STEP
  02.js:14 CHECK IS i<3? 3<3
  undefined

=====================

### PROTOTYPES. DEMONSTRATION OF PROTOTYPAL INHERITANCE

  1. https://hackernoon.com
  /a-definitive-guide-to-javascript-prototypes-2c263788021e
  
NOTE. Nobody reads that far today. Switch to online resouces. Learn by doing. There are nice printed books also:

1. JAVASCRIPT
   FOR KIDS
   A PLAYFUL INTRODUCTION TO PROGRAMMING
   BY NICK MORGAN
   (C) 2015
   ISBN-10: 1-59327-408-4 
   ISBN-13: 978-1-59327-408-5

2. 3D GAME PROGRAMMING FOR KIDS
   Create Interactive Worlds With JavaScript
   Chris Strom
   Edited by Fahmida Y. Rashid
   Copyright (C) 2013 The Pragmatic Programmers, LLC.
   ISBN-13: 978-1-937785-44-4
   
Happy scripting!

---------

# Annex A. turtle 2D

turtle.html

  <!DOCTYPE HTML>
  <!- git clone https://github.com/bjpop/js-turtle -->
  <!- html, css, js files merged                   -->
  <html>
    <head>
    <title>Javascript Turtle</title>
    <style>
      body h1 { text-align:center; }

      #leftcolumn   { float:left;   width:25%; }
      #rightcolumn  { float:left;   width:40%; }
      #turtlecanvas { background:#fff; border: 1px solid black; }
    </style>
    </head>
    <body>
      <h1>Javascript Turtle Graphics</h1>
      <div id="leftcolumn">
        <h4>Language Reference</h4>
        <code>
          forward(distance) <br/>
          right(angle) <br/>
          left(angle) <br/>
          goto(x,y) <br/>
          clear() <br/>
          penup() <br/>
          pendown() <br/>
          reset() <br/>
          angle(angle) <br/>
          width(width) <br/>
          colour(r,g,b,a) <br/>
          write(string) <br/>
          n = random(low,high) <br/>
          hideTurtle() <br/>
          showTurtle() <br/>
          redrawOnMove(bool) <br/>
          draw() <br/>
          repeat(n, action) <br/>
          wrap(bool) <br/>
          animate(action,ms) <br/>
        </code>
      </div> <!-- leftcolumn -->
      <div id="midcolumn">
        <h4>Canvas</h4>
        <canvas id="turtlecanvas" 
                width="600" 
                height="600">
        </canvas>
        <canvas id="imagecanvas" 
                width="600" height="600" 
                style="display:none">
        </canvas>
      </div> <!-- midcolumn -->
    </body>
    <script type="text/javascript">
    // get a handle for the canvases in the document
    var imageCanvas = document.getElementById("imagecanvas");
    var imageContext = imageCanvas.getContext('2d');

    imageContext.textAlign = "center";
    imageContext.textBaseline = "middle";

    var turtleCanvas = document.getElementById("turtlecanvas");
    var turtleContext = turtleCanvas.getContext('2d');

    // the turtle takes precedence when compositing
    turtleContext.globalCompositeOperation = 'destination-over';

    // initialise the state of the turtle
    var turtle = undefined;

    function initialise() {
       turtle = { pos: {
                     x: 0,
                     y: 0
                  },
                  angle: 0,
                  penDown: true,
                  width: 1,
                  visible: true,
                  redraw: true, // does this belong here?
                  wrap: true,
                  colour: {r: 0, g: 0, b: 0, a: 1},
                };
       imageContext.lineWidth = turtle.width;
       imageContext.strokeStyle = "black";
       imageContext.globalAlpha = 1;
    }

    // draw the turtle and the current image if redraw is true
    // for complicated drawings it is much faster to turn redraw off
    function drawIf() {
       if (turtle.redraw) draw();
    }

    // use canvas centered coordinates facing upwards
    function centerCoords (context) {
       var width = context.canvas.width;
       var height = context.canvas.height;
       context.translate(width/2, height/2);
       context.transform(1, 0, 0, -1, 0, 0);
    }

    // draw the turtle and the current image
    function draw() {
       clearContext(turtleContext);
       if (turtle.visible) {
          var x = turtle.pos.x;
          var y = turtle.pos.y;
          var w = 10;
          var h = 15;
          turtleContext.save();
          // use canvas centered coordinates facing upwards
          centerCoords(turtleContext);
          // move the origin to the turtle center
          turtleContext.translate(x, y);
          // rotate about the center of the turtle
          turtleContext.rotate(-turtle.angle);
          // move the turtle back to its position
          turtleContext.translate(-x, -y);
          // draw the turtle icon
          turtleContext.beginPath();
          turtleContext.moveTo(x - w/2, y);
          turtleContext.lineTo(x + w/2, y);
          turtleContext.lineTo(x, y + h);
          turtleContext.closePath();
          turtleContext.fillStyle = "green";
          turtleContext.fill();
          turtleContext.restore();
       }
       turtleContext.drawImage(
          imageCanvas, 
          0, 
          0, 
          600, 
          600, 
          0, 
          0, 
          600, 
          600
       );
    }

    // clear the display, don't move the turtle
    function clear() {
       clearContext(imageContext);
       drawIf();
    }

    function clearContext(context) {
       context.save();
       context.setTransform(1,0,0,1,0,0);
       context.clearRect(
          0,
          0,
          context.canvas.width,
          context.canvas.height
       );
       context.restore();
    }

    // reset the whole system, clear the display and move turtle 
    // back to origin, facing the Y axis.
    function reset() {
       initialise();
       clear();
       draw();
    }

    // Trace the forward motion of the turtle, allowing for possible
    // wrap-around at the boundaries of the canvas.
    function forward(distance) {
       imageContext.save();
       centerCoords(imageContext);
       imageContext.beginPath();
       // get the boundaries of the canvas
       var maxX = imageContext.canvas.width / 2;
       var minX = -imageContext.canvas.width / 2;
       var maxY = imageContext.canvas.height / 2;
       var minY = -imageContext.canvas.height / 2;
       var x = turtle.pos.x;
       var y = turtle.pos.y;
       // trace out the forward steps
       while (distance > 0) {
          // move the to current location of the turtle
          imageContext.moveTo(x, y);
          // calculate the new location of the turtle 
          // after doing the forward movement
          var cosAngle = Math.cos(turtle.angle);
          var sinAngle = Math.sin(turtle.angle)
          var newX = x + sinAngle  * distance;
          var newY = y + cosAngle * distance;
          // wrap on the X boundary
          function xWrap(cutBound, otherBound) {
             var distanceToEdge = Math.abs((cutBound - x) / sinAngle);
             var edgeY = cosAngle * distanceToEdge + y;
             imageContext.lineTo(cutBound, edgeY);
             distance -= distanceToEdge;
             x = otherBound;
             y = edgeY;
          }
          // wrap on the Y boundary
          function yWrap(cutBound, otherBound) {
             var distanceToEdge = Math.abs((cutBound - y) / cosAngle);
             var edgeX = sinAngle * distanceToEdge + x;
             imageContext.lineTo(edgeX, cutBound);
             distance -= distanceToEdge;
             x = edgeX;
             y = otherBound;
          }
          // don't wrap the turtle on any boundary
          function noWrap()
          {
             imageContext.lineTo(newX, newY);
             turtle.pos.x = newX;
             turtle.pos.y = newY;
             distance = 0;
          }
          // if wrap is on, trace a part segment of the path 
          // and wrap on boundary if necessary
          if (turtle.wrap) {
             if (newX > maxX)
                xWrap(maxX, minX);
             else if (newX < minX)
                xWrap(minX, maxX);
             else if (newY > maxY)
                 yWrap(maxY, minY);
             else if (newY < minY)
                yWrap(minY, maxY);
             else
                noWrap();
          }
          // wrap is not on.
          else {
             noWrap();
          }
       }
       // only draw if the pen is currently down.
       if (turtle.penDown)
          imageContext.stroke();
        imageContext.restore();
       drawIf();
    }

    // turn edge wrapping on/off
    function wrap(bool) {
       turtle.wrap = bool;
    }

    // show/hide the turtle
    function hideTurtle() {
       turtle.visible = false;
       drawIf();
    }

    // show/hide the turtle
    function showTurtle() {
       turtle.visible = true;
       drawIf();
    }

    // turn on/off redrawing
    function redrawOnMove(bool) {
       turtle.redraw = bool;
    }

    // lift up the pen (don't draw)
    function penup() { turtle.penDown = false; }
    // put the pen down (do draw)
    function pendown() { turtle.penDown = true; }

    // turn right by an angle in degrees
    function right(angle) {
       turtle.angle += degToRad(angle);
       drawIf();
    }

    // turn left by an angle in degrees
    function left(angle) {
       turtle.angle -= degToRad(angle);
       drawIf();
    }

    // move the turtle to a particular coordinate 
    // (don't draw on the way there)
    function goto(x,y) {
       turtle.pos.x = x;
       turtle.pos.y = y;
       drawIf();
    }

    // set the angle of the turtle in degrees
    function angle(angle) {
       turtle.angle = degToRad(angle);
    }

    // convert degrees to radians
    function degToRad(deg) {
       return deg / 180 * Math.PI;
    }

    // convert radians to degrees
    function radToDeg(deg) {
       return deg * 180 / Math.PI;
    }

    // set the width of the line
    function width(w) {
       turtle.width = w;
       imageContext.lineWidth = w;
    }

    // write some text at the turtle position.
    // ideally we'd like this to rotate the text based on
    // the turtle orientation, but this will require some clever
    // canvas transformations which aren't implemented yet.
    function write(msg) {
       imageContext.save();
       centerCoords(imageContext);
       imageContext.translate(turtle.pos.x, turtle.pos.y);
       imageContext.transform(1, 0, 0, -1, 0, 0);
       imageContext.translate(-turtle.pos.x, -turtle.pos.y);
       imageContext.fillText(msg, turtle.pos.x, turtle.pos.y);
       imageContext.restore();
       drawIf();
    }

    // set the colour of the line using RGB values in the range 0 - 255.
    function colour (r,g,b,a) {
        imageContext.strokeStyle = 
           "rgba(" + r + "," + g + "," + b + "," + a + ")";
        turtle.colour.r = r;
        turtle.colour.g = g;
        turtle.colour.b = b;
        turtle.colour.a = a;
    }

    // Generate a random integer between low and hi
    function random(low, hi) {
       return Math.floor(Math.random() * (hi - low + 1) + low);
    }

    function repeat(n, action) {
       for (var count = 1; count <= n; count++)
          action();
    }

    function animate(f,ms) {
       return setInterval(f, ms);
    }

    function setFont(font) {
       imageContext.font = font;
    }

    reset();
    </script>

  </html>

EOF

Example:

  var sun = function (r) {
    var N = 50;
    penup();
    forward(r);
    right(90+180/N);
    pendown();
    for( let i=0; i<N; i++) {
      forward(2*r*Math.sin(Math.PI/N));
      right(360/N);
    }
    penup();
    right(90-180/N);
    forward(r);
    right(180);
    pendown();
  }
  
  var rainbow = function (a) {
    switch (a) {
      case 0: colour( 143, 0, 255, 1); break;
      case 1: colour( 0, 0, 255, 1); break;
      case 2: colour( 0, 255, 255, 1); break;
      case 3: colour( 0, 255, 0, 1); break;
      case 4: colour( 255, 255, 0, 1); break;
      case 5: colour( 255, 127, 0, 1); break;
      case 6: colour( 255, 0, 0, 1); break;
    }
  }
  
  colour(255,0,0,1);
  width(20);
  for( let i=0; i<7; i++) {
    rainbow(i);
    sun(10+20*i);
  }

------------------------------------------------------------------------

# DRAFT

J21

# Organizing data

  point = {
    x: 0,
    y: 0,
    z: 0
  }

# Center is p

  var go = function(a=8, s=20, p={x:0,y:0,z:0}) {
    for (var x=-a*s; x<=a*s; x+=s) {
       moveto(x, p.y, p.z);
       drop(egg.SPHERE);
       moveto(p.x, p.y, x);
       drop(egg.SPHERE);
    }
  }

  // go(6,5,{x:0,y:0,z:0});
  
# types of eggs available in three.js

  $ cat three.js | \
    grep -P '\.constructor = [A-Z][a-z]+BufferGeometry;' | \
    grep -oP '[A-Za-z]+;' | cat -n
     1  BoxBufferGeometry;
     2  PlaneBufferGeometry;
     3  ParametricBufferGeometry;
     4  PolyhedronBufferGeometry;
     5  TetrahedronBufferGeometry;
     6  OctahedronBufferGeometry;
     7  IcosahedronBufferGeometry;
     8  DodecahedronBufferGeometry;
     9  TubeBufferGeometry;
    10  TorusBufferGeometry;
    11  ExtrudeBufferGeometry;
    12  TextBufferGeometry;
    13  SphereBufferGeometry;
    14  RingBufferGeometry;
    15  LatheBufferGeometry;
    16  ShapeBufferGeometry;
    17  CylinderBufferGeometry;
    18  ConeBufferGeometry;
    19  CircleBufferGeometry;
    
  -o, --only-matching
    Print  only  the matched (non-empty) parts of a matching line, with each such part on a separate output line.
    
  -P, --perl-regexp
    Interpret the pattern as a Perl-compatible regular expression (PCRE).  This is experimental and grep -P may warn of unimplemented features.

  1. https://stackoverflow.com/questions/1546711
       /can-grep-show-only-words-that-match-search-pattern
