<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<generator uri="http://jekyllrb.com" version="3.1.6">Jekyll</generator>
<link href="http://jrsaathoff.com/feed.xml" rel="self" type="application/atom+xml" />
<link href="http://jrsaathoff.com/" rel="alternate" type="text/html" />
<updated>2017-12-20T17:04:17-06:00</updated>
<id>http://jrsaathoff.com/</id>
<subtitle>My little home on the web</subtitle>
<entry>
<title>Martian Dice Game</title>
<link href="http://jrsaathoff.com/martian_dice_game.html" rel="alternate" type="text/html" title="Martian Dice Game" />
<published>2016-02-19T00:00:00-06:00</published>
<updated>2016-02-19T00:00:00-06:00</updated>
<id>http://jrsaathoff.com/martian-dice-game</id>
<content type="html" xml:base="http://jrsaathoff.com/martian_dice_game.html">&lt;div class=&quot;row control-group&quot;&gt;
&lt;div class=&quot;form-group col-md-3 floating-label-form-group controls&quot;&gt;
    &lt;button class=&quot;btn btn-default&quot; id=&quot;newgame&quot; onclick=&quot;newgame()&quot;&gt;New Game&lt;/button&gt;
&lt;/div&gt;
&lt;div class=&quot;form-group col-md-3 floating-label-form-group controls&quot;&gt;
     &lt;button class=&quot;btn btn-default&quot; onclick=&quot;toggleScores()&quot;&gt;Toggle Scores&lt;/button&gt;
&lt;/div&gt;
&lt;div class=&quot;form-group col-md-1 floating-label-form-group controls&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;form-group col-md-3 floating-label-form-group controls&quot;&gt;
    &amp;nbsp;Dice:&lt;input type=&quot;text&quot; id=&quot;dice&quot; class=&quot;form-control&quot; value=&quot;13&quot; /&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;currentScore&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;board&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;expectedScore&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;warning&quot;&gt;&lt;/div&gt;

&lt;h3 id=&quot;rules&quot;&gt;Rules&lt;/h3&gt;

&lt;p&gt;The rules are pretty straight forward.  For every roll of the dice you have to take all the tanks, and then you have to take one of the remaining types of dice.  You can always take rays, but each of the earthling types can only be taken once.  After taking, you’ll have the choice to re-roll or stop playing.  If you choose to show expected scores, it’ll show the expected score for each roll and for taking each different type of die. &lt;a href=&quot;{{ site.imgpath }}/md_sample_turn_alt.jpg&quot;&gt;Here’s&lt;/a&gt; an image to an example turn, and a full descripition of the rules &lt;a href=&quot;{{ site.imgpath }}/md_rules.pdf&quot;&gt;simple&lt;/a&gt; as well.&lt;/p&gt;

&lt;h3 id=&quot;options&quot;&gt;Options&lt;/h3&gt;

&lt;p&gt;The game comes with thirteen dice in the box.  But, I’ve set up the game to have a configurable number of dice, with a maximum of twenty-six.&lt;/p&gt;

&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;

&lt;p&gt;I decided I wanted to play around with server side scripting, javascript, ajax, etc…, and in order to do it I decided to expand a bit on the examination of Maritan Dice I’d done in a &lt;a href=&quot;http://www.jrsaathoff.com/posts/martian-dice.html&quot;&gt;previous post&lt;/a&gt;.  This simple game would help me figure out how to get all the different network compentents working together before I attempt something more complicated.&lt;/p&gt;

&lt;script type=&quot;text/javascript&quot;&gt;

var T, S, Tstring, Rstring, turn;
var N;      // The number of free dice remaining
var R;      // The current roll of dice
var turn;   // The first roll is turn 0

// When scores is true, the expected score will be reported
var scores = true;
var rolled = false;
var current_score;

// The webpage will have several buttons and fields on the page for manipulation
// &lt;button id=&quot;newgame&quot; onclick=&quot;newgame()&quot;&gt;New Game&lt;/button&gt;
// &lt;button onclick=&quot;toggleScores()&quot;&gt;Toggle Scores&lt;/button&gt;
// &lt;div id=&quot;current&quot;&gt;&lt;/div&gt;
// &lt;div id=&quot;board&quot;&gt;&lt;/div&gt;
// &lt;div id=&quot;score&quot;&gt;&lt;/div&gt;
// &lt;div id=&quot;warning&quot;&gt;&lt;/div&gt;

// the divs will all be empty until newgame() is clicked

function intToChar(val) {
	return &#39;zyxwvutsrqponmlkjihgfedcba0ABCDEFGHIJKLMNOPQRSTUVWXYZ&#39;.charAt(val+26);
}

function toggleScores() {
	scores = ! scores;
	genScores();
}

function validMove(ref, T, R) {
	if ((R[ref]&gt;0)&amp;&amp;((ref==1)||((T[ref]==0)&amp;&amp;(ref&gt;1)))) {
		return true;
	} else {
		return false;
	}
}

function getExpectedScore(N, T) {
	// Use local rather than global values of N (number free), T (taken dice)
	// T  R  1  2  3
	var query_freeDice   = N;
	var query_deltaTanks = T[0]-T[1];
	var query_earthlings = T[2]+T[3]+T[4];
	var query_typesTaken = 0;
	for (var i = 2; i &lt; 5; i++) {
		if (T[i]&gt;0) { query_typesTaken += 1; }
	}
	var resultText = &#39;&#39;;
	//text += intToChar(query_freeDice);
	//text += intToChar(query_deltaTanks);
	//text += intToChar(query_typesTaken);
	//text += intToChar(query_earthlings);

	u = &#39;http://jrsaathoff.com/files/md_expected_values/&#39;;
	u += intToChar(query_freeDice);
	u += intToChar(query_deltaTanks);
	u += intToChar(query_typesTaken);
	u += intToChar(query_earthlings);
	u += &#39;.txt&#39;;

	//$.get(u, function( text ) {
	//});

	$.ajax({
			type: &#39;GET&#39;,
			url: u,
			contentType: &#39;text/plain&#39;,
			xhrFields: {
				withCredentials: false
			},
			// Async is necessary, otherwise the script continues before the
			// value is returned and nothing is displayed elsewhere
			async: false,
			//dataType: &#39;json&#39;,
			headers: {
			},

			success: function(result) {
			//success: function(result) {
				resultText = result;
			//alert (resultText)
			},

			error: function() {
				resultText = &#39;connection error&#39;;
			}
		});
	return resultText;
}

