RSS Feed

Multilingual programming

Recently I involve in various projects. And they are using different technologies. I am fervent in programming because it conforms to my theological and philosophical perspective.

The languages and technology I am currently using: AngularJS and NodeJS, .NET MVC with C# Mono, and Ruby on Rails. Other related technologies: Nginx, AWS, migrations, Bootstrap CSS, etc. Besides that, my background is strong fundamental C, C++, and PHP skills; have good experience on Python; some experiences on Java, Android, Perl, and VB Script.

Since the advancement of cloud computing, everything is about server and client. HTML, JavaScript, and CSS are the basic of the basics. Furthermore, I am a Linux user, working on sysadmin tasks becomes much easier.

Naming convention and syntax

Involving in various languages and different development frameworks, there is something very important, that is, naming convention. Unlike syntax, where syntax is the language level rules, naming convention is the framework level rules. That means, when using a certain framework, you should follow the naming convention, especially MVC framework. Because by following naming convention (and file structure as well), the framework will use the corresponding database, view page, and controller as well. That is why, you follow it, your development will work faster, need not to care about the internal algorithms.

And some of the naming conventions, is just the style, not really related to the framework. They are “recommended”, instead of “required”. You must know how to differentiate these two.

Let me explain why the naming convention matters. Web technology is a very interesting area. If you open an HTML file, you will see three kinds of syntaxes: HTML, JavaScript, and CSS. Yes, these kinds of syntaxes exist in one file. JavaScript usually use the camel case, so do HTML DOM methods. CSS selector has no requirement, you can use camel case as well, but it is usually hyphenated identifiers, eg foo-bar instead of fooBar. HTML has no restriction. But the attributes are usually hyphenated, yet the value can be camel case or hyphenated. If it is JavaScript related, then camelCase; if CSS, hyphenated. This is how HTML works.

The above is purely client side HTML. For the server side, we usually use a template engine or template system. MVC uses Razor: Rails uses ERB; ExpressJS uses Jade; etc. So, when using these engines, new syntax comes in. Some template engines allow logical statements written in the view, such as Razor and ERB. As a result, you will see pascal case in Razor, snake case in ERB. So, by looking at these naming conventions and syntaxes, you will know what languages being used and what you should do. On the other hand, AngularJS has a very neat template design. No logical statements allowed in the template. Consequently, the template is very neat!

Pascal case and camel case

I don’t like Microsoft, but I admit that Microsoft has its own strength in some technologies. (Else you will not see Mono in Linux.)

Microsoft uses Hungarian notations in C/C++ documentation, for instance, “szName” means identifier “Name” with zero-terminated string data type. It is less human readable. Currently there are a lot of high level languages, thus human readable is required so EVERYONE can code. That is why the methods/functions are verbs like getSomething, setSomething, countSomething, addSomething, removeSomething, clearSomething, etc.

Microsoft uses PascalCase; JavaScript uses camelCase. Because I am used to work on JavaScript and HTML DOM more, that is why I prefer camelCase. Microsoft doesn’t disallow camelCase, but the PascalCase is a suggested naming convention. The reason I prefer camelCase rather than PascalCase is because, uppercase of the first later like


means data type. And


means variable.

So, using the uppercase of the first letter allows me to differentiate my source code easily. However, Microsoft .NET C# uses PascalCase.

So, the question is, should I follow PascalCase or camelCase when using C#? After working with so many projects, I decided to follow the naming convention as recommended. Just use PascalCase as it is recommended. So that, I can feel the conformity instead of alienation. So, how to differentiate the data type and the variable? That is an easy solution. Just recognise them semantically! Because the programming languages, at the end, are still human readable language.


Lastly, I have to talk about the text editor. Instead of IDE, I prefer my favourite text editor, which can split the view into multiple unlimited windows, or clone multiple unlimited windows. Not only that, the text editor has syntax highlighting in multiple languages in one file like HTML. At the same time, open different file types like Ruby, C#, JavaScript, CoffeeScript, CSS, SASS, SCSS, it can still differentiate them. None of the editor can beat it! Yah! That is Emacs. Emacs is the best programmer editor!

