Project: Codingame.com – There is no spoon

Tools and Technology: C++

There’s a great site called Codingame that gives practice code challenges, including weekly and sponsored challenges, as well as coder-vs-coder and 5-minute challenges. This site helps keep me coding every day. I’ve completed all of the Easy puzzles and am now pushing through the Medium ones. This is from the There Is No Spoon challenge.

Sample Code

#include 
#include 
using namespace std;

int main()
{
    int width; // the number of cells on the X axis
    cin >> width; cin.ignore();
    int height; // the number of cells on the Y axis
    cin >> height; cin.ignore();
    string *grid = new string[height]; // grid of characters, each either 0 or .
    for (int i = 0; i < height; i++) {
        getline(cin, grid[i]); // line of characters
    }
    

    for (int vert = 0; vert < height; vert++)
    {
     for (int horz = 0; horz < width; horz++)
     {
         if('0' == grid[vert][horz]) // If we found a 
         {
              // Print the base node coords
              cout << horz << " " << vert << " ";
              
              // Print possible right neighbor coords
              int i = 0;
              int tempx = -1;
              int tempy = -1;
              while(width != horz + ++i)
              {
                  if('0' == grid[vert][horz + i])
                  {
                      tempx = horz + i;
                      tempy = vert;
                      break;
                  }
              }
              cout << tempx << " " << tempy << " ";
              
              // Print possible bottom neighbor coords
              i = 0;
              tempx = tempy = -1;
              while(height != vert + ++i)
              {
                  if('0' == grid[vert + i][horz])
                  {
                      tempx = horz;
                      tempy = vert + i;
                      break;
                  }
              }
              cout << tempx << " " << tempy << " " << endl;
         }
     }  
    }
    
    delete[] grid;
}

Project: Oh Buoy!

Tools and Technology: C++, Arduino, C#, Unity, Solidworks, 3D printing, miscellaneous hardware, simplex noise maths, SimTools, Live for Speed

After I created my own Stewart Platform it was time to push it further, creating an interactive game (“Oh Buoy!”) and custom peripheral (custom Lego boat).

Sample Code

C++ code Arduino code used to control the platform with Inverse Kinematics and Matrix maths.
Download Arduino code.

C# code used to communicate serial data from Unity to Arduino. Also, the code to move the buoys with Simplex Noise.

public class ArduinoHelper : MonoBehaviour {

	[StructLayout(LayoutKind.Explicit)]
	struct floatyBytes
	{
		[FieldOffset(0)]
		public byte byte0;
		[FieldOffset(1)]
		public byte byte1;
		[FieldOffset(2)]
		public byte byte2;
		[FieldOffset(3)]
		public byte byte3;
		[FieldOffset(0)]
		public float floaty;

		public floatyBytes(float _floaty = 0.0f)
		{
			byte0 = 0;  // The compiler thinks these bytes are
			byte1 = 0;  // not set at the end of this constructor.
			byte2 = 0;  // It is wrong, of course, but we need to
			byte3 = 0;  // make it happy.  The float overwrites these.
			floaty = _floaty;
		}
	}
		
	byte[] startByte = {33};  // '!'
	byte[] endByte = {35};  // '#'
	floatyBytes[] tempDOFs = new floatyBytes[6];
	byte[] tempBytes = new byte[4];
	byte[] tempByte = new byte[1];
	float sendTime;
	float serialTimeBuffer = 0.02f;

	SerialPort serialPort;


	void Start () {
		sendTime = Time.time + serialTimeBuffer;
		serialPort = new SerialPort("COM7", 9600);
		serialPort.Open();
	}

	//  In keeping with the reference spreadsheet,
	//  Order: x, y, z, pitch, roll, yaw
	public void Send6DOF(float[] _dofs)
	{
		
		if (Time.time > sendTime) {
			if (serialPort.IsOpen) {
				serialPort.Write (startByte, 0, 1);
				
				for (int i = 0; i < 6; i++) {
					tempDOFs [i].floaty = _dofs [i];

					tempBytes [0] = tempDOFs [i].byte0;
					tempBytes [1] = tempDOFs [i].byte1;
					tempBytes [2] = tempDOFs [i].byte2;
					tempBytes [3] = tempDOFs [i].byte3;
					serialPort.Write (tempBytes, 0, 4);
				}

				serialPort.Write (endByte, 0, 1);
				//serialPort.BaseStream.Flush ();  // This sends the data right away, with no buffering
			}
			sendTime = Time.time + serialTimeBuffer;
		}

			
	}

	void OnApplicationQuit()
	{
		if (null != serialPort && serialPort.IsOpen) {
			serialPort.Close ();
		}
	}
}


// ********************************************************************
// ********************************************************************

public class BuoyMovement : MonoBehaviour {

	const float ANGLE_MAX = 14.0f;
	Vector3 tempVec3 = Vector3.zero;
	Vector3 tempPos;
	bool acquired = false;

	[SerializeField]
	AudioClip buoyDing;
	AudioSource m_audio;

	// Use this for initialization
	void Start () {
		tempPos = transform.position;
		m_audio = GetComponent ();
	}
	