function genScores() {
	// T  R  1  2  3
	// Take all tanks and reduce number of free dice
	T[0] += R[0];
	N    -= R[0];
	R[0]  = 0;

	// Calculate current Score
	currentScore = 0;
	if (T[0] &lt;= T[1]) {
		currentScore = T[2]+T[3]+T[4];
		if (T[2]&gt;0 &amp;&amp; T[3]&gt;0 &amp;&amp; T[4]&gt;0) { currentScore += 3; }
	}
	$(&quot;#currentScore&quot;).html(&#39;&lt;h3&gt;Score:&amp;nbsp;&#39;+currentScore+&#39;&lt;/h3&gt;&#39;);

	// If expected scores aren&#39;t to be calculated, we&#39;re done
	if (! scores) {
		$(&quot;#expectedScore&quot;).html(&#39;&#39;);
		return;
	}

	// Iterate through the different types of dice.  Each time checking if it&#39;s a valid move
	// and if so, adding that image and score to the html
	var text = &#39;&lt;h3&gt;Expected Score: &lt;/h3&gt;&#39;;
	if (rolled) {
		for (var i=1; i&lt;5; i++) {
			if (validMove (i, T, R)) {
				// &#39;Take&#39; the appropriate dice, and retrieve the expected score
				// Slice copies by value rather than by reference so the original T is unchanged
				newN     = N - R[i];
				newT     = T.slice();
				newT[i] += R[i];
				text += &#39;&lt;img src=&quot;http://jrsaathoff.com/files/md_diceimg_&#39;+i+&#39;_sm.png&quot; id=&quot;dice_&#39;+i+&#39;&quot; ondblclick=&quot;take(&#39;+i+&#39;)&quot; &quot;=&quot;&quot;&gt;&amp;nbsp;&#39;;
				text += getExpectedScore (newN, newT)
				text += &#39;&lt;br&gt;&#39;
			}
		}
	} else {
		text += &#39;&lt;img src=&quot;http://jrsaathoff.com/files/md_diceimg_roll_sm.png&quot; ondblclick=&quot;roll()&quot; &quot;=&quot;&quot;&gt;&amp;nbsp;&#39;
		text += getExpectedScore (N, T)
	}
	$(&quot;#expectedScore&quot;).html(text);
}

function genBoard() {
	var text = &#39;&#39;
	if (turn) {
		text += &#39;&lt;h3&gt;Taken:&lt;/h3&gt;&#39;
		for (var i = 0; i &lt; 5; i++) {
			for (var j = 0; j &lt; T[i]; j++) {
				text += &#39;&lt;img src=&quot;http://jrsaathoff.com/files/md_diceimg_&#39;+i+&#39;.png&quot;&gt;&#39;;
			}
		}
	}
	if (rolled) {
		text += &#39;&lt;h3&gt;Rolled:&lt;/h3&gt;&#39;;
		//alert(R[0]+&#39;,&#39;+R[1]+&#39;,&#39;+R[2]+&#39;,&#39;+R[3]+&#39;,&#39;+R[4]);
		for (var i = 0; i &lt; 5; i++) {
			for (var j = 0; j &lt; R[i]; j++) {
				text += &#39;&lt;img src=&quot;http://jrsaathoff.com/files/md_diceimg_&#39;+i;
				if (i&gt;0) {
					text += &#39;.png&quot; id=&quot;dice_&#39;+i+&#39;&quot; ondblclick=&quot;take(&#39;+i+&#39;)&quot;&gt;&#39;
				} else {
					text += &#39;.png&quot;&gt;&#39;
				}
			}
		}
	} else {
		text += &#39;&lt;h3&gt;Reroll: &lt;/h3&gt;&#39;
		for (var i=0; i&lt;N; i++) {
			text += &#39;&lt;img src=&quot;http://jrsaathoff.com/files/md_diceimg_roll.png&quot; id=&quot;dice_roll&quot; ondblclick=&quot;roll()&quot;&gt;&#39;
		}
	}
	$(&quot;#board&quot;).html(text);
}

function roll() {
	// Reset the current roll of dice and roll N dice
	R = [0,0,0,0,0];
	for (var i = 0; i &lt; N; i++) {
		var j = Math.floor(Math.random() * 6);
		if (j == 5) { j = 1; }  // The rays show up twice on the dice
		R[j] += 1;
	}

	rolled = true;
	genBoard();
	genScores();
}

function newgame() {
	// T  R  1  2  3
	T = [0, 0, 0, 0, 0];
	// Change the button from &#39;new game&#39; to &#39;restart&#39; and get the number of dice to
	// use from the field.  Set to default (13) if N&lt;1 or N&gt;26
	$(&quot;#newgame&quot;).html(&#39;Restart&#39;);
	N = $(&quot;#dice&quot;).val();
	if ((N&gt;26) || (N&lt;1)) {
		N = 13;
		$(&quot;#dice&quot;).val(13);
	}
	// Reset a few additionanl things and then roll dice
	turn = 0;
	current_score = 0;
	$(&quot;#warning&quot;).html(&#39;&#39;);
	roll();
}

function take(ref) {
	var taken= false;
	var ts   = &#39;&#39;;

	// Check if allowed.  Can always take rays (ref==1)
	if (validMove(ref, T, R)) {
		taken   = true;
		turn   += 1;
		T[ref] += R[ref];
		N      -= R[ref];
		for (var i=0; i&lt;5; i++) { R[i] = 0; }
		rolled  = false;

		genBoard();
		genScores();
		$(&quot;#warning&quot;).html(&#39;&#39;);
	} else {
		$(&quot;#warning&quot;).html(&#39;&lt;h3&gt;This is not a valid move&lt;/h3&gt;&#39;);
	}
}


&lt;/script&gt;

</content>
<summary>    New Game     Toggle Scores    &amp;nbsp;Dice:</summary>
</entry>
<entry>
<title>Texas Park Campground Availability</title>
<link href="http://jrsaathoff.com/posts/txpark.html" rel="alternate" type="text/html" title="Texas Park Campground Availability" />
<published>2015-10-01T00:00:00-05:00</published>
<updated>2015-10-01T00:00:00-05:00</updated>
<id>http://jrsaathoff.com/posts/tx-park-scraper</id>
<content type="html" xml:base="http://jrsaathoff.com/posts/txpark.html">&lt;p&gt;It’s camping season in Texas.  And, already, all the campgrounds near me are fully booked every weekend for the foreseeable future.  People tend to cancel their reservations occasionally, but since there’s no notification system in place through the park service, the only way to discover this is to regularly visit the website, then look at the schedule for each potential two week time period for each potential campground.  It a tedious process and takes up quite a bit of time.&lt;/p&gt;

&lt;p&gt;So, I created a script that will regularly scrape the campground availability from the park website and post it in the table below.  The last time the page was updated is shown and all weekends are highlighted in green. For each day and each campground the total number of non-primitive sites (left) and primitive sites (right) are listed.&lt;/p&gt;

&lt;div class=&quot;row control-group&quot;&gt;
	&lt;div class=&quot;form-group col-md-4 floating-label-form-group controls&quot;&gt;
&lt;select name=&quot;aa&quot; onchange=&quot;updateTable(this.value)&quot;&gt;
  &lt;option value=&quot;default&quot;&gt;default&lt;/option&gt;
  &lt;option value=&quot;219&quot;&gt;Abilene SP&lt;/option&gt;
  &lt;option value=&quot;110&quot;&gt;Atlanta SP&lt;/option&gt;
  &lt;option value=&quot;164&quot;&gt;Balmorhea SP&lt;/option&gt;
  &lt;option value=&quot;180&quot;&gt;Bastrop SP&lt;/option&gt;
  &lt;option value=&quot;1&quot;&gt;Blanco SP&lt;/option&gt;
  &lt;option value=&quot;4&quot;&gt;Bonham SP&lt;/option&gt;
  &lt;option value=&quot;50&quot;&gt;Brazos Bend SP&lt;/option&gt;
  &lt;option value=&quot;31&quot;&gt;Buescher SP&lt;/option&gt;
  &lt;option value=&quot;19&quot;&gt;Caddo Lake SP&lt;/option&gt;
  &lt;option value=&quot;217&quot;&gt;Caprock Canyons SP&lt;/option&gt;
  &lt;option value=&quot;112&quot;&gt;Cedar Hill SP&lt;/option&gt;
  &lt;option value=&quot;123&quot;&gt;Choke Canyon SP&lt;/option&gt;
  &lt;option value=&quot;145&quot;&gt;Cleburne SP&lt;/option&gt;
  &lt;option value=&quot;169&quot;&gt;Colorado Bend SP&lt;/option&gt;
  &lt;option value=&quot;39&quot;&gt;Cooper Lake SP Doctors Creek&lt;/option&gt;
  &lt;option value=&quot;36&quot;&gt;Cooper Lake SP South Sulphur&lt;/option&gt;
  &lt;option value=&quot;67&quot;&gt;Copper Breaks SP&lt;/option&gt;
  &lt;option value=&quot;12&quot;&gt;Daingerfield SP&lt;/option&gt;
  &lt;option value=&quot;90&quot;&gt;Davis Mountains SP&lt;/option&gt;
  &lt;option value=&quot;13&quot;&gt;Dinosaur Valley SP&lt;/option&gt;
  &lt;option value=&quot;61&quot;&gt;Eisenhower SP&lt;/option&gt;
  &lt;option value=&quot;79&quot;&gt;Enchanted Rock SNA&lt;/option&gt;
  &lt;option value=&quot;185&quot;&gt;Fairfield Lake SP&lt;/option&gt;
  &lt;option value=&quot;187&quot;&gt;Falcon SP&lt;/option&gt;
  &lt;option value=&quot;56&quot;&gt;Fort Parker SP&lt;/option&gt;
  &lt;option value=&quot;160&quot;&gt;Fort Richardson SP&lt;/option&gt;
  &lt;option value=&quot;5703&quot;&gt;Galveston Island SP&lt;/option&gt;
  &lt;option value=&quot;156&quot;&gt;Garner SP&lt;/option&gt;
  &lt;option value=&quot;22&quot;&gt;Goliad SP&lt;/option&gt;
  &lt;option value=&quot;190&quot;&gt;Goose Island SP&lt;/option&gt;
  &lt;option value=&quot;99&quot;&gt;Government Canyon SNA&lt;/option&gt;
  &lt;option value=&quot;7&quot;&gt;Guadalupe River SP&lt;/option&gt;
  &lt;option value=&quot;88&quot;&gt;Hill Country SNA&lt;/option&gt;
  &lt;option value=&quot;117&quot;&gt;Huntsville SP&lt;/option&gt;
  &lt;option value=&quot;102&quot;&gt;Inks Lake SP&lt;/option&gt;
  &lt;option value=&quot;5810&quot;&gt;Kickapoo Cavern SP&lt;/option&gt;
  &lt;option value=&quot;75&quot;&gt;Lk Arrowhead SP&lt;/option&gt;
  &lt;option value=&quot;223&quot;&gt;Lk Bob Sandlin SP&lt;/option&gt;
  &lt;option value=&quot;194&quot;&gt;Lk Brownwood SP&lt;/option&gt;
  &lt;option value=&quot;29&quot;&gt;Lk Casa Blanca International SP&lt;/option&gt;
  &lt;option value=&quot;114&quot;&gt;Lk Colorado City SP&lt;/option&gt;
  &lt;option value=&quot;47&quot;&gt;Lk Corpus Christi SP&lt;/option&gt;
  &lt;option value=&quot;136&quot;&gt;Lk Livingston SP&lt;/option&gt;
  &lt;option value=&quot;85&quot;&gt;Lk Mineral Wells SP&lt;/option&gt;
  &lt;option value=&quot;172&quot;&gt;Lk Somerville SP Birch Creek&lt;/option&gt;
  &lt;option value=&quot;177&quot;&gt;Lk Somerville SP Nails Creek&lt;/option&gt;
  &lt;option value=&quot;167&quot;&gt;Lk Tawakoni SP&lt;/option&gt;
  &lt;option value=&quot;42&quot;&gt;Lk Whitney SP&lt;/option&gt;
  &lt;option value=&quot;9&quot;&gt;Lockhart SP&lt;/option&gt;
  &lt;option value=&quot;95&quot;&gt;Lost Maples SNA&lt;/option&gt;
  &lt;option value=&quot;129&quot;&gt;Martin Creek Lake SP&lt;/option&gt;
  &lt;option value=&quot;132&quot;&gt;Martin Dies Jr. SP&lt;/option&gt;
  &lt;option value=&quot;25&quot;&gt;Mckinney Falls SP&lt;/option&gt;
  &lt;option value=&quot;203&quot;&gt;Meridian SP&lt;/option&gt;
  &lt;option value=&quot;210&quot;&gt;Mission Tejas SP&lt;/option&gt;
  &lt;option value=&quot;226&quot;&gt;Monahans Sandhills SP&lt;/option&gt;
  &lt;option value=&quot;120&quot;&gt;Mother Neff SP&lt;/option&gt;
  &lt;option value=&quot;153&quot;&gt;Mustang Island SP&lt;/option&gt;
  &lt;option value=&quot;174&quot;&gt;Palmetto SP&lt;/option&gt;
  &lt;option value=&quot;208&quot;&gt;Palo Duro Canyon SP&lt;/option&gt;
  &lt;option value=&quot;77&quot;&gt;Pedernales Falls SP&lt;/option&gt;
  &lt;option value=&quot;82&quot;&gt;Possum Kingdom SP&lt;/option&gt;
  &lt;option value=&quot;54&quot;&gt;Purtis Creek SP&lt;/option&gt;
  &lt;option value=&quot;96&quot;&gt;Ray Roberts Lk SP Isle Du Bois&lt;/option&gt;
  &lt;option value=&quot;83&quot;&gt;Ray Roberts Lk SP Johnson Branch&lt;/option&gt;
  &lt;option value=&quot;141&quot;&gt;San Angelo SP&lt;/option&gt;
  &lt;option value=&quot;5971&quot;&gt;Sea Rim SP&lt;/option&gt;
  &lt;option value=&quot;163&quot;&gt;Seminole Canyon SP&lt;/option&gt;
  &lt;option value=&quot;171&quot;&gt;South Llano River SP&lt;/option&gt;
  &lt;option value=&quot;198&quot;&gt;Stephen F. Austin SP&lt;/option&gt;
  &lt;option value=&quot;70&quot;&gt;Tyler SP&lt;/option&gt;
  &lt;option value=&quot;214&quot;&gt;Village Creek SP&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;div id=&quot;test&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;results&quot;&gt;&lt;/div&gt;

&lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js&quot;&gt;&lt;/script&gt;

&lt;!-- Bootstrap Core JavaScript --&gt;
&lt;script type=&quot;text/javascript&quot;&gt;


function updateTable(campId) {
	u = &quot;http://jrsaathoff.com/files/parkscan/parkscan_&quot;+campId+&quot;.txt&quot;;
 	console.log(u);

	$.ajax({
			type: &#39;GET&#39;,
			url: u,
			contentType: &#39;text/plain&#39;,
			xhrFields: {
			  withCredentials: false
			},
			//dataType: &#39;json&#39;,
			headers: {
			},

			success: function(result) {
			  document.getElementById(&quot;results&quot;).innerHTML = result;
			},

			error: function() {
			  document.getElementById(&quot;results&quot;).innerHTML = result+&#39;server connection error&#39;;
			}
	  });
}

updateTable(&#39;default&#39;)

&lt;/script&gt;

</content>
<summary>It’s camping season in Texas.  And, already, all the campgrounds near me are fully booked every weekend for the foreseeable future.  People tend to cancel their reservations occasionally, but since there’s no notification system in place through the park service, the only way to discover this is to regularly visit the website, then look at the schedule for each potential two week time period for each potential campground.  It a tedious process and takes up quite a bit of time.</summary>
</entry>
<entry>
<title>Martian Dice Statistical Analysis</title>
<link href="http://jrsaathoff.com/posts/martian-dice.html" rel="alternate" type="text/html" title="Martian Dice Statistical Analysis" />
<published>2015-01-19T00:00:00-06:00</published>
<updated>2015-01-19T00:00:00-06:00</updated>
<id>http://jrsaathoff.com/posts/martian-dice</id>
<content type="html" xml:base="http://jrsaathoff.com/posts/martian-dice.html">&lt;h3 id=&quot;about-the-game&quot;&gt;About The Game&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://www.coolstuffinc.com/p/138977&quot;&gt;Martian Dice&lt;/a&gt; is a fun little dice game with more strategy and player choice than a lot of similar games, like Zombie Dice.  You’re playing the alien invaders, equipped with death rays, and are out to abduct as many earthlings as possible.  The humans are equipped with tanks to defend against you.&lt;/p&gt;

&lt;p&gt;The game has thirteen dice, each of which has on it’s six sides: Tank, 2 x Death Ray, Human , Chicken, Cow.  For the rest of this post, to make the dice representation a bit easier, I’ll represent a dice roll by TTA:TTRRRAAACB (A: Human, B:Chicken, C:Cow).  The dice to the left of the colon have been taken in a previous turn, the dice to the right are freshly rolled.&lt;/p&gt;

&lt;p&gt;The rules of the game are relatively &lt;a href=&quot;/{{ site.imgpath }}/md_rules.pdf&quot;&gt;simple&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Roll all the available dice.&lt;/li&gt;
  &lt;li&gt;Set aside all tanks, adding them to any set aside previously.&lt;/li&gt;
  &lt;li&gt;From the remaining dice, choose &lt;strong&gt;one&lt;/strong&gt; type.  Humans, chickens, or cows can not be chosen if they have been taken previously.  Death Rays can always be chosen.&lt;/li&gt;
  &lt;li&gt;If any dice remain, you can return to step one and reroll, or choose to stop playing and proceed to scoring.  If you were unable to take any dice, or no dice remain, proceed to scoring.&lt;/li&gt;
  &lt;li&gt;Score.  If there are more tanks than death rays, then the score for the turn is zero.  Otherwise, each human, chicken, or cow dice is worth one point.  If you grabbed at least one of all three earthling types, then you get an additional three points.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An example turn (taken from the instructions):&lt;/p&gt;
&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_sample_turn_alt.jpg  12 %}
&lt;/div&gt;

&lt;h3 id=&quot;motivation&quot;&gt;Motivation&lt;/h3&gt;
&lt;p&gt;I almost always bring along this game when I go camping.  It’s fast to teach to new players, it’s easily washable, and has more player decisions than a normal dice game.  I was losing quite a lot of games (I tend to push my luck more than I should) and realized I didn’t have a good intuitive grasp on the impact my decisions would make in the game.  So, I decided to investigate some of the in-game choices that are hardest for me to make, and at the same time try to create a &lt;em&gt;perfect&lt;/em&gt; computer player that would understand all the probabilities and, at each decision tree, would make the choice that would maximize his score.&lt;/p&gt;

&lt;h3 id=&quot;probability-to-survive-a-reroll&quot;&gt;Probability to Survive a Reroll&lt;/h3&gt;
&lt;p&gt;The first thing is to look at the probabilities of different dice rolls.  The order of the dice is not important, only the number of each dice that is rolled.  So, I needed to determine both the total number of different dice combinations for a given number of free dice (N), and the probability that a particular combination will be rolled.  These are given by the following two equations, and good explanation for which can be found &lt;a href=&quot;http://www.mathsisfun.com/combinatorics/combinations-permutations.html&quot;&gt;here&lt;/a&gt;:&lt;/p&gt;

$$\begin{align*} 
C &amp;= \frac{1}{24}\frac{(N+4)!}{N!}\\
P &amp;= 2^{R}\frac{(T+R+A+B+C)!}{T! \; R! \; A! \; B! \; C!}
\end{align*}$$

&lt;p&gt;One thing I wanted to determine was the probability, for any given combination of dice, that a reroll would result in a loss.  The player choice in this game makes any kind of probability calculation difficult, so I’m assuming for all the following work that the player always makes the &lt;em&gt;best&lt;/em&gt; choice (in this case the choice that maximizes his survival probability).  This probability depends only on the number of excess tanks (ΔT), how many types of earthlings have already been taken (E), and the number of free dice remaining (N).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In the simplest case, TTTTRRRRAAAA:?, where there is only one free dice, as many death rays as tanks, and only one type of earthling taken, we only need to examine one die to determine the probability of winning.  The dice has five options, the probability of rolling a death ray is &lt;script type=&quot;math/tex&quot;&gt;\frac{1}{3}&lt;/script&gt;, and &lt;script type=&quot;math/tex&quot;&gt;\frac{1}{6}&lt;/script&gt; for all others.  The only roll that would result in a loss is a tank, so the probability of surviving in this case is &lt;script type=&quot;math/tex&quot;&gt;\frac{5}{6}&lt;/script&gt; or 0.83.  In the equation below, the right column is all the combinations with the same survival probability, the middle is the probability of rolling one of the listed combinations, and the left is the survival probability for the given combination.&lt;/p&gt;
&lt;/blockquote&gt;

$$\begin{align} N=0\\ \Delta T=0 \\ E=1 \end{align} ,\ \quad  P_S = \left\{ \begin{array}{lll}
         0 &amp; \frac{1}{6}&amp;T\\
         1 &amp; \frac{5}{6}&amp;R,A,B,C\end{array} \right. ,\ \quad P_S = \frac{5}{6}$$

&lt;blockquote&gt;
  &lt;p&gt;A more complicated example, TTTTTRRRRA:???, takes a bit more work to calculate.  In order to win, the player must get at least a single R.  And, since there are multiple dice, rerolls have to be taken into consideration.  For this example, there are four different cases to be considered: lose, win, one dice to reroll, two dice to reroll.  In both of the reroll cases, a single death ray and no tanks would considered a successful reroll.  Here there are 35 possible combinations, and the probability of rolling a particular combination varies.  The total probability is then given by, for each combination, summing the probability of the combination times the probability of surviving that combination.  Ihe survival probability for this example is 0.614.&lt;/p&gt;
&lt;/blockquote&gt;

$$\begin{align} N=3\\ \Delta T=1 \\ E=1 \end{align} ,\ \quad  P_S = \left\{ \begin{array}{lll}
         0 &amp; \frac{23}{108}&amp;TTT,TTR,TTC,TTB,TTA,TCC,TBC,\\
          &amp;&amp; TBB,TAC,TAB,CCC,BBB,AAA\\
         1/3 &amp;\frac{21}{108}&amp; TRC,TRB,TRA,ACC,ABB\\
         52/108 &amp;\frac{9}{108}&amp; BCC,BBC,ABC,AAC,AAB\\
         1 &amp; \frac{55}{108}&amp;TRR,RRR,RRC,RRB,RRA,RCC,\\
         &amp;&amp; RBC,RBB,RAC,RAB,RAA\end{array} \right.$$

&lt;p&gt;The previous case is about as far out as I was willing to go with hand calculation, but I was willing to spend the time to write a perl program to recursively calculate everything for me.  For any given combination of dice, it will follow steps very similar to the above examples.  It will calculate the probability of occurrence for each combination of N dice.  Then, for each of those combinations, it will calculate the probability of losing.  Whenever presented with a choice (EG: Taking death rays or chickens), it calculates the probabilities for each of the different valid choices, and then takes the one that maximizes the value.  Finally, it determines the actual probability of survival using the equations in the previous section.  I matched the results of the program to the values I calculated by hand, and always found them to match exactly.&lt;/p&gt;

&lt;p&gt;The following table shows the probability that a reroll will result in a win.  It isn’t taking score into consideration, it’s only looking at whether there are more tanks than death rays at the end of the game.  So, it would consider a game of TTRR a win, even though the score is zero.  The plot is excess tanks (T-R) VS number of free dice (N).&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_survivalprob_n1_exact.png 12 %}
&lt;/div&gt;

&lt;p&gt;The rules state that a single earthling type can never be taken more than once per game.  To see how this would affect the survival probability, I calculated it for the case of having taken one, two, and again for all three earthling types.  I was surprised to find that the number already taken before rolling had very little effect, only making a noticeable difference in the cases with very few free dice.  Below are heatmaps done, on the same scales, for both one and three earthlings already taken.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_survivalprob_n1.png %}
    {% gen_img md_survivalprob_n3.png %}
    &lt;div class=&quot;col-md-2&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;col-md-8&quot;&gt;Survival probability.  E=1 and E=3 (number of earthlings taken before rerolling).&lt;/div&gt;
&lt;/div&gt;

&lt;h3 id=&quot;expectation-score&quot;&gt;Expectation Score&lt;/h3&gt;
&lt;p&gt;My next goal was to try to figure out the expectation score for any given dice distribution.  In other words, if a set combination of dice was perfectly played an infinite number of times, the average of all those games would be the expectation score.  The process to calculate it is almost identical to the previous section.  As before, I set the computer to calculate out the expectation scores for all possible dice combinations and then compared it’s results to a small selection of hand calculated results.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Looking at the same case used in the earlier example, TTTTRRRRAAAA:?, where there is only one free dice, as many death rays as tanks, and only one type of earthling taken, we only need to examine one die to determine the expectation score.  There are three possible cases to consider: losing, returning the same score, or returning an increased score.  The expectation score in this case is 3.67, and since the current score is 4, a reroll would most likely result in a lower score.&lt;/p&gt;
&lt;/blockquote&gt;

$$\begin{align} N=0\\ \Delta T=0 \\ E=1 \end{align} ,\ \quad  P_S = \left\{ \begin{array}{lll}
  0 &amp; \frac{1}{6}&amp; T\\
  4 &amp;\frac{1}{2}&amp; R,A\\
  5 &amp;\frac{1}{3}&amp; B,C\end{array} \right.$$

&lt;p&gt;The expectation score for a game of Martian Dice is 3.11.&lt;/p&gt;

&lt;h3 id=&quot;first-roll&quot;&gt;First Roll&lt;/h3&gt;
&lt;p&gt;I wanted to answer the the question, “which dice do I take on the very first roll?”  I have always found this to be the most difficult of the game.  Frequently I’ll roll a large number of death rays and no tanks, or a few tanks and a large number of earthlings.  In the death ray situation, I never could figure out whether it’s best to take the death rays as a buffer against future tanks, or pass on them with the hope of getting a more valuable roll later.&lt;/p&gt;

&lt;p&gt;The following tables are the calculated expectation scores for a first roll, where no dice have been taken.  Plotted is the number of tanks rolled VS the number of death rays or earthlings taken, followed by the probabilty for the same plots.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_expect_score_RvsT.png %}
    {% gen_img md_expect_score_AvsT.png %}
    &lt;div class=&quot;col-md-2&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;col-md-8&quot;&gt;Expectation for a first roll.  Rolled Tanks VS Death Rays or Earthlings.  I&#39;ve capped the color scale at 7, so for the A plot 7-12 are all the same shade of yellow.&lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_roll_prob_RvsT.png %}
    {% gen_img md_roll_prob_XvsT.png %}
    &lt;div class=&quot;col-md-2&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;col-md-8&quot;&gt;Probabilty for the first roll.  The plot has the same axis as the above.&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A complete list of all 2380 first roll combinations, along with the various expectation scores, is located &lt;a href=&quot;/{{ site.imgpath }}/md_expect_first_roll.txt&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;perfect-player&quot;&gt;Perfect Player&lt;/h3&gt;
&lt;p&gt;Next I set up a computer player to play the game.  It would keep rolling as long as it’s current score was less than the expectation score.  Whenever a choice needed to be made, it would consider all the options and pick the one that maximizes it’s score.  An example of this process is below.&lt;/p&gt;

&lt;p&gt;{% highlight console %}
ROLLED:         T=1   R=4   A=1   B=5   C=2 
SCORES:               R=4.5 A=2.9 B=4.8 C=3.4
  Taking B with score 4.77
LOOP:     N=7   T=1   R=0   A=0   B=5   C=0
-
ROLLED:         T=0   R=3   A=2   B=2   C=0 
SCORES:               R=7.2 A=5.7 B=0.0 C=0.0
  Taking R with score 7.16
LOOP:     N=4   T=1   R=3   A=0   B=5   C=0
-
ROLLED:         T=0   R=3   A=1   B=0   C=0 
SCORES:               R=5.3 A=8.0 B=0.0 C=0.0
  Taking A with score 8.04
LOOP:     N=3   T=1   R=3   A=1   B=5   C=0
-
ROLLED:         T=0   R=0   A=0   B=2   C=1 
SCORES:               R=0.0 A=0.0 B=0.0 C=10.0
  Taking C with score 10
LOOP:     N=2   T=1   R=3   A=1   B=5   C=1
-
FINSIHED:       T=1   R=3   A=1   B=5   C=1
FINAL SCORE: 10
{% endhighlight %}&lt;/p&gt;

&lt;p&gt;I let the program run for a a million iterations, and I came up with some numbers for the &lt;em&gt;perfect&lt;/em&gt; player.  The average score for a game is the same as the expection score, 3.11.  27% of games will end in a loss, and the average score for the winning games was 4.25.  A histogram showing the score breakdown for one million games is below.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img md_scores_histogram.png %}
&lt;/div&gt;

&lt;h3 id=&quot;interactive-game&quot;&gt;Interactive Game&lt;/h3&gt;

&lt;p&gt;I created an &lt;a href=&quot;http://www.jrsaathoff.com/martian_dice_game.html&quot;&gt;interactive version&lt;/a&gt; of the game as well.  In addition to playing traditionally, it’ll report the expectation scores for each of the different rolls as you play.  So, think of it as a Martian Dice trainer, just in case you’re planning to go pro.&lt;/p&gt;
</content>
<summary>About The Game</summary>
</entry>
<entry>
<title>Guadalupe Mountains Trip Report</title>
<link href="http://jrsaathoff.com/posts/gmnp.html" rel="alternate" type="text/html" title="Guadalupe Mountains Trip Report" />
<published>2014-12-29T00:00:00-06:00</published>
<updated>2014-12-29T00:00:00-06:00</updated>
<id>http://jrsaathoff.com/posts/gmnp</id>
<content type="html" xml:base="http://jrsaathoff.com/posts/gmnp.html">&lt;p&gt;I took a road trip out to Guadalupe Mountains National Park a few weeks ago with a couple friends of mine for some mid-December backpacking.  It’s a ten hour drive from Houston to GMNP and on the way is Balmorhea State Park, a place I’ve been wanting to visit for years.  So, with the excuse to break up the drive to GMNP, we decided to stay the first night at &lt;a href=&quot;http://tpwd.texas.gov/state-parks/balmorhea&quot;&gt;Balmorhea State Park&lt;/a&gt;, which is only eight hours away from houston.&lt;/p&gt;

&lt;h3 id=&quot;balmoreah-state-park&quot;&gt;Balmoreah State Park&lt;/h3&gt;
&lt;p&gt;The main appeal of this park is the unique pool, which was built by the Civilian Conservation Corps in the 1930s.  It’s a huge pool, filled by a natural spring, and equipped with several diving boards and water depths ranging from four to twenty-five feet.  The pool is filled with native fish that swim along with you, the concrete walls are covered in algae, and you can see the rocky bottom through the clear water.  But, most importantly, the water is 72-76 degrees year round, so it’s a great travel destination even during the winter.&lt;/p&gt;

&lt;p&gt;The park rangers said that the place is packed during the summer, but otherwise it’s usually not very crowded.  We were the only people that stayed overnight in the park, and despite spending several hours at the pool, we only saw two other people come and go.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC110103.jpg %}
    {% gen_img PC110143.jpg %}
&lt;/div&gt;
&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC110010.jpg 4 %}
    {% gen_img PC110139.jpg 4 %}
    {% gen_img PC110152.jpg 4 %}
&lt;/div&gt;

&lt;p&gt;The park has standard camp ground, but we opted to stay in one of the park’s cabins, positioned along the stream coming from the pool. The cabin was equipped with a shower, heater, three queen beds, and a grill.  And, since it’s only two hours away from GMNP, it’s a perfect luxury stop-over before beginning a backpacking trip the next morning.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC110154.jpg %}
    {% gen_img PC120163.jpg %}
&lt;/div&gt;

&lt;h3 id=&quot;guadalupe-mountains-national-park&quot;&gt;Guadalupe Mountains National Park&lt;/h3&gt;
&lt;p&gt;GMNP is a pretty barebones park.  I never made it to Dog Canyon, which is in the North, but the amenities in the rest of the park are pretty limited.  There are no showers (the Pilot Travel Stop in Van Horn has them for $12), no gas stations, no restaurants, and no stores.  There is no burning in the campgrounds, not even charcoal (propane stoves are allowed).  All the campgrounds and backpacking permits in the park are available on a first-come first-serve basis.&lt;/p&gt;

&lt;p&gt;In October the trees change color, making that the most busy time of the year for this park.  When we visited in December, there seemed to be few crowds and an abundance of bored park rangers.  So, although that meant we had our permits checked by several random rangers before we got onto the trail, they were all eager to talk about our plans and recommend their favorite parts of the trail.  We decided to backpack from McKittrick Canyon to Pine Springs, staying at the Tejas and McKittrick Ridge backcountry campgrounds, followed by a day hike to Guadalupe Peak, and car camping the last night at Pine Springs.&lt;/p&gt;

&lt;h1 id=&quot;mckittrick-canyon-to-pine-springs&quot;&gt;McKittrick Canyon to Pine Springs&lt;/h1&gt;
&lt;p&gt;We were fortunate to have two vehicles, otherwise this trip wouldn’t have been as easy.  There are no shuttles from Pine Springs to McKittrick Canyon (there was a good amount of vehicle traffic so hitchhiking might be an option), but since we had two vehicles we left one in Pine Springs and drove the other to the trailhead at McKittrick Canyon.  There are no water sources in the backcountry, and the NPS recommends one gallons of water per day above dehydrated food requirements.  The dehydrated meals I took to eat would require approximately 2L, and I took out 8L above that for drinking directly, which proved to be just about perfect since I ended the hike with only half a liter remaining.  All that water meant the first day was pretty rough with several thousand feet of elvation gain and a pack weight of approximately fifty pounds.&lt;/p&gt;

&lt;h1 id=&quot;mckittrick-canyon-to-mckittrick-ridge&quot;&gt;McKittrick Canyon to McKittrick Ridge&lt;/h1&gt;

&lt;p&gt;The first part of the hike takes you through the bottom of the canyon along a dry wash surrounded by the towering canyon walls.  As you progress, a stream appears and suddenly instead of the typical desert vegetation, deciduous trees appear, including oaks and maples.  This part of the trail is a pretty easy hike without much elevation change.  Along the way you’ll pass the Pratt Cabin, and after a total of 3.4 miles, you’ll reach The Grotto.  It’s a small limestone “cave” with stalagmites and stalactites, and although the name grotto implies a historic use by humans, I couldn’t find anything on the history of the site that explains where the name came from.  In any case, there are some gorgeous stone picnic tables here to take a break and have lunch before starting the difficult accent to the McKittrick Ridge.  It’ll be another four miles, along the steepest trail in the park, before reaching the campground.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC120177.jpg %}
    {% gen_img PC120187.jpg %}
    {% gen_img PC120201.jpg %}
    {% gen_img PC120210.jpg %}
    {% gen_img PC120214.jpg %}
    {% gen_img PC120217.jpg %}
&lt;/div&gt;

&lt;p&gt;Shortly after leaving the Grotto, the trail changes from a nice easy path, to switchbacks.  Nothing but switchbacks.  We started this part of the hike late in the day (approximately 2pm), and the trail was almost completely in the shade.  You’ll have some amazing views of the canyon as you slowly climb, and if you pay attention to the rocks here you’ll see an abundance of fossils in the limestone layers, formed from the ancient Caspian reef.  After the switchbacks, there’s still about of mile of hiking before reaching the well marked campground.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC120223.jpg 4 %}
    {% gen_img PC120229.jpg 4 %}
    {% gen_img PC130357.jpg 4 %}
    {% gen_img PC120221.jpg 4 %}
    {% gen_img PC120233.jpg 4 %}
    {% gen_img PC120247.jpg 4 %}
    {% gen_img PC120257.jpg %}
    {% gen_img DSCN5478.jpg %}
&lt;/div&gt;

&lt;p&gt;This campground has eight sites, most of which are in fairly close proximity to each other.  The tent pads are well marked, and there’s penty of trees here, so hammock camping wasn’t a problem.  The night we were there the temperature only reached about 50°F, and the wind posed no problem at all.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC130298.jpg %}
    {% gen_img PC130300.jpg %}
&lt;/div&gt;

&lt;h1 id=&quot;mckittrick-ridge-to-tejas&quot;&gt;McKittrick Ridge to Tejas&lt;/h1&gt;

&lt;p&gt;There’s a great spot to view the sunrise right outside the campground along the main trail (turn left on the main trail from the campground, and there’s a great viewing spot on a rock ledge just past the slight ascent).&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC130274.jpg 4 %}
    {% gen_img PC130276.jpg 4 %}
    {% gen_img PC130294.jpg 4 %}
&lt;/div&gt;

&lt;p&gt;Although exhausted from the previous day, this was still a pretty nice easy hike.  It was only 5.8 miles, and we faced significantly less elevation change than from the previous day.  The hike traversed the ridge in many spots, giving breathtaking views of the valley before descending down into tree cover and switching to the tejas trail.  The trail merges with a white stone wash in many places, but it was never too difficult to identify.  Hiking along the tree covered trail, we soon passed the Mescalo campground, and later arrived to the Tejas campground.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC130313.jpg %}
    {% gen_img PC130332.jpg %}
    {% gen_img PC130371.jpg %}
    {% gen_img PC130380.jpg %}
    {% gen_img PC130388.jpg %}
    {% gen_img PC130399.jpg %}
&lt;/div&gt;

&lt;p&gt;We hadn’t seen anyone else along the trail so far, so were were a bit surprised to find to other backpackers at this site.  Although friendly enough, we each set up on opposite sides of the rather large campground.  There were still plenty of trees here for hammock camping, but I found that the locations of most of the pads were slightly too far away from trees for easy hammock setup.  That said, I still had no problem finding a spot to set up.  This night the temperature got down to approximately 30°F (there was a touch of ice in my water bottle the next morning).  Also, the lower elevation and abundance of trees meant there weren’t any issues with wind blasting through the campsite.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC130409.jpg %}
    {% gen_img PC130414.jpg %}
    {% gen_img PC140425.jpg %}