I like Vim too. There is always Emacs and Vim war. I like Vim, as it is a general text editor. Edit any text with keyboard only. Edit configuration files through SSH, Vim is the best. Yet, Emacs is the programmer editor. It takes care the programming language indentation smartly. This is what I need! Highlight all and TAB, everything is formatted!

Technology that you must know

Linux, git, ssh, and Docker.

Linux is the most flexible OS kernel in the world right now. It is used in supercomputer, personal computer, server, embedded system like smart vacuum cleaner, mobile phone, smart TV, etc. Firstly because it is open source, everyone can study it, modify it, and redistribute it. Secondly, thanks to GPL (license). Because of GPL, anyone who use Linux need to open source their code. Those bossy people who knows Windows only and like to earn money without paying any efforts, and never understood programming and programmers, they will never understand the power of Linux and GPL.

git, like Linux, the main author is Mr. Torvalds. It is the most popular source code and revision management tool in the world right now. Those who only know GUI will never understand the power of text files. Those who don’t know what is open source are even more out of their topics.

SSH, with the advancement of cloud computing, you need to access to remote computer or server, SSH is your need!

[B]locking an SSH port for a Linux user is like taking a mouse away from a Windows user! (Powers, 2015)

Then lastly is Docker. It is an OS level virtualisation. The development environment and production environment always has a gap. Therefore, to develop a system in an environment as similar as the production is always a need. For the software level, we can use rbenv or rvm for Ruby, virtualenv for Python. However, if the production environment uses stable version of PHP and Apache, and your working computer is using the latest version of PHP and Apache, are you going to uninstall the latest version and install the stable version? If you have multiple projects, are you going to buy many computers for each of them? One of the solution is virtualisation using virtual machine like VirtualBox. But when we are using virtual machines, we need to reserve the memory and hard disk space to the virtual machines. And some of the hardware cannot be shared, but virtualised, like the graphic card and network card. However, if using container like Docker, it can access the hardware and share the OS libraries. You can also run the GUI application as it is running on the host computer. For those Windows users they will not understand, because Docker is based on Linux technology. However, you can still using Docker on Windows and Mac OS X.

MIUI 7 Google Calendar sync problem

Recently, I found that, the calendar item (agenda) created in MIUI 7 Calendar does not sync to my Google Calendar. Then I ignore it.

And until today, I found that, the agenda from Google Calendar does not sync to MIUI7 Calendar too. Then this will be serious. So, I search around the forum, and finally get this solution.

Install Google Calendar! This will solve the calendar syncing problem. Enjoy!

Unit testing and TDD

  1. I was thinking, WT* is the unit test?
  2. Why should I need unit test?
  3. Why should I spend my time to prepare the test cases?
  4. Why should I spend my time to become a tester instead of a developer?

For the first question, if searching online, what you get are just bunch of almost useless information. They can let you get high score in exam.

For the second question, instead of answering why, I will say, it depends. It depends on the language you are using and the framework that you are using. Let’s say you are working on C programming, there is less support of unit testing library. If you are working on Linux kernel development, unit test is difficult to implement. But, if you are developing web application, then unit testing and other testings are highly recommended. Why? Let me go to the next two answers beforehand.

For the 3rd and 4th questions, if you are not a tester, you no need spend your time specifically to prepare the test case. But, since you are a developer, surely you need to test your function during the development. Then, that is the time you prepare your test cases.

Why do you need “testing”?

Because of the advance of the web applications, the faster web development is needed. That is why there are so many MVC frameworks. But, faster development does not guarantee stable and valid products. In order to make it stable and valid (do what I want), you need to test it.

Since I was developing command-line tools, C/C++ libraries, scripting, desktop application using GUI widgets like GTK+/GTKMM, they are less likely to be tested as MVC. For example, if you are writing a linear function, y=mx+c, are you going to write a test case on it? Surely no. You can write a test case, but it is insignificant to see the advantage of unit testing. Because it is too simple. Nevertheless, if you insist to write the test cases, then you can include the test cases with non numerical input parameters, numerical input parameters, etc. However, since you are not a tester, but a developer, surely you can ignore this kind of testings.

