Thursday, May 2, 2019

My Gaming History

I recently joined Twitch, a company that is all about gaming and community—so it only seems appropriate to post something about my history with games. While I've never worked on a commercial game, I love games—but mostly retro games.

Board Games

Growing up there were no game consoles, arcade games, or home computers; but there were board games, and boy did I play a lot of them with my family and friends. First there were the games we played as very young children, like LIFE and Sorry and Trouble. As we grew older, there were the old family favorites: Monopoly and Yahtzee and Scrabble. There were the Parker Brothers classics like Clue and Masterpiece and Risk. There was Rack-O and Stratego.

In Risk you are out to take over the world. My brother Lee and I played Risk frequently, often roping in a relucant family member to be a third player. I'm afraid we tended to prey on the third player until we were both powerful enough to take each other head on, not a lot of fun for the third player (our mother eventually refused to play with us).


Clue was fun because you had to solve a mystery before anyone else did: who did the murder, with what weapon, in what room? Taking notes, analyzing new clues, and guarding your facial expressions were essential.

Clue

In addition to strategy games, word games were also special. Scrabble was/is great for vocabulary (and sometimes for bluffing), but you can wait an awful long time for someone to make a move if they have a poor set of letters. Over time we developed the art of pointing nearby objects (such as spoons, mug handles, pens, etc.) in the direction of the player who was taking too long to move until they got the hint.

Scrabble

Besides Scrabble, we played a lot of Boggle. I was quite good at rapidly finding all the words to be found in a random set of letters.

Boggle

What about card games? Especially in earlier times, many families avoided official playing cards, not wanting to encourage gambling; but other card games were fine. In particular, Rook is popular in Christian circlesparticularly on my wife's side of the family. A family visit from the in-laws always means we'll be playing Rook.

Rook

We and our friends played games all the time. I guess we also went to school and worked somewhere along the way, but otherwise we were getting together for games whenever we could.

In high school I was on the chess club; in between matches we would meet in the library to play chess. By combining several chess sets, we were able to rig a 4-way chess game by adding half chess boards to the outer edges of a chess board, which was arranged omething like this:


Early Computer Games

In High School, on the last day of the 9th grade, I got my first taste of an electronic game. My friend Andrew asked if I had ever been to the Computer Room in the Math Department. A computer? In our school? This was news to me, and I enthusiastically went with him to see Room 214 of Connetquot High School. The room was chattering with noisy teletypewriters churning out text on paper rolls. These teletypes were connected to a DEC PDP-10 timesharing system the county owned, and we were fortunate indeed to have access as there were no personal computers at the time. It was the first time I had ever seen a computer of any kind, and I was instantly hooked.

On the walls were stapled listings of programs and program output, including many games. There was a CASINO game, offering games like 21 and slot machines. There was a WUMPUS game where you had to track down and kill an elusive Wumpus creature. LUNAR was a game where you could try to land the Lunar Module on the moon with a limited amount of fuel. In TREK, the user battled Klingons in a space grid. There was an ELIZA game, simulating a psychologist. And, there was ADVENT (Adventure), an Adventure game. Adventure was special: you explored a world, found and carried objects, overcame obstacles and adversaries. Adventure was in fact the very first interactive fiction, and I'll be posting more about it in the future.

Adventure

Hunt the Wumpus

I no longer have any output from it, but I created a game on the PDP10 named CHASE, in which the player was moving around in a grid, being pursued by several adversaries. Each time you moved, the enemies moved closer; but there were barriers you could hide behind and leverage. It was basically the game of Fox and Hounds.

Arcade Video Games

When video games hit the arcades, I was in my late teens / early twenties, and I spent as much time as I could at the local mall using up my quarters. I mostly played BattleZone, QBert, Tempest, and Marble Madness.

Battlezone was one of my favorites, with its simple vector-graphics display but very effective strategic gameplay. I hear it was used by the U.S. Army to train tank gunners.