&lt;/div&gt;

&lt;p&gt;We timed this camping trip just about perfect, because the night we stayed in this backcountry campground was the expected peak of the Geminid meteor shower, and due to the low light pollution present in the park (particularly in the backcountry) we had an amazing view.  I saw probably half a dozen meteors in the short time I was watching, several of which were the brightest I’ve ever seen.&lt;/p&gt;

&lt;p&gt;#Tejas to Pine Springs&lt;/p&gt;

&lt;p&gt;We decided that we wanted to summit the Guadalupe Peak as soon as we completed this hike, so we did a quick hike out that morning.  With hardly any food or water remaining in the pack, we were able to make really good time down the 5.5 mile trail to the Pine Springs trailhead, completing it in approximately three hours.&lt;/p&gt;

&lt;p&gt;The last few miles of the trail go down a rather steep decline.  The trail is very exposed, and the winds were absolutely brutal.  Several times I had to grab onto rocks to avoid being knocked down by the gusts of wind.&lt;/p&gt;

&lt;p&gt;Since the campsites are first-come first-serve, we went ahead and grabbed one before heading up to Guadalupe Peak as a day hike.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC140459.jpg %}
    {% gen_img PC140486.jpg %}
&lt;/div&gt;

&lt;h1 id=&quot;guadalupe-peak&quot;&gt;Guadalupe Peak&lt;/h1&gt;