In the case of web development, it is different. The reason is, because your web application involves so many things, MVC: model, view, and controller. It involves I/O, database, HTTP protocols, session, cookie, cache, email, HTML, JavaScript, CSS, etc. So, the question is, how are you going to test your product? Are you going to test everything? Yes, you should test everything. But test from login and click every links, enter various types of inputs, until logout, is just impracticable. So, that is why test-driven development (TDD) comes in. And it involves unit test and integration test. Unit test is the smallest unit testing. It is smallest, to make sure each unit works as expected individually. Only if the unit testing is passed, then we do the integration testing, which tests the units together.

Now, interesting part is writing the test cases. Once we write the test cases, then we can test these cases in automation. This is the part I like most. When you do the testing, it will go through all the test cases you have written. This means that, we can get the bugs when we do the development and testing. Since the web application involves so many components, we will break the functionality easily when we add some features. By adding new functions, we modify the old function, and accidentally break the old functions. Without using automated testing, we will prone to test the new functions only, because we “knew” that, old functions work.

So, using unit test and integration test, we can make sure that our product passes all the test cases. And we are confident that our product is not just being tested with the latest function, but the existing functions are still working.

Dell Vostro 5459 review and setup

Due to the changes of the career, I invested on Dell Vostro 5459, after a long survey. I chose it because it is compatible to Linux. The compatibility to Linux meaning that, all the hardware devices are accessible by Linux. Besides that, it has the NVIDIA graphic card, which allows me to use GPGPU to do my research and study. Moreover, I can play high quality 3D graphics games.


So, the laptop I bought was pre-installed with Ubuntu. And, I was impressed by the Ubuntu first boot video, which can be found here.

Partition and bootloader

It is new laptop, thus the hard disk partitioning table is using GPT format instead of MBR format. And the laptop uses UEFI boot system by default. It will be very convenient to have multiboot with several OSes.

In order to do partitioning, I used my favourite tool, SystemRescueCD. But I failed to run the X11 window, due to the very new NVIDIA graphic card. (I believe I can run the X11 now.)

Before partitioning and formatting the hard disk, I checked the xorg.conf from the existing Ubuntu, believed that it can help me to figure out how to start X11 window in SystemRescueCD. Then I discovered that /etc/X11/xorg.conf does not exist. This is a very important point.

Consequently, I used the command-line interface to re-partitioning the hard disk. Because I was going to install Windows and Arch Linux on it.


Though I prefer Linux, Ubuntu not my primary OS. So, I have to install the Arch Linux. Before installing Arch Linux, due to the luxurious hardware specification, I intended to install Windows 7. The laptop does not have USB2.0, but only USB3.0, and I didn’t want to install Windows 7 through external DVD-ROM, because I didn’t want to burn Windows 7 to a DVD. As a result, Windows 7 with USB3.0 cannot be installed. Looking for the solution, extra drivers are required. Thus, I gave up Windows 7 and tried Windows 8.1. (Sorry, Windows 8 and 10 are not my favourite.)

Great. Windows 8.1 is not bad after installation. I came back to Windows drivers later, since Windows is my secondary OS, for the purpose of… gaming.

Arch Linux

Installing Arch Linux needs some skills, and Internet connection is very important. So, I installed all the packages based on the old laptop, just following the powerful Arch Linux Wiki.


NVIDIA GeForce 930M is very troublesome. After installing Arch Linux, to fully utilise my graphic card, I decided to use NVIDIA driver instead of Nouveau.

However, nvidia-xconfig generated xorg.conf file does not work. I failed to run the X11 window as in the SystemRescueCD.

As a result, I removed the NVIDIA related section in the xorg.conf according to the Arch Linux forum here. And the pre-installed Ubuntu does not have the xorg.conf as well. After removing the file, X11 window works fine.

After running the Arch Linux and configuring my preferences, I found that some of the screensavers (from xscreensaver) showed the error message,

Xlib: extension "GLX" missing on display ":0"

So, I knew that there is something wrong with my Xorg configuration and the NVIDIA.

Keep doing the trial and error, then I discovered something called bumblebee. Actually I am still very confused with this bumblebee, only know that it is related to NVIDA Optimus. And, I also don’t know what the hell is NVIDIA Optimus, only know that it is something wonderful.