Battlezone

My all-time favorite arcade game was Marble Madness. I thoroughly admired the Escher-like artwork, the musical score, the zany elements of the game: all artistically combined. Using a trackball to control a marble was genius. I loved it. Alas, Marble Madness only had six levels so although initially successful it was not long lasting.


Marble Madness

I also played a lot of Pac-Man, mostly because that game was everywhere including restaurants and convenience stores. My programmer friend Randy had memorized winning patterns of movement for the first few levels and could play that game like a piano (for this reason, when Ms. Pac Man came out an element of randomness was added).

Later Computer Games

A few years later, after home computers had happened, game consoles for the home started becoming available. I had an Atari 2600 and later an Amiga computer. I purchased some of my favorite arcade games such as BattleZone and Marble Madness, but frustratingly these were often not-so-faithful to the original. Marble Madness in particular was hard to adjust to without the original's trackball, which was such a natural way to control a rolling marble.

In the early 2000s, I remember bringing home Zoo Tycoon for the PC. My daughter Susan loved it, and she kept playing. As a teenager she designed her own extensions for the game and joined an online design community. She met some of her best friends that way: she's currently at the University of Louisville, and got familiar with Kentucky chiefly through a connection she made in that Zoo Tycoon design community. She's visited another friend in Australia several times, another connection from that same community. It surprised me that a game I bought for her as a child (and its community) could have such an ongoing influence in her life.

Zoo Tycoon

XBox and XBox 360

In 2003 I was working at Microsoft, now with my own family and young children. In an employee knowledge quiz I ended up winning an XBox.

One of my favorite XBox games was Indiana Jones and the Emperor's Tomb. It was done exceedingly well, and you really felt like Indy when you played. There were great settings, puzzles to solve, treasures to find, and villains to fight. It took me 4 months of weekends to get to the end of the game, somehow also keeping up with my work responsibilities.


Indiana Jones and the Emperor's Tomb

We later upgraded to an XBox 360—only to be highly disappointed that many original XBox games would not work on the 360. I've never understood the XBox team's lack of concern over game compatibility with the prior generation of consoles; it's sad when you can't play your favorite games any more, especially considering the money you've invested in them. When I learned it was going to be the same thing all over again with the XBox One, I decide to stop buying XBox consoles.

Family Favorites

In addition to my own game interests, it was fascinating to watch the rest of my family's interest in video games. A family favorite on the XBox was Midtown Madness 3, which allowed you to drive like a madman (or madwoman) in either Paris or Washington DC. It was a sad day when our XBox died, and my family still talks about missing Midtown Madness to this day. Alas, it doesn't seem to be available anywhere on modern gaming platforms.

Midtown Madness 3

I made the mistake of bringing home Viva Piñata one day from the Microsoft Store, and my wife and kids loved it so much I saw nothing of them for the next three weeks ("umm... are we having dinner today?"). In this game, you have to domesticate candy-animals in a strange land. If nothing else, it's certainly colorful.


Viva Piñata

When the Kinect came out for XBox 360, we could get up off the couch and play interactive games. The Kinect could identify one or two players and respond to location, movement, and hand motions. Kinect Adventures let you do things like river rafting. Kinect Sports let you play many different sports, from bowling to football to volleyball. For a while, Kinect games were all the rage.

Kinect Adventures

Kinect Sports

Traditional board games became available for the 360, and we'd often play those instead of having to set up and put away physical board games. This included Monopoly, Trivial Pursuit, Scrabble, and Yahtzee.

Monopoly on XBox 360

As my kids got older, their taste in games changed. My son liked driving games like Forza Motorsports 3 and Skate 3 (he likes breaking every bone in his body in the "Hall of Meat" mode). My daughter Susan liked Portal 2 and Skyrim. My daughter Debra liked Civilization 6 as well as Skyrim. Skyrim looked a tad dark to me, but I could see the legacy of that original Adventure game in these later games.