&lt;p&gt;Done as a day hike, this is a 8.4 mile hike, with approximately 3000 ft of elevation change.  The NPS says that it should take 6-8 hours,&lt;/p&gt;

&lt;p&gt;It took us longer to get ready to go out on the trail than expected, so we didn’t get started on the trail until close to 2 p.m.  Based on our times for the previous days, we were pretty confident we could make it back off the trail before sunset, but brought our headlamps and cold weather gear just in case.  It ended up taking us 4.5 hours (the NPS says it’s generally 6-8 hours), which put us back at the trailhead right as the sun was setting.  As a day hike, it’s 8.4 miles and approximately 3000 feet of elevation change.&lt;/p&gt;

&lt;p&gt;Other than the elevation change, the trail was easy, with no scrambling, all the way to the summit.  The wind in certain sections of the trail was brutal.  Several times on the trail I ended up dropping to the ground to avoid being pushed around by the gusts of wind.  At the campground, the wind was gusting at 50 Mph, and it must have been at least that on the trail we were hiking.  Surprisingly, despite how bad the wind was on the trail, the peak had very little wind at all.&lt;/p&gt;

&lt;p&gt;The views from the summit was amazing.  Strangely, the summit marker has a giant American Airlines logo on it (it was installed before it became a national park), but the marker itself looks really cool and is a great photo op with the views in the background.  Even here, at the highest point in Texas, you can look at the rock and see a lot of fossils embedded in the limestone that forms the peak.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC140579.jpg %}
    {% gen_img PC140599.jpg %}
