Harvard’s CS50 – Intro to Computer Science, Week 0

I started Harvard’s CS50 course through EdX today. I was introduced to a really impressive (and fun) GUI scripting interface called Scratch. I was pleasantly surprised at how easy it is to use, and that it contains all the building blocks for programming. My only issue is that it relies on Flash, which is leaving the web very very quickly.

For this week’s homework I added googly eyes to Joseph Ducreux and gave him a bow tie that plays funky music. Clearly I am poised to take over the world with this enterprise-level code.

Advertisements
Harvard’s CS50 – Intro to Computer Science, Week 0

Why I Switched to Capricorn XS PTFE Tubing

In 2018-style, this is not a sponsored post. I’m simply very impressed by this product and I want to share why.

Earlier this year I began experimenting with PETG on my Monoprice Maker Select Plus (MMSP). The MMSP is a direct-drive printer with a 34mm PTFE tube that guides the filament through the heat break and into the nozzle. The PETG I was using required a temperature of 245C to flow properly. However, the PTFE that came with the MMSP was not up to the task and it began to deteriorate in short order.

If you’ve not had a PTFE melt down the easiest way to tell there’s a problem is that the filament starts to act as though there’s a clog. You can clean the nozzle all day long, but the problem is that the PTFE is becoming gummy. The other problem is that PTFE is teflon, and vaporized teflon is not something humans should be breathing (as happens when PTFE tubing overheats to the point of losing its integrity).

I am deeply resistant to the refrain of “just get an all-metal hot end!!”. For every person whose printing hobby is saved by an all-metal, just as many find that they regret spending the money and that they wasted their time. I am also cheap. While searching for alternatives to the white PTFE that came with the MMSP I quickly found reference to Capricorn.

Capricorn’s XS PTFE tubing is reportedly able to retain its integrity up to 260C, which is (for all intents a purposes) well above the temperature I intend to print at. It’s also $12 per meter. The MMSP requires 34mm of tubing. That 34mm of tubing put me back in business and my PETG printed flawlessly. That alone is enough to prompt me to evangelize the product.

I also run a Creality CR-10S, which is an indirect/Bowden tube design. With this machine I’ve been using a 1.0mm nozzle to print terrain pieces. The increased size lets me print the same weight of filament in a fraction of the time. For example, a 25-piece run took 49 hours using a standard 0.4mm nozzle. The second time I was able to do it in 17 hours with the 1.0mm nozzle. I have taken advantage of being able to put more filament through the hardware.

Today my prints almost indicated that there was a clog (!!) in the nozzle. They had terrible line width, the perimeter overlap was almost nonexistent, I had all manner of blobs/zits (and this was with retraction, coasting AND extra restart distances set in Simplify3D). My infill was garbage. Rectilinear and Fast Honeycomb looked like someone carelessly laid some filament into the cavity of the print. But how is a 1.0mm nozzle going to get a non-fatal performance-reducing clog? (It does happen with 0.4mm nozzles.)

I noticed a slight grinding sound, like something was catching somewhere. I isolated the sound to the stock PTFE tube. As I still had the better part of a meter of Capricorn XS I cut a section to length and installed. I’ve only heated PLA with this printer and I haven’t exceeded 225C for any print, so I figure the PTFE was simply wearing out from friction. I’ve been running this printer at least 20 hours a week since the end of November 2017 and have emptied not less than 10 rolls of PLA. Probably any replacement PTFE would have done the job. Be that as it may, the Capricorn PTFE made an immediate difference. My initial layer line widths are nice and wide, the infill Wiggle pattern is crisp, and overall there appear to be no underextrusion issues.

I’m hopeful this PTFE has added wear resistance on account of it being a more slippery product; so much so it’s tangible. Simply holding the Capricorn feels more slippery than any of the white tubing I have, even after I’ve wiped the Capricorn to remove any potential oil residue. I will update when I feel I need to replace the tubing again.

Why I Switched to Capricorn XS PTFE Tubing

Thoughts on Data Structures Related to Linked Lists, in the Key of Python