After installing bumblebee, then the nvidia-libgl package is replaced by mesa-libgl. And the xscreensaver did not show the error message above anymore.

Since installed bumblebee, I supposed I can use Optimus with optirun command. Running

optirun glxgears -info

I got the new error,

libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast

Then, I thought may be my NVIDIA is too new, so I tried to install nvidia-beta. But it did not solve the problem as well.

As a result, I tried nvidia-dkms. Yeah! It works. “optirun” works fine now.

Windows 8.1

I love Dell, because the drivers are available online. I just download all the important drivers, graphic card, sound card, WiFi drivers, etc. Then I booted into Windows 8.1, and installed all the drivers. I just wonder, Arch Linux can use the WiFi device immediately during the installation, but Windows cannot? That means, if I have Windows and WiFi only, but does not have the driver, then how can I download the drivers?

After installed all the drivers, then I booted into Arch Linux, but failed. Because I failed to mount the Windows partition in Linux after installing the drivers. Then I found that, it is because of the Fast Startup feature in Windows 8. (Solution is here, look for the Fast Startup.) Because Fast Startup causes the partition “not clean”, so that Linux cannot mount it.

After disabling the Fast Startup, then everything works fine now.

Data transfer

Transferring vast amount of data between computers is very time consuming. I previously used an external hard disk. But transferring data from a 500G laptop to a 1T laptop, using an external hard disk is not applicable, since I don’t have extra empty hard disk.

At the end, I used the ethernet cable to transfer the data. (This is what I learnt from my student previously.) In Linux, I used the Network Manager to share the wired connection. Then directly connect two laptops with a single ethernet cable, and router is not required. Ethernet cable is faster than WiFi, and I can transfer whatever data I want from A to B or vice versa.

But still, I have to use the SSH to mount the target laptop.

This is a time consuming process.

Hibernation and resume issue

Now the only problem is resume from hibernation in Arch Linux. The resuming from hibernation works inconsistently. I have tried to install Linux LTS version, but it is worse because I cannot use Fn key after booting in Linux LTS.

I am still figuring out how to solve this problem.

Best ever programmer text editor: Emacs

I was using jEdit. And once willing to change to, so called modern text editor, Atom Text Editor. Then I did some comparisons among the text editors. At the end, now my primary text editor for coding is Emacs.

Emacs requires some time to learn and practise. But at the end, I love it too much. It is so powerful, no other text editor to compare with it. But the primary usage is for coding.

What are the advantages? It has various powerful addons (packages). It is highly customisable. It can work in command-line, that means you can use it over the SSH. (But normally I use Vim instead.) Like Vim, it can browse a directory. It can also perform diff and merge (but I use meld usually). It can work with gdb for debugging. It has syntax highlighting on different languages. It can perform different indentation based on various languages. Syntax highlighting can work on web development which combines JavaScript, CSS, HTML, and even PHP (using “web mode”). It can save the opened files as a project, so that you can work on multiple projects. It can split the views vertically and horizontally, basically unlimited splits. If you want, you can play Tetris in it. It can be used as window manager too.

There are several modes that are interesting. I suggest to know these modes:

  • dired – Directory browsing
  • ibuffer – List and manage opened files
  • eshell – Emacs shell, like bash
  • ielm – Inferior Emacs Lisp Mode. Interactive Lisp environment
  • w3m – w3m web browser, requires package installation.
  • eww – Default web browser in Emacs, but I found it is difficult to use compared to w3m

Customising Emacs to fit your pattern requires some time.

Just share my .emacs file,

 ;; custom-set-variables was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(buffers-menu-max-size 10)
 '(column-number-mode 1)
 '(ediff-split-window-function (quote split-window-horizontally))
 '(inhibit-startup-screen t)
 '(show-paren-mode t)
 '(tool-bar-mode nil))
 ;; custom-set-faces was added by Custom.
 ;; If you edit it by hand, you could mess it up, so be careful.
 ;; Your init file should contain only one such instance.
 ;; If there is more than one, they won't work right.
 '(default ((t (:family "DejaVu Sans Mono" :foundry "unknown" :slant normal :weight normal :height 113 :width normal)))))