	// Update is called once per frame
	void FixedUpdate () {
		// Add random floaty angles
		float currentPositionZ = transform.position.z;
		tempVec3.z = getAngle (0.0f + currentPositionZ );
		tempVec3.x = getAngle (180.5f + currentPositionZ );

		transform.eulerAngles = tempVec3;

		tempPos.y = getAngle (90.0f + currentPositionZ ) / 112.0f + 1.0f;
		transform.position = tempPos;
	}

	float pseudoRandGen(long seed)
	{
		seed %= 256;
		seed += 71;
		long tempLong = (101111111111 * seed * seed) % 10001;
		return ((float)tempLong / 10001.0f) * (2.0f * ANGLE_MAX) - ANGLE_MAX;
	}

	float getAngle(float _ratioOffset)
	{
		float currentTime = (Time.time * 0.5f) + _ratioOffset;
		long currentTimeIndex = (long)currentTime % 256;
		long nextTimeIndex = (currentTimeIndex + 1) % 256;

		float currentAngleIndex = pseudoRandGen (currentTimeIndex);
		float nextAngleIndex = pseudoRandGen (nextTimeIndex);

		float ratio = currentTime - (float)currentTimeIndex;
		ratio = ease1 (ratio);

		return lerp (ratio, currentAngleIndex, nextAngleIndex);
	}

	float lerp(float _ratio, float _num1, float _num2)
	{
		return (_num2 - _num1) * _ratio + _num1;
	}

	float ease1(float _ratio)
	{
		return 1 - (Mathf.Cos(_ratio * Mathf.PI) + 1.0f) * 0.5f;
	}

	public bool acquireBuoy()
	{
		if (acquired)
			return false;
		
		acquired = true;

		// Ding!
		m_audio.PlayOneShot(buoyDing);

		Light[] buoyLight = GetComponentsInChildren ();
		for (int i = 0; i < buoyLight.Length; i++) {
			buoyLight [i].color = Color.green;
		}
		GetComponentInChildren ().Play ();

		return true;
	}
}

Project: Nahaulis – A Gun of Three Spirits

Tools and Technology: C#, Unity, PhotoShop, Agile/SCRUM

“Nahaulis: A Gun of Three Spirits is a 2D explorative, action-adventure game that takes place in an Aztec temple where the player uses Nahaulis to defeat the manifested god, Tezcatlipoca.”

My development group and I spent a month and a half creating this platformer in multiple Agile sprints. My responsibilities included projectiles, minimap, animatics, a few enemies, and a lot of bug hunting.

C# code for the part of the minimap controller.

void DisableAllMapSquares()
	{
		for (int i = 0; i < gom_MinimapSquares.Length; i++) {
			gom_MinimapSquares[i].SetActive(false);
		}

		gom_AlternateEndingSquare.SetActive(false);

	}

	int GetMiniMapIndexByRoomAndSquare(int _mmRoom, int _mmSquare)
	{
		for (int i = 0; i < m_MinimapSquares.Length; ++i) {
			if ((_mmRoom == m_MinimapSquares[i].RoomIndex)&&(_mmSquare == m_MinimapSquares[i].SquareIndex)) {
				return i;
			}
		}
		return -1;
	}

	public void LoadMinimapRoomsFromPlayerPrefs()
	{
		string currentRoomString;
		for (int i = 1; i <= 28; i++) {
		if (PlayerPrefs.HasKey ("MM_ActiveRoom_" + i) && PlayerPrefs.GetString("MM_ActiveRoom_" + i).Length >= 8) {
                    currentRoomString = PlayerPrefs.GetString ("MM_ActiveRoom_" + i);
				for (int square = 0; square < 8; square++) {
					if ("1" == currentRoomString.Substring (7 - square, 1)) {
						ActivateMinimapRoomAndSquare (i, square);
					}
				}
			}
		}
	}

	void TurnOnPlayerPrefSquare(int _mmRoom, int _mmSquare)
	{
        // This resets the entire room to ZERO.  DO NOT USE, EVERRRRRRRRRRR
        //PlayerPrefs.SetString ("MM_ActiveRoom_" + _mmRoom, "00000000");
        //return;

        //Debug.Log(PlayerPrefs.GetString("MM_ActiveRoom_" + _mmRoom).Length + " " + _mmSquare);

		if (!PlayerPrefs.HasKey ("MM_ActiveRoom_" + _mmRoom) || PlayerPrefs.GetString("MM_ActiveRoom_" + _mmRoom).Length < 8) 
		{
			PlayerPrefs.SetString ("MM_ActiveRoom_" + _mmRoom, "00000000");
		}
			
		string tempString = PlayerPrefs.GetString ("MM_ActiveRoom_" + _mmRoom);

		if ("0" == tempString.Substring(7 - _mmSquare, 1)) { // If it's not yet set:
			string ReturnString = "";
			for (int i = 0; i < 8; i++) {
				if ((7 - _mmSquare) == i) {
					ReturnString += "1";
				} else {
					ReturnString += tempString.Substring (i, 1);
				}
			}
			PlayerPrefs.SetString ("MM_ActiveRoom_" + _mmRoom, ReturnString);
		}
}



	public void ActivateMinimapRoomAndSquare(int _mmRoom, int _mmSquare, bool _isFromRoomMap = false)
	{
		m_currentRoom = _mmRoom;
		m_currentSquare = _mmSquare;

		// Set the PlayerPrefs appropriately
		TurnOnPlayerPrefSquare(_mmRoom, _mmSquare);


		// Turn on the Game Object
		gom_MinimapSquares[GetMiniMapIndexByRoomAndSquare(_mmRoom,_mmSquare)].SetActive(true);

		// Update the minimap position
		Vector2 currentMapPosition = GetMapPositionFromRoomAndSquare(_mmRoom, _mmSquare);
		m_TargetPosition = new Vector2(m_BaseX - (m_MMUnitMultiplier * currentMapPosition.x) + m_OffsetX, m_BaseY + (m_MMUnitMultiplier * currentMapPosition.y) + m_OffsetY);

		// Jump to the current room the first time
		if ((_isFromRoomMap)&&(!m_bHasInitialized)) {
			m_MapPartContainer.transform.position = m_TargetPosition;
			m_bHasInitialized = true;
		}
	}