Apologies in advance for the wonky formatting.
This started as a gist at https://gist.github.com/KMSkelton/1b1c0ecf59d8b7406e3495f831184ad1
and I decided to also make it a blog post for easier reference. It
turns out gists are not easy to get to via Github on my phone.

I am using Python3 because it is better suited for data structures
than is JavaScript. I understand there may be some code formatting
issues that betray my background in JavaScript, and I am happy to
discuss best practices. The mea culpa and ado concluded…

A linked list is a collection of data comprised of nodes. 
Each node is either empty or it contains "cargo" and a reference
 to the next node in the list (for a singly linked list) or 
references to the next node and the previous node (for a doubly 
linked list). The advantage to linked lists is that we do not have
 to allocate memory to them; the nodes will add themselves to 
memory wherever they have room. Insertions are super fast [O(1)] 
as are removals because we typically work from the ends. 
The trade off is that the entire list has to be traversed to find 
the data being requested, so all find operations are O(n). 
There are no external references to locations in a linked list 
(unlike an array which is indexed and is contiguous in memory).
This is the most basic form of a node in a linked list:
class Node:
  def __init__(self, cargo=None, next=None):
     self.cargo = cargo
     self.next = next
     
  def __str__(self):
    return str(self.cargo)

node1 = Node(1)
node2 = Node(2)
node3 = Node(3)