;; Emacs default setting
(desktop-save-mode 1)
(global-linum-mode 1)
(savehist-mode 1)
(global-auto-revert-mode t)
(setq column-number-mode 1)
(delete-selection-mode 1)

(setq backup-inhibited t)
(setq auto-save-default nil)
(setq mouse-drag-copy-region nil)

(setq-default indent-tabs-mode nil) ;;Disable indent tabs globally
;;Create my own function
(defun my-toggle-tab ()
  (if (default-value indent-tabs-mode)
        (message "Space indent")
        (setq indent-tabs-mode nil)
      (message "Tab indent")
      (setq indent-tabs-mode t)
(global-set-key (kbd "C-x C-t") 'my-toggle-tab)

;; Very annoying that override the content with delete word
(defun backward-delete-word (arg)
  "Delete characters backward until encountering the beginning of a word.
With argument ARG, do this that many times."
  (interactive "p")
  (delete-region (point) (progn (backward-word arg) (point))))
(global-set-key (kbd "<M-backspace>") 'backward-delete-word)

;; Change font for Chinese characters
(set-fontset-font t 'han (font-spec :family "WenQuanYi Zen Hei Mono"))

;; mouse from
(setq mouse-wheel-scroll-amount '(4 ((shift) . 1))) ;; one line at a time
(setq mouse-wheel-progressive-speed nil) ;; don't accelerate scrolling
(setq mouse-wheel-follow-mouse 't) ;; scroll window under mouse
(setq scroll-step 1) ;; keyboard scroll one line at a time

;; Delete whitespace when save
(add-hook 'before-save-hook 'delete-trailing-whitespace)

;; White space mode
(global-whitespace-mode 1)
(autoload 'whitespace-global-mode "whitespace"
  "Toggle whitespace visualization." t
  (setq whitespace-style (quote (face spaces tabs space-mark tab-mark)))
(autoload 'whitespace-toggle-options "whitespace"
  "Toggle load `whitespace-mode' options." t)

;; Add MELPA
(require 'package)
(add-to-list 'package-archives
	     '("melpa" . ""))
(when (< emacs-major-version 24)
  (add-to-list 'package-archives '("gnu" . "")))

;;Recent file
(require 'recentf)
(recentf-mode 1)
(setq recentf-max-menu-items 15)
(global-set-key (kbd "C-x C-r") 'recentf-open-files)

;; Load undo-tree and set the undo/redo hotkey
(require 'undo-tree)
(global-undo-tree-mode 1)
(global-set-key (kbd "C-z") 'undo-tree-undo)
(global-set-key (kbd "C-S-z") 'undo-tree-redo)

;; Smooth scroll
(require 'smooth-scroll)
(smooth-scroll-mode 1)

;; Enable auto-complete
(require 'auto-complete)
(global-auto-complete-mode 1)

;; Enable hideshowvis to fold and expand the code
;;(require 'hideshowvis)
;;(hideshowvis-minor-mode 1)

;; Make web-mode to indent with 2 spaces,
(require 'web-mode)
(defun my-web-mode-hook ()
  "Hooks for Web mode."
  (setq indent-tabs-mode nil)
  (setq tab-width 4)
  (setq web-mode-markup-indent-offset 2)
  (setq web-mode-css-indent-offset 2)
  (setq web-mode-code-indent-offset 2)
  (setq web-mode-style-padding 0)
  (setq web-mode-script-padding 0)
  (setq web-mode-enable-css-colorization t)
(add-hook 'web-mode-hook  'my-web-mode-hook)

;; Disable csharp-mode tab
(require 'csharp-mode)
(defun my-csharp-mode-fn ()
  "function that runs when csharp-mode is initialized for a buffer."
  (setq indent-tabs-mode nil)
(add-hook  'csharp-mode-hook 'my-csharp-mode-fn t)

;;Auto js2-mode
(autoload 'js2-mode "js2-mode.el" nil t)
(add-to-list 'auto-mode-alist '("\\.js$" . js2-mode))

(autoload 'web-mode "web-mode.el" nil t)
(add-to-list 'auto-mode-alist '("\\.html$" . web-mode))
;; (add-to-list 'auto-mode-alist '("\\.php$" . web-mode))

(autoload 'pkgbuild-mode "pkgbuild-mode.el" "PKGBUILD mode." t)
(setq auto-mode-alist (append '(("/PKGBUILD$" . pkgbuild-mode)) auto-mode-alist))

(require 'w3m-load)
(setq w3m-default-display-inline-images t)

(require 'desktop+) ;;Use the desktop+

;; (autoload 'php-mode "php-mode.el" "Php mode." t)
;; (setq auto-mode-alist (append '(("/*.\.php[345]?$" . php-mode)) auto-mode-alist))
;; (autoload 'python-mode "python-mode.el" "Python mode." t)
;; (setq auto-mode-alist (append '(("/*.\.py$" . python-mode)) auto-mode-alist))

It would be better if you learn Emacs from the beginning and try to adapt the default key bindings (hotkeys). Because, if you replace some of the hotkeys with the ones you are used to, you may miss the default key binding power. No more Ctrl+X, C, or V for cut, copy, and paste. Just learn Emacs and customise it.

One more thing, I was looking for folding (collapse and expand) feature. But failed to find one. Yet, just use the key binding C-M-p and C-M-n are enough to fit my demand.

The following is the video which I screencasted with SimpleScreenRecorder and edited by Blender.

Data structure and algorithm

As a computer science lecturer (though I am from cognitive science background, and even labelled as NOT from computer science, 士可杀,不可辱!), I focus on the fundamental knowledge and experience. I focus on C/C++ language on my students, because only have good fundamental knowledge and skills, then they can survive with the evolving technology once they graduated. For example, Flash was popular technology, yet now it is dying. Those who know Flash only, have to learn new technology. Without fundamental skill, how to cope with the new technologies that emerge everyday? Know the root, then you can get any leaf.

So, I gave my students an assignment. The assignment requires them to write a program that can

  • Read a text file as a map, with binary information in the map, block or space. Block does not allow to move; the space allows to move.
  • Find the route from upper left to the lower right (assuming that there is at least one route in the map file.)
  • Show the route that goes from upper left to lower right through the space.

To write a program, the first thing is to design the data structure that can hold the input/output data. Only with the good data structure, then the algorithms will emerge automatically.

I personally spent around 3 hours to write the program using C++ language, but not object oriented and omitted the STL. No object oriented involved, but only struct. The solution involves 2D array, linked list, tree (ADT) and tree traversal, and stack with doubly linked list.

The file is read line by line, and converted into 2D array. Then using the 2D array, convert this 2D map with blocks and spaces into a tree data structure. The spaces are connected as the tree nodes, the blocks are ignored. Each node has an (x, y)-coordinate. Once the tree data structure is completed, then I wrote a depth first search (DFS) as a tree traversal, start from the upper left, and target the lower right. However, because it is a DFS, it will try all branches in the search tree. So, I have to use a stack (using doubly linked list) to store the route that straight to the destination. Finally, the route in the stack is printed.

No GUI, because inside-out is important, just like a pretty apple with rotten content is good for nothing. What I focus is the inner quality (attitude, hardworking, problem solving, etc), not the flattering or boasting. Since I am a Catholic, Chinese, cognitive science student, programmer, and INTJ personality (if you don’t know what is INTJ, please go to google it), when it is true, I say true; when it is false, I say false; when I don’t know, I say I don’t know. All the BS reserved for those BSers. Since I am a lecturer, it is my responsibility to optimise my lecturing function to guide the students in their studies. It is a shame for those academic murderers who exploit the students in order to get their own fame, get the research grant, and plagiarise the students’ work to publish their own research papers.

So, the coding I wrote also demonstrates the usage of pointer (computer science students MUST know), dynamic memory allocation, and recursive function (important in FP).

#include <cstdio>
#include <cstring>
#include <cstdlib>

struct MapNode {
  MapNode *up;
  MapNode *down;
  MapNode *left;
  MapNode *right;
  int data;
  int x;
  int y;
  int visited;

 * This is just like the OOP object constructor.
MapNode* mapNodeCreate(int x, int y, int data) {
  MapNode *n = new MapNode;
  n->up = NULL;
  n->down = NULL;
  n->left = NULL;
  n->right = NULL;
  n->x = x;
  n->y = y;
  n->data = data;
  n->visited = 0;
  return n;

 * The following stack design is like this,
 * the Stack is a container of the StackNode*.
 * The StackNode contains MapNode*
 * Therefore, using the Stack ADT, we can push and pop the StackNode.
 * Since the StackNode is a doubly linked list, at the same time it holds the MapNode* (pointer)

struct StackNode {
  MapNode *mapNode;
  StackNode *next;
  StackNode *prev;

StackNode* stackNode(MapNode *mapNode) {
  StackNode *n = new StackNode;
  n->mapNode = mapNode;
  n->next = NULL;
  n->prev = NULL;
  return n;

 * So, a Stack contains several StackNode*.
struct Stack {
  StackNode *head;
  StackNode *tail;

Stack* stackCreate() {
  Stack *s = new Stack;
  s->head = NULL;
  s->tail = NULL;
  return s;

void stackPush(Stack *s, StackNode *n) {
  if(!s->head) { //First item
    s->head = n;
    s->tail = n;
  else { //If there is a node
    s->tail->next = n;
    n->prev = s->tail;
    s->tail = s->tail->next;
    //Make sure it is the last
    s->tail->next = NULL;

int stackSize(Stack *s) {
  int size = 0;
  StackNode *curr = s->head;
  while(curr) {
    curr = curr->next;
  return size;

StackNode* stackPop(Stack *s) {
  StackNode *n = s->tail;
  s->tail = s->tail->prev;
  s->tail->next = NULL;
  return n;

void stackPrint(Stack *s) {
  StackNode *curr = s->head;
  while(curr) {
    printf("(%d, %d)\n", curr->mapNode->x, curr->mapNode->y);
    curr = curr->next;

MapNode **list; //For storing the nodes, then delete them at the end
Stack *stack = stackCreate(); //For storing the coordinates, default will head NULL and tail NULL

 * In order to solve this, this is very complicated. Firstly, I used
 * a variable depth to check when is the push and pop are appropriate,
 * As a result, convert the depth++ to the push and depth-- to the pop
 * to make sure that only correct nodes are stored, and incorrect nodes will be popped.
 * So, this function is traversing all the route, and push the correct route to the stack.
void mapTraverse(MapNode *node, int x, int y, bool *stop) {
  if(!*stop) //Push only if still searching
    stackPush(stack, stackNode(node));

  if(*stop) {
  if(!node) {
  if(node->visited) {

  if(node->x == x && node->y == y) {
    *stop = true;
    printf("(%d, %d) Found!!\n", node->x, node->y);
  node->visited = 1; //mark visited
  printf("(%d, %d), ", node->x, node->y);
  mapTraverse(node->left, x, y, stop);
  mapTraverse(node->up, x, y, stop);
  mapTraverse(node->right, x, y, stop);
  mapTraverse(node->down, x, y, stop);
  if(!*stop) { //Do not pop if founded.

void arrPrint(int *arr, int w, int h) {
  for(int i=0;i<h;i++) {
    for(int j=0;j<w;j++) {
      printf("%d ", arr[i*w + j]);

 * The text file is the binary (1 or 0) content.
 * @param w is the pointer to the width (output)
 * @param h is the pointer to the height (output)
 * @return a pointer of integer for the map.
int* readFileToArray(const char* filename, int *w, int *h) {
  FILE *fp = fopen(filename, "r");

  if(!fp) {
    fprintf(stderr, "Failed to open file\n");
    return NULL;

  char buffer[256];

  //This method (supposed) only applicable for the text file with "\n" (Unix file),
  // not the "\r\n" or "\n\r" (Windows or MacOSX)
  //Get the map dimension first.
  fgets(buffer, 255, fp);
  int width = strlen(buffer) -1;

  //Go to the end of the file
  fseek(fp, 0, SEEK_END);
  int height = ftell(fp) / (width+1);

  printf("width: %d\theight: %d\n", width, height);

  //Go back to the beginning of the file
  fseek(fp, 0, SEEK_SET);

  //Create an array
  int *arr = new int[width * height];
  int *cursor = arr;

  while(fgets(buffer, 255, fp)) {
    buffer[strlen(buffer) -1 ] = 0;
    for(int i=0;i<strlen(buffer);i++) {
      *cursor = buffer[i] - '0'; //Convert the character to the value

  //Get the width and height
  *w = width;
  *h = height;

  return arr;

MapNode* arrToMap(int *arr, int width, int height) {
  //Use an array to store the map node
  list = new MapNode*[width * height]; //This is the syntax that creates an array of pointer (with "*") after the data type.

  for(int j=0;j<height;j++) {
    for(int i=0;i<width;i++) {
      //Create the node
      MapNode *node = mapNodeCreate(i, j, arr[j*width +i]);
      list[j*width +i] = node;

  //Check the connectedness horizontally
  for(int i=0;i<height;i++) {
    for(int j=0;j<width -1;j++) {
      if(arr[i*width+j] == 1 && arr[i*width +j+1] ==1) {
        list[i*width+j]->right = list[i*width +j+1];
        list[i*width+j+1]->left = list[i*width+j];

  //Check the connectedness vertically
  for(int i=0;i<height-1;i++) {
    for(int j=0;j<width;j++) {
      if(arr[i*width+j] == 1 && arr[(i+1)*width +j] ==1) {
        list[i*width+j]->down = list[(i+1)*width +j];
        list[(i+1)*width+j]->up = list[i*width+j];
  MapNode *root = list[0];

  return root; //Return the first node

int main(int argc, char **argv) {
  if(argc < 2) {
    printf("Usage: %s map.txt\n", argv[0]);
    return 1;

  int width, height;
  int *arrMap;
  arrMap = readFileToArray(argv[1], &width, &height);

  arrPrint(arrMap, width, height);

  MapNode* mapRoot = arrToMap(arrMap, width, height);

  //Traverse the nodes;
  bool stop = false; //use this to control so that once found, need not to perform recursive search
  mapTraverse(mapRoot, width-1, height-1, &stop);

  printf("Stack size %d\n", stackSize(stack));


  delete arrMap;

  //Delete all the nodes
  for(int i=0;i<width * height;i++) {
    delete list[i];

  delete stack;

  return 0;

The sample input text file,


And this is the output

width: 20	height: 15
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 
1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 
1 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 1 1 1 0 
0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 0 
0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 
0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 

(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 4), (2, 4), (3, 4), (4, 4), (5, 4), (6, 4), (7, 4), (8, 4), (8, 3), (8, 2), (8, 1), (9, 1), (10, 1), (11, 1), (12, 1), (13, 1), (14, 1), (15, 1), (16, 1), (17, 1), (14, 2), (14, 3), (14, 4), (13, 4), (12, 4), (11, 4), (10, 4), (9, 4), (15, 4), (16, 4), (17, 4), (18, 4), (14, 5), (14, 6), (15, 6), (16, 6), (17, 6), (18, 6), (5, 5), (5, 6), (5, 7), (5, 8), (4, 8), (3, 8), (2, 8), (1, 8), (0, 8), (5, 9), (6, 9), (7, 9), (8, 9), (9, 9), (10, 9), (11, 9), (12, 9), (13, 9), (14, 9), (10, 10), (10, 11), (10, 12), (11, 12), (12, 12), (13, 12), (14, 12), (15, 12), (16, 12), (17, 12), (17, 13), (18, 13), (18, 14), (19, 14) Found!!
Stack size 34
(0, 0)
(0, 1)
(0, 2)
(0, 3)
(0, 4)
(1, 4)
(2, 4)
(3, 4)
(4, 4)
(5, 4)
(5, 5)
(5, 6)
(5, 7)
(5, 8)
(5, 9)
(6, 9)
(7, 9)
(8, 9)
(9, 9)
(10, 9)
(10, 10)
(10, 11)
(10, 12)
(11, 12)
(12, 12)
(13, 12)
(14, 12)
(15, 12)
(16, 12)
(17, 12)
(17, 13)
(18, 13)
(18, 14)
(19, 14)



Get every new post delivered to your Inbox.

Join 170 other followers