Project: ASCII Roguelike Dungeon Crawler

Tools and Technology: C++

ASCII Roguelike Dungeon Crawler is a short game I started in an early programming class.

C++ code for the drawing the map.

void MapData::drawMap(void)
{

	int offsetX = 59;
	int offsetY = 1;

	for (int rows = 0; rows < MAP_HEIGHT + 1; rows++)
	{
		for (int cols = 0; cols < MAP_WIDTH + 1; cols++)
		{
			Console::SetCursorPosition(cols * 2 + offsetX, rows * 2 + offsetY);

			// Print out the "column" value (currently not used)
			Console::ForegroundColor(ConsoleColor::DarkGray);
			cout << char(197);
			Console::ResetColor();

			// Print out the Horizontal Wall type (top wall)
			if (getSquare(rows, cols)->getHWallType() == WallData::WallType::Wall_Solid)
			{
				if (cols != MAP_WIDTH)
				{
					Console::ForegroundColor(ConsoleColor::DarkGray);
					cout << char(196);
					Console::ResetColor();
				}
			}
			else if (getSquare(rows, cols)->getHWallType() == WallData::WallType::Door_Locked)
			{
				cout << '=';
			}
			else if (getSquare(rows, cols)->getHWallType() == WallData::WallType::Door_Boss)
			{
				Console::ForegroundColor(ConsoleColor::DarkMagenta);
				cout << char(219);
				Console::ResetColor();
			}
			else
			{
				cout << ' ';
			}

			Console::SetCursorPosition(cols * 2 + offsetX, rows * 2 + 1 + offsetY); //Jump the cursor down a row

			// Print out the Vertical Wall type (left wall)
			if (getSquare(rows, cols)->getVWallType() == WallData::WallType::Wall_Solid)
			{
				if (rows != MAP_HEIGHT)
				{
					Console::ForegroundColor(ConsoleColor::DarkGray);
					cout << char(179);
					Console::ResetColor();
				}
			}
			else if (getSquare(rows, cols)->getVWallType() == WallData::WallType::Door_Boss)
			{
				Console::ForegroundColor(ConsoleColor::DarkMagenta);
				cout << char(219);
				Console::ResetColor();
			}
			else
			{
				cout << ' ';
			}

			// Print out the Floor Object Type (This is whatever is sitting in the room)
			if ((getSquare(rows, cols)->getFloorObjectType() == FloorObjectData::FloorObjectType::Character_NPC) && (cols != MAP_WIDTH) && (rows != MAP_HEIGHT))
			{
				Console::ForegroundColor(ConsoleColor::Red);
				cout << '&';
				Console::ResetColor();
			}
			else if ((getSquare(rows, cols)->getFloorObjectType() == FloorObjectData::FloorObjectType::Character_NPC_Boss) && (cols != MAP_WIDTH) && (rows != MAP_HEIGHT))
			{
				Console::ForegroundColor(ConsoleColor::Magenta);
				cout << '&';
				Console::ResetColor();
			}
			else if ((getSquare(rows, cols)->getFloorObjectType() == FloorObjectData::FloorObjectType::Character_PC) && (cols != MAP_WIDTH) && (rows != MAP_HEIGHT))
			{
				Console::ForegroundColor(ConsoleColor::Cyan);
				switch (m_pcParty->getDirection())
				{
				case PlayerParty::Direction::North:
					cout << '^';
					break;
				case PlayerParty::Direction::East:
					cout << '>';
					break;
				case PlayerParty::Direction::South:
					cout << 'v';
					break;
				case PlayerParty::Direction::West:
					cout << '<';
					break;
				default:
					break;
				}
				Console::ResetColor();
			}
			else
			{
				cout << ' ';
			}
		}
		cout << endl;
	}

	// Draw enemies colleted
	Console::ForegroundColor(ConsoleColor::Red);
	Console::SetCursorPosition(offsetX, offsetY + 20);
	for (int i = 0; i < enemiesCollected; i++)
	{
		cout << "& ";
	}
	Console::ResetColor();

	drawViewport();
}