This inserts three integers into three locations that are 
patterned after the Node class above. It will be more useful if we
are able to retrieve more than one item that we already know the 
location of (i.e. let's add links).

node1.next = node2
node2.next = node3

This is OK for brute force creation of the most basic of linked 
lists. As it is we can search for a Node if we know it's there, 
but we can't return a list or remove a Node.
A little functional panache will make things easier for searching 
and updating the list. From the top we'll establish all the 
properties of the Node: 

class Node:
  def __init__(self, cargo=None, next=None):
     self.cargo = cargo
     self.next = next
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val

#Next we need to be able to make and modify the linked list itself
#this prints as a STACK or first-in last-out (FILO) or 
# Last In First Out (LIFO) implementation

  def __init__(self,head=None):
    self.head = head
    self.size = 0
  
  def getSize(self):
    return self.size
    
  def addNode(self, cargo): # Typically stacks call this a push
    newNode = Node(cargo, self.head)
    self.head = newNode
    self.size += 1
    return True
    
  def printNodes(self):
    current = self.head
    while current:
      print(current.cargo)
      current = current.nextNode()

# Alias LinkedList as myList to make things slightly easier      
myList = LinkedList()
myList.addNode(4)
myList.addNode(50)
myList.addNode(37)
myList.printNodes() # 37 50 4

# Let's simply discover whether a value exists in the linked list 
# (True or False). This is done by traversing through each
# node and comparing node.cargo to the value in question. 

def findNode(self,value):
  current = self.head
  #as long as there is a 'self' this process will continue
  while current: 
    #compare the cargo to the value 
    if current.getCargo() == value:
      return True
    current = current.nextNode()
  return False

# Finally let's remove a node from the list. We'll need to keep 
# track of where we are (current) and where we've been (previous) 
# This removal step begins with a search, so the worst case 
# scenario is this will take O(n) time.

def removeNode(self, value): #Typically this operation is called pop
    previous = None
    current = self.head
    
    while current:
      if current.getCargo() == value:
        if previous:
          previous.setNextNode(current.nextNode())
        else:
          self.head = current.nextNode()
        return True
        
      previous = current
      current = current.nextNode()
      
    return False
    
# Time to make this a more traditional linked list where each new 
# node is added as a tail
# This prints as a First In First Out (FIFO) structure, also 
# called a QUEUE
# Making the Node class stays the same

class Node:
  def __init__(self, cargo):
     self.cargo = cargo
     self.next = None 
# Note this is slightly different from above. No reason other than
# to demonstrate that both ways work
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val
    
# and now we need a tail
class LinkedList: 
  def __init__(self):
    self.head = None
    self.tail = None
    self.size = 0
  
  def getSize(self):
    return self.size
    
# Specifically it is the adding of nodes that is different than before. 
# Adding a node to the tail is called "enqueueing" while removing
# the head node is "dequeueing"
# I am maintaining the continuity in my verbiage to make these
# examples as easy to relate to each other as possible

  def addNode(self, cargo):
    
    # make sure the cargo is in the correct format as a Node
    cargo = Node(cargo)
            
    if ( self.head == None ):
      self.head = cargo
    else:
      self.tail.next = cargo
      
    self.tail = cargo
    return True

  def printNodes(self):
    current = self.head
    while current:
      print(current.cargo)
      current = current.nextNode()

# Finding and removing work the same as before: 

def findNode(self,value):
  current = self.head
  while current: 
    #compare the cargo to the value 
    if current.getCargo() == value:
      return True
    current = current.nextNode()
  return False

def removeNode(self, value):
    previous = None
    current = self.head
    
    while current:
      if current.getCargo() == value:
        if previous:
          previous.setNextNode(current.nextNode())
        else:
          self.head = current.nextNode()
        return True
        
      previous = current
      current = current.nextNode()
      
    return False
    
#The Doubly Linked List (DLL) adds a reference to the previous Node
class Node:
  def __init__(self, cargo):
     self.cargo = cargo
     self.next = None
     self.prev = None
     
  def getCargo(self):
    return self.cargo
  
  def setCargo(self, val):
    self.cargo = val
    
  def nextNode(self):
    return self.next
    
  def setNextNode(self,val):
    self.next = val
    
  def prevNode(self):
    return self.prev
    
  def setPrevNode(self,val):
    self.prev = val

# Now we have to consider some edge cases as well as keep track of where we are

class DoublyLinkedList: 
  def __init__(self):
    self.head = None
    self.tail = None
    self.size = 0
  
  def getSize(self):
    return self.size
    
  def addNode(self, cargo):
    newNode = Node(cargo)
    if (self.head == None):
      self.head = self.tail = newNode
    else:
      newNode.prev = self.tail
      newNode.next = None
      self.tail.next = newNode
      self.tail = newNode
    self.size += 1
    
  def removeNode(self, value):
    currentNode = self.head 
    
    while currentNode is not None:
      if currentNode.cargo == value:
        if currentNode.prev is not None:
          currentNode.prev.next = currentNode.next
          currentNode.next.prev = currentNode.prev
        else:
          self.head = currentNode.next
          currentNode.next.prev = currentNode.prev
          
      currentNode = currentNode.next
      self.size -= 1
      
  def printNodes(self):
    currentNode = self.head
    
    while currentNode is not None:
      print(" prev: {}\n cargo: {}\n next: {} ".format(
      currentNode.prev.cargo if hasattr( currentNode.prev, "cargo") else None,
      currentNode.cargo,
      currentNode.next.cargo if hasattr( currentNode.next, "cargo") else None))
      
      currentNode = currentNode.next
    return True

And there we have it. Linked Lists can be implemented in a brutish manner, or as a stack or queue. Further, adding references to where the previous node is allows us to traverse the list (potentially) faster than if we only know where the next node is.

Thoughts on Data Structures Related to Linked Lists, in the Key of Python

Does CSS Absolute Positioning Just Make Things Big?

Screen Shot 2017-12-13 at 11.18.04 AM

It looks like absolute positioning is a shortcut for adding a bunch of padding to an element making an element huge. My PM was testing some changes to our controls layout. He showed me his phone and asked why he couldn’t reliably mute the player.

What I discovered is that the timer was blocking access to the volume/mute toggle. The blue box above is for the timer’s container. The volume icon has a z-index of 5. That timer box had a z-index of 7; changing the z-index to 3 unblocked the toggle.
[edit: a team member suggested also a “height” rule to the element, which allows the element to accept the positioning while also restraining its dimensions.] 
Does CSS Absolute Positioning Just Make Things Big?

Gaming Terrain, revisited (and a note about paint)

In my last post on the topic I said I preferred Open Forge/Printable scenery because of the walls. This is still mostly true.
However, the folks at fat dragon games really stepped up their game with a kickstarter that just ended. In addition to kickstarting some large pieces, they basically gave away their castle and offered all of their previous dungeon and cavern terrain at a discount. How could I say no?  Further, the lady of the house was able to buy almost 10 boxes of Master Maze terrain for a really good price, so we’ll have that to play with, too.  It’s a hard plaster but it matches the look of the Dwarvenite that Dwarven Forge now uses. The Fat Dragon model files are very similar (not tooooo similar, though) so we’ll be able to fill in any gaps in the collection if need be. Otherwise we can focus on printing pieces that are completely different from what’s in the DF line. Yes, I will need to figure out reasonable storage, but trading card boxes are inexpensive and seem to be working.

As mentioned previously the 3D printed pieces come off the printer in the color of the filament that they’re printed in.  This is handy for putting things on the table quickly – brown filament makes for trees that look close enough. But what to do when there’s “downtime” and the pieces need to be painted?  Luke at Luke’s Affordable Paint Service released a video a few months ago in which he discussed using primer for minis. Most importantly he said he warms the cans in hot tap water before using them. I was skeptical that it would be better than house-temperature, but gave it a try.
If you’re using rattle can primer, you need to be warming your cans before shaking them. Primers go on really smoothly and evenly, like nothing I’ve experienced in all my years of using rattle can paint. I accidentally grabbed a can that I should have thrown away months ago because it always clogged and sprayed in blobs. After 20 minutes in a pot of hot tap water I realized my “mistake” but figured a few test sprays would put the theory to the test. The paint sprayed in a perfect fine mist and when I put it on the model it looked spectacular.  Here’s a link to the video.

Game on!

Gaming Terrain, revisited (and a note about paint)

Is Google Testing Vehicle Traffic Load Balancing?

Screen Shot 2017-08-23 at 9.47.34 AM

Put on your tinfoil hat. This past weekend was “The Great American Eclipse” and it truly was amazing. Almost as unbelievable as eclipse totality was the traffic on the return trip to Seattle. And we think Google made things worse for us.

This is the town of Donald, it’s between Salem and Tigard. Google told us that leaving the freeway in favor of local roads would save us 1h11m and we would avoid a car wreck. It took over 2 hours for us to complete the trip back to I-5. Bad directions, or a shortcut that isn’t, is understandable. However, because my girlfriend keeps her phone in a hands free cradle I couldn’t see the directions, so I opened the directions on my phone. “Looks like yet another uncontrolled left coming up”
“Nuh uh. It says go straight.”
What? Refresh. Turn left vs go straight. Still. OK that was just a fluke, right?

We made it through the line of cars, which took twenty minutes to move as many car lengths. Butterville to Fargo to Bents To Arndt. “This says it’ll cost an hour and forty-nine if we go straight.”
“Mine says we save a half hour by going straight.”
Great. We turned left. Into a ridiculous line of cars. At times we paralleled I-5 and traffic was … moving?! It was going at a steady 15MPH. There was no sign of a wreck, which should have been visible from the bypass road we were on.  Meanwhile we’re moving one car length every five minutes.

Our situation was not helped by a complete lack of cell data, despite three and four bars showing on our phones. When we returned to the freeway, Google again offered a detour which we firmly declined. We couldn’t help but notice that our estimated time savings’ were different again.

I’m conjecturing that Google was trying to load balance the vehicle traffic on August 21, 2017. By tempting us with a huge time savings (really a ridiculous time savings, but we figured they were overestimating) Google removed us and hundreds of other cars from the main thoroughfare. I suspect they may be testing an algorithm for their autonomous vehicle projects; one which needs tweaking to better estimate the capacity of these two lane roads. If they assume a certain market saturation for their software in autonomous vehicles they will want to work to ensure that dense traffic takes advantage of the pressure relief offered by side roads.

Is Google Testing Vehicle Traffic Load Balancing?