&lt;/div&gt;
&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC140499.jpg 4 %}
    {% gen_img PC140506.jpg 4 %}
    {% gen_img PC140589.jpg 4 %}
&lt;/div&gt;

&lt;p&gt;Unsurprisingly, we made much better time on the descent, and reached the bottom of the trail just in time to catch the sunset.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img PC140624.jpg 4 %}
    {% gen_img PC140641.jpg 4 %}
    {% gen_img PC150664.jpg 4 %}
&lt;/div&gt;
</content>
<summary>I took a road trip out to Guadalupe Mountains National Park a few weeks ago with a couple friends of mine for some mid-December backpacking.  It’s a ten hour drive from Houston to GMNP and on the way is Balmorhea State Park, a place I’ve been wanting to visit for years.  So, with the excuse to break up the drive to GMNP, we decided to stay the first night at Balmorhea State Park, which is only eight hours away from houston.</summary>
</entry>
<entry>
<title>Ruben’s Tube</title>
<link href="http://jrsaathoff.com/rubenstube.html" rel="alternate" type="text/html" title="Ruben&#39;s Tube" />
<published>2010-03-01T00:00:00-06:00</published>
<updated>2010-03-01T00:00:00-06:00</updated>
<id>http://jrsaathoff.com/rubens-tube</id>
<content type="html" xml:base="http://jrsaathoff.com/rubenstube.html">&lt;p&gt;&lt;a href=&quot;http://www.roymontalvo.com/rj.html&quot;&gt;Roy Montalvo&lt;/a&gt; and I made a Rubens Tube for the 2010 Texas A&amp;amp;M Physics Festival.  We will be demonstrating it to students over a wide range of ages, from elementary to college level.&lt;/p&gt;

&lt;h3 id=&quot;what-is-a-rubens-tube&quot;&gt;What is a Rubens Tube?&lt;/h3&gt;
&lt;p&gt;A &lt;a href=&quot;http://en.wikipedia.org/wiki/Rubens%27_Tube&quot;&gt;Ruben’s Tube&lt;/a&gt; is a long metal tube with small holes drilled along its length.  A speaker or signal generator is mounted in one end and the other end is capped.  Propane is fed into the tube and the small holes are lit on fire.&lt;/p&gt;

&lt;p&gt;Sound is a pressure wave, so as it moves through a gas it alternately compresses and expands the gas in different regions.  When a constant tone at one of a set of particular frequencies is sent through the speaker, a &lt;a href=&quot;http://en.wikipedia.org/wiki/Standing_wave&quot;&gt;standing wave&lt;/a&gt; can form.  A standing wave causes areas of high pressure to appear at fixed points along the pipe, spaced half-wavelengths apart. Where the pressure is high, the propane is driven more strongly out of the pipe, resulting in a tall flame.  Between these high-pressure points will be low-pressure points, which create lower flames.&lt;/p&gt;

&lt;h3 id=&quot;our-tube&quot;&gt;Our Tube&lt;/h3&gt;
&lt;p&gt;When we first constructed the tube we were worried about having too little gas flow, so we drilled the holes along the top of the pipe every inch.  With the holes spaced this far apart we found that an individual hole, if the flame was extinguished, would take a long time to relight from its neighbors.  This was a serious problem since we wanted to be able to rapidly change the tones, so we reduced the spacing to half an inch and found that to work well.  Any closer than a half inch and the flames tended to merge together.&lt;/p&gt;