Portal 2

Elder Scrolls V: Skyrim

As the Internet started getting more sophisticated, online games started getting better and better. I remember my young children enjoying Club Penguin, a family-friendly safe place for young ones from Disney.

Later, Minecraft was a craze. All three of my kids spent lots of time building blocky pixelated creations in Minecraft.

Minecraft

My son became obsessed with airplanes a few years back, and ever since he's spent a lot of his time with flight simulators, particularly X-Plane. He's flown everything from Cessnas to the Space Shuttle. By playing with others, he gets the full experience of flying, talking to air traffic controllers, navigating around other planes, and so on. I'd say these simulators must be pretty good, because when we took him on an actual flight with an instructor for his birthday last year, the instructor was impressed with his knowledge of the cockpit and rules of flight.

X-Plane

Today there is Steam, and for this retro gamer that's one way to play some of my favorite games from the past such as the Indiana Jones titles. But I'm still looking for a way to play Midtown Madness and Marble Madness.

One board game that has recently become a new family favorite is Settlers of Catan, particularly when my daughter Debra is home. She is cold, calculating, and vicious in her gameplay (I've never been prouder!) Catan features heavy strategy and trading elements, and while there's no warfare in the game it reminds me strongly of Risk.

Catan

Phone Games

Like the rest of the world, there's the occasional game craze like Angry Birds or Flappy Bird that everyone gets caught up in fror a while.

Angry Birds

The phone game my wife and I play the most is Words with Friends: we play it every day with each other. This is something we can do whether we're together or apart.

Words with Friends

Conclusion

One reason I'm a retro gamer is the amount of creativity I saw in the early days. Maybe that was a side effect of the limitations in platforms. Today it seems so many games are First Person Shooters or Driving Games. Many of them are done well, and there's lots of work on world-building, but it still feels to me like there was more creativity and inventiveness in the past. On the other hand, there are lots of modern games I haven't played yet.

Well, there you have it: a lifetime of game play that is continuing on with the next generation. I'll admit, I've sometimes been so busy at work I've neglected gaming at times. Fortunately, I now work somewhere where gaming is part of work. Let the games begin!


Wednesday, April 24, 2019

Create and Host a Cross-Platform Web Site on ASP.NET Core

This is the second post in a series on .NET Cross-Platform Support. In my first post, I covered how to create, build, and deploy a console command in .NET Core for Windows, Linux, and MacOS. In today's post, I'll cover how to create a web site with ASP.NET Core and deploy it on both Windows and Linux.

If you're going to follow along, you'll need to install the .NET Core SDK. I'm doing my development with .NET Core 2.2 and Visual Studio Code on Windows, but you could just as easily do the same on Linux or MacOS.

The web site we'll create is a simple one-page site that performs conversions between different units of measurement, such as from miles to kilometers.

Development


Creating an ASP.NET MVC Project

We'll use the dotnet new command to create a starter project. I want to use MVC, so we'll request the MVC template.We'll specify the folder and project name convert.

dotnet new mvc -o convert











This creates a folder named convert. Within that folder are our project files along with subfolders.













Coding the Site

Fire up Visual Studio Code and use Open Folder to open the convert folder that was just created.

If you're new to ASP.NET Core, let's take a moment to familiarize ourselves with the project that has been created. Keep in mind this MVC project is only one of many ASP.NET Core project tempaltes
you can use.

Project Structure

In the convert folder, there is Program.cs and Startup.cs. Program.cs contains function Main, which is where execution begins. It creates a WebHost, and references the Startup class.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace convert
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();

Startup.cs contains the initialization code for the WebHost. This refactoring of ASP.NET is extremely modular and extensible, and includes a built-in dependency injection system.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace convert
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}

Since we're just building a simple demonstration web site, we dont need to make any changes to the code in Program.cs or Startup.cs.