&lt;p&gt;We soldered fittings onto the side of the pipe at each end for the propane lines.  Most of the Rubens Tubes I’ve seen use the end opposing the speaker as the gas inlet, but having an inlet on each end would have the propane more evenly distributed over the length of the pipe.  We capped one end of the pipe and closed off the other with a stretched latex membrane (a surgical glove).  We decided to use a membrane and an external speaker rather than seal a speaker inside the tube because we wanted to be able to show how simple the device really is.  During the demonstration we can show that the sound is the only cause of the flame crests by simply removing the speaker and watching the pattern disappear.  Another nice thing about having a removable speaker is that you can show that other sources of sound can also generate a standing wave.  We discovered that simply shouting into the tube with the proper frequency would generate nice waves and was entertaining to the audience.  We also connected a piano keyboard to the speaker (with a long speaker cable) and allowed the audience to play notes and melodies on the keyboard to see different standing waves appear.&lt;/p&gt;

&lt;h3 id=&quot;video&quot;&gt;Video&lt;/h3&gt;
&lt;p&gt;My friend posted a video that details the construction a bit more.  It also shows the tube running under several different frequencies and even to some actual music.  Jump to 4:30 in the video to see how the tube responds to various frequencies and songs.&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;http://www.youtube.com/embed/vhmKc1U5jjA&quot; frameborder=&quot;0&quot;&gt; &lt;/iframe&gt;

&lt;h3 id=&quot;picture-gallery&quot;&gt;Picture Gallery&lt;/h3&gt;
&lt;p&gt;The pictures below show the construction and a particular standing wave (750 Hz) inside the tube.&lt;/p&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img img_1715.jpg %}
    {% gen_img img_1717.jpg %}
&lt;/div&gt;

&lt;div class=&quot;row&quot;&gt;
    {% gen_img img_1720.jpg %}
    {% gen_img img_1725.jpg %}
    {% gen_img img_1732.jpg %}
    {% gen_img img_1738.jpg %}
    {% gen_img img_1741.jpg %}
    {% gen_img img_1742.jpg %}
&lt;/div&gt;
</content>
<summary>Roy Montalvo and I made a Rubens Tube for the 2010 Texas A&amp;amp;M Physics Festival.  We will be demonstrating it to students over a wide range of ages, from elementary to college level.</summary>
</entry>
<entry>
<title>Supergenpass</title>
<link href="http://jrsaathoff.com/supergenpass.html" rel="alternate" type="text/html" title="Supergenpass" />
<published>2010-01-01T00:00:00-06:00</published>
<updated>2010-01-01T00:00:00-06:00</updated>
<id>http://jrsaathoff.com/supergenpass</id>
<content type="html" xml:base="http://jrsaathoff.com/supergenpass.html">&lt;p&gt;I had been wanting a perl implementation of the &lt;a href=&quot;http://supergenpass.com&quot;&gt;supergenpass&lt;/a&gt; script and couldn’t find one anywhere, so I just wrote one myself.  It is a very simple script, but I’m making it available because I had a hard time getting the Perl hash to give the same result as the javascript one used by SGP.  I’ve tested it with a lot of password and domain combinations and have always found it to give the same results.&lt;/p&gt;

&lt;p&gt;The main function is easy enough to identify in the code.  I also wanted an easy way to tell if the password I typed in had a typo (I fat finger passwords quite a bit), so I added a function that would allow you to store the hash of commonly used passwords.  Then, if any of those are defined, it prints the password as either green or red, depending on whether the master password matches one of the hashes.&lt;/p&gt;

&lt;p&gt;If you have any suggestions or improvements on the script, please leave a comment below.&lt;/p&gt;

&lt;p&gt;{% highlight perl %}
#!/usr/bin/perl&lt;/p&gt;

&lt;h1 id=&quot;the-following-was-written-by-john-r-saathoff&quot;&gt;The following was written by John R Saathoff&lt;/h1&gt;
&lt;h1 id=&quot;wwwjrsaathoffcom&quot;&gt;www.jrsaathoff.com&lt;/h1&gt;

&lt;h1 id=&quot;to-the-extent-possible-under-law-john-saathoff--has-waived-all&quot;&gt;To the extent possible under law, John Saathoff  has waived all&lt;/h1&gt;
&lt;h1 id=&quot;copyright-and-related-or-neighboring-rights-to-this-work&quot;&gt;copyright and related or neighboring rights to this work.&lt;/h1&gt;

&lt;p&gt;use strict;
use warnings;
use MIME::Base64;
use Digest::MD5 qw(md5 md5_hex md5_base64);
use Getopt::Long;&lt;/p&gt;

&lt;h1 id=&quot;hashes-of-master-passwords--these-variables-are-optional-determined-by&quot;&gt;Hashes of master passwords.  These variables are optional, determined by&lt;/h1&gt;
&lt;h1 id=&quot;using-the--m-option-when-running&quot;&gt;using the -m option when running&lt;/h1&gt;
&lt;h1 id=&quot;they-are-used-so-that-during-normal-operation-the-color-will-be-green-for&quot;&gt;They are used so that during normal operation the color will be green for&lt;/h1&gt;
&lt;h1 id=&quot;a-regularly-entered-password-and-red-for-an-unrecognized-one&quot;&gt;a regularly entered password, and red for an unrecognized one&lt;/h1&gt;
&lt;p&gt;my @masterhashlist = ();
#my @masterhashlist = (‘dfd9798dfdkadfkdjfdkfjAA’, ‘21378421897edfdaafdfdfAA’);&lt;/p&gt;

&lt;h1 id=&quot;handle-command-line-options&quot;&gt;Handle command line options&lt;/h1&gt;
&lt;p&gt;my ($opt_d, $opt_m, $opt_p, $opt_h, $opt_l) = (0,0,0,0,10);
my $result = GetOptions (“d|domain=s”      =&amp;gt; $opt_d,     # string
                         “h|?|help”        =&amp;gt; $opt_h,     # boolean
                         “master-hash”     =&amp;gt; $opt_m,     # boolean
                         “l|length=i”      =&amp;gt; $opt_l);    # integer
if (! $result) { die “\nIncorrect input, run -h for help\n”; }
if ($opt_h)    { usage(); }&lt;/p&gt;

&lt;h1 id=&quot;store-command-line-value-can-also-use--d-if-one-exists-as-domain-opt_d&quot;&gt;Store command line value (can also use -d), if one exists, as domain $opt_d&lt;/h1&gt;
&lt;p&gt;if ($ARGV[0]) {
  $opt_d = $ARGV[0];
  shift;
}&lt;/p&gt;

&lt;p&gt;print “master password = “;
system(“stty -echo”);               # Don’t display the password on the terminal
chop($opt_p = &amp;lt;&amp;gt;);
print “\n”;
system(“stty echo”);&lt;/p&gt;

&lt;h1 id=&quot;print-the-hash-of-the-master-password-if-the-option-is-provided-and-exit-program&quot;&gt;Print the hash of the master password if the option is provided and exit program&lt;/h1&gt;
&lt;p&gt;if ($opt_m) {
  print “master hash     = “, masterHash($opt_p), “\n”;
  die “\n”;
}&lt;/p&gt;

&lt;h1 id=&quot;if-no-domain-has-been-defined-prompt-for-one-on-command-line&quot;&gt;If no domain has been defined prompt for one on command line&lt;/h1&gt;
&lt;p&gt;if (! $opt_d) {
  print “domain          = “;
  chomp($opt_d = &amp;lt;&amp;gt;);
}&lt;/p&gt;

&lt;p&gt;print “site password   = “;&lt;/p&gt;
&lt;h1 id=&quot;this-checks-to-see-if-any-master-hashes-have-been-defined--if-so-it-prints-the&quot;&gt;this checks to see if any master hashes have been defined.  If so, it prints the&lt;/h1&gt;
&lt;h1 id=&quot;password-using-the-appropriate-color&quot;&gt;password using the appropriate color.&lt;/h1&gt;
&lt;p&gt;if (@masterhashlist &amp;gt; 0) {
  setPasswordColor ($opt_p);
  print generatePassword($opt_p.’:’.$opt_d), “\033[0m\n”;
} else {
  print generatePassword($opt_p.’:’.$opt_d), “\n”;
}&lt;/p&gt;

&lt;p&gt;###########  hash  ###########################&lt;/p&gt;

&lt;h1 id=&quot;returns-the-md5-value-of-a-string-as-expected-by-sgp--pass-the-string-to-hash&quot;&gt;Returns the md5 value of a string as expected by SGP.  Pass the string to hash.&lt;/h1&gt;
&lt;p&gt;sub hash {
  my $md5string = $_[0];
  $md5string = md5_base64($md5string);
  $md5string = $md5string.’AA’;                            # The following three lines are simply to make the Perl MD5
  $md5string =~ s/+/9/g;                                  # return the same result as the javascript MD5 funciton
  $md5string =~ s/\//8/g;&lt;/p&gt;

&lt;p&gt;return $md5string;
}&lt;/p&gt;

&lt;p&gt;###########  masterHash  ###########################&lt;/p&gt;

&lt;h1 id=&quot;returns-the-result-of-the-hash-function-called-50-times-on-a-value&quot;&gt;Returns the result of the hash function called 50 times on a value&lt;/h1&gt;
&lt;p&gt;sub masterHash {
  my $mhash = $_[0];&lt;/p&gt;

&lt;p&gt;for (my $i=0; $i&amp;lt;50; $i++) {
    $mhash = hash($mhash);
  }
  return $mhash;
}&lt;/p&gt;

&lt;p&gt;###########  setPasswordColor  ###########################&lt;/p&gt;

&lt;h1 id=&quot;sets-the-color-as-green-if-it-matches-a-saved-hash-red-if-it-doesnt&quot;&gt;Sets the color as green if it matches a saved hash, red if it doesn’t&lt;/h1&gt;
&lt;p&gt;sub setPasswordColor {
  my $chash = $_[0];
  my $md5match = 0;&lt;/p&gt;

&lt;p&gt;$chash = masterHash($chash);
  foreach (@masterhashlist) {
    if ($chash eq $_) { $md5match = 1; }
  }&lt;/p&gt;

&lt;p&gt;if ($md5match) {
    print “\033[32m”;
  } else {
    print “\033[31m”;
  }
}&lt;/p&gt;

&lt;p&gt;###########  validpassword  ###########################&lt;/p&gt;

&lt;h1 id=&quot;returns-true-if-the-passed-string-is-a-valid-password&quot;&gt;Returns true if the passed string is a valid password&lt;/h1&gt;
&lt;p&gt;sub validPassword {
  my $password = $_[0];
  my $valid    = 1;&lt;/p&gt;

&lt;p&gt;$valid = $valid &amp;amp;&amp;amp; ($password =~ m/[A-Z]/);   # Contain at least one uppercase letter of the alphabet
  $valid = $valid &amp;amp;&amp;amp; ($password =~ m/[0-9]/);   # Contain at least one numeral
  $valid = $valid &amp;amp;&amp;amp; ($password =~ m/^[a-z]/);  # Start with a lowercase letter of the alphabet&lt;/p&gt;

&lt;p&gt;return $valid;
}&lt;/p&gt;

&lt;p&gt;###########  generatePassword  ###########################&lt;/p&gt;

&lt;h1 id=&quot;md5-the-starting-string-10-times-or-until-we-get-a-valid-password&quot;&gt;MD5 the starting string 10 times or until we get a valid password&lt;/h1&gt;
&lt;p&gt;sub generatePassword {
  my $hashstring         = $_[0];
  my ($count, $password) = (0, 0);&lt;/p&gt;

&lt;p&gt;while (! (validPassword($password)) || ($count &amp;lt; 10)) {
    $hashstring = hash($hashstring);
    $password   = substr($hashstring, 0, $opt_l);
    $count += 1;
  }
  return $password;
}&lt;/p&gt;

&lt;p&gt;###########  USAGE  ###########################&lt;/p&gt;

&lt;h1 id=&quot;print-help-and-exit-program&quot;&gt;Print help and exit program&lt;/h1&gt;
&lt;p&gt;sub usage {
  print “\n”;
  print “-d, –domain       the site domain\n”;
  print “–master-hash      print a check hash value for a password.  It is the result of\n”;
  print “                   hashing the password 50 times\n”;
  print “-l, –length       the length of the generated password (default is 10)\n”;
  print “-h, -?, –help     prints help and exits\n”;&lt;/p&gt;

&lt;p&gt;die “\n”;
}
{% endhighlight %}&lt;/p&gt;

</content>
<summary>I had been wanting a perl implementation of the supergenpass script and couldn’t find one anywhere, so I just wrote one myself.  It is a very simple script, but I’m making it available because I had a hard time getting the Perl hash to give the same result as the javascript one used by SGP.  I’ve tested it with a lot of password and domain combinations and have always found it to give the same results.</summary>
</entry>
</feed>