Within the convert folder, we have Controllers, Models, and Views subfolders. These are all conceptually familiar to anyone familiar with the Model-View-Controller pattern. Controllers contains C# controller classes; Models contains C# model classes; and Views contain Razor pages (which are HTML with embedded C# code and Razor directives).

There's also a wwwroot folder, which contains static css, image, and JavaScript files.

Project Starting Point

We can build and run the project to see what we have been given out-of-the-box. In Visual Studio Code, open a new terminal window with Terminal > New Terminal. Run dotnew build to build the prjoect.

In traditional ASP.NET, launching the site locally from Visual Studio would use IIS or IIS Express to host the web site. In ASP.NET Core, all we need is the dotnet run command. Enter dotnet run in the terminal window to host a web server. Click the displayed HTTP or HTTPS link to open the site in a browser. We can see we get a simple Welcome page.








Code the HTML Page

We need to change the HTML in the default page, /Views/Home/index.cshml. We add the following code to the page:
@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
    <h1 class="display-4">Unit Converter</h1>
    <p>Use this page to convert between common units of measurement</a>.</p>
</div>

<div> </div>

<div>
    <input id="source-value" type="number" value="10" style="font-size: 14px" />
        
    <select id="source-unit">
        <option value="">-- select source units --</option>
        <option value="ft" selected>Feet (ft)</option>
        <option value="km" selected>Kilometers (km)</option>
        <option value="m">Meters (m)</option>
        <option value="mi">Miles (mi)</option>
    </select> 
        
    <button id="btn-convert" onclick="convert();">Convert</button> 
        
    <input id="dest-value" type="number" value="" style="font-size: 14px" readonly=readonly />
        
    <select id="dest-unit">
        <option value="">-- select destination units --</option>
        <option value="ft" selected>Feet (ft)</option>
        <option value="km">Kilometers (km)</option>
        <option value="m">Meters (m)</option>
        <option value="mi" selected>Miles (mi)</option>
    </select>
</div>


<script>
function convert() {
    var value = $('#source-value').val();
    var sourceUnits = $('#source-unit').val();
    var destUnits = $('#dest-unit').val();

    $('#dest-value').val('');

    if (sourceUnits==='' || destUnits==='') return;

    if (sourceUnits===destUnits)
    {
        $('#dest-value').val(value);
        return;
    }

    console.log(value);
    console.log(sourceUnits);
    console.log(destUnits);

    var url = '/home/Convert?value=' + value + '&source=' + sourceUnits + '&dest=' + destUnits;

    $.ajax({
        url: url,
        method: 'GET',
    }).done(function(data) {
        $('#dest-value').val(data);
        //$( this ).addClass( "done" );
        console.log(data);
    });
}

</script>
We can now build the site with dotnet build and run it with dotnet run so that we can test it.

dotnet build
dotnet run

Now we can enter an amount and select source and destination units. Clicking Convert converts the value.










Our site, while simple, could easily be expanded to support many more conversions over time. For our purposes of testing cross-platform compatibility, this is sufficient and we can move on to seeing things work on Linux.

Publishing to Linux

We can generate output for linux with the dotnet publish command, specifying the distribution we wish to target. We'll use Ubuntu 18.04, 64-bit (because that's an AMI available for AWS EC2).

dotnet publish -c Release --self-contained -r ubuntu.18.04-x64

To deploy, we'll need to allocate a Linux web server, for which we'll use NGINX. We'll then deploy our convert site, and finally configure NGINX to serve as a reverse proxy to our ASP.NET Core site.

1. Create EC2 instance

We first create an Ubuntu EC2 instance on AWS. We save the .pem (key) file created with the instance, which will be needed anytime we want to connect to the instance with SSH.

Configure an inbound rule allowing port 80 in the security group for the EC2 instance.

As we allocate the EC2 instance, we save the .pem (key) file, which we'll need for subsequent steps.










2. Connect with SSH

Once the instance is up and running, we connect to it with SSH, specifying our instance URL and the .pem (key) file we created with the instance:

ssh -i "dp-dev.pem" ubuntu@ec2-my-ip.us-west-2.compute.amazonaws.com

3. Set up web server

To set up a web server, we use the sudo ("SuperUser do") command to allow port 80 on the firewall.

sudo ufw allow 80/tcp

Next, we install nginx, a popular web server:

sudo apt-get install nginx
sudo service nginx start

Once installation completes, we are able to confirm that we can access the EC2 instance as a web server:

















4. Deploy the .NET Core application

Via SSH, create a convert file under /home/ubuntu. Then use a tool such as WinSCP to copy the files from the Ubuntu publish folder to /home/ubuntu/convert:















5. Configure nginx to be a Reverse Proxy for Convert.dll

Following the Microsoft instructions here, we do the following to set up NGINX as a reverse proxy for the NET Core convert site. This simply means NGINX will forward requests to our application.

a. Stop the nginx site

sudo service nginx start

b. Change directory to /etc/nginx/sites-available and replace the file default with the content below (I used Notepad++ and WinSCP for this):

cd /etc/nginx/sites-available

server {
    listen        80;
    server_name   example.com *.example.com;
    location / {
        proxy_pass         http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection keep-alive;
        proxy_set_header   Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

If you run into permission issues, try uploading your new default file to a path you have write access to, such as where you copied the convert application publish files to. Then, in cd /etc/nginx/sites-available, you can use sudo cp to copy the file:

cd /etc/nginx/sites-available
sudo cp /home/ubunto/convert/default .

c. Start the nginx service

sudo service nginx start

6. Start the Convert Site

From /home/ubuntu/convert, use the dotnet command to run convert.dll to start the Convert site

cd /home/ubuntu/convert dotnet convert.dll

7. Try to access the site in a browser:


















Our ASP.NET Core Convert site is now running on Ubuntu Linux, with NGINX serving as a reverse proxy. If you've never worked with Linux as a web server before, getting to this step with a .NET web site is a great moment.


Conclusion

In this post I've shared what my first-time experience publishing an ASP.NET Core web site to Linux. There were plenty of unknowns working with an operating system I had little experience with, but with a little persistence I got there. .NET Core is well done, and ASP.NET Core is no exception. It's very empowering to realize how broader your .NET Skills can now reach with .NET Core.


25th Anniversary Cruise, Part 7: Pompeii

In this series of posts I'm describing the Mediterranean Cruise my wife Becky and I took in 2018 for our 25th anniversay, Here in Part 7 I'm covering our seventh stop, Pompeii.

Pompeii (★★★★)

Pompeii was marvelous. In terms of historical richness and the amount of things to see, Pompeii delivered more than any other stop on our trip. 

Pompeii was an ancient Roman city near Naples that was buried by lava in the AD 79 eruption of Mount Vesuvius. The result is a highly-preserved ancient city. It's also a complete city: you can walk it's streets, look into houses and public places and restaurants and so on. It's not possible to see it all in one day, but our excellent tour guide Jose took us to many of the highlights and gave us lots of good information throughout the day.

Pompeii is in pleasant surroundings with picturesque hillsides, trees, and flowers.


Our guide walked us past practice fields for the gladiators and an amphitheatre.



We then proceeded to walk the streets. The Pompeiians were pretty sophisticated. There were stone blocks to step on so upper-class citizens could avoid walking in garbage. There were shells embedded in the streets to provide reflective illumination at night.


"Your Money is Welcome Here"

Seeing Roman homes was impressive. Some homes had impressive floor tiles. Wall mosaics were common.


Public baths with hot and cold water; and a restaurant kitchen.



We also saw some of the casts made of bodies.


Inside this arch you can see Mount Vesuvius.


That's about all we had time for, but despite seeing a lot there's far more to Pompeii. We certainly felt Pompeii didn't disappoint.

Previous: Part 6: Rome