Why Do You Need to Automate Your Hiring Process in 2019?

Please follow and like us:

Managing recruitment and selection process is one of the most critical, time consuming tasks. It is essential for any organization to recruit well qualified and suitable employees. As a growing company, you need the right tools to manage your hiring process. A significant amount of time and resource can be taken up with the hiring process unless you automate.

According to LinkedIn, the most important recruiting KPIs are:

* Quality of hire

* Time to hire

Experts believe that by streamlining some aspects of the recruiting process, recruitment automation will enhance a human recruiter’s capabilities.

Here are some major ways recruitment automation is changing recruiting

  • Assess them Before You Interview Them

You could assess or gauge prioritization abilities, IQ and other relevant qualities even before the aspiring candidates step into your office. A vast majority of talent acquisition leaders say the hardest part of recruitment is identifying the right candidates from a large pool of applicants. The system assesses prospective candidates by surfacing key data points that cannot be found on resumes. It can be used to track the candidates’ career highlights, likelihood of switching jobs, company fit and aptitude.

  • Ensure Consistency in Hiring Process

The recruitment process involves a number of steps and when done manually there are huge mistakes created due to human error. The entire process can be streamlined and automated.

  • Free Yourself for More Productive Tasks

Free yourself or your team from mundane tasks that can be automated and utilize the same resources for other productive tasks, thus increasing efficiency and productivity.

  • Automate Screening Questions

Filter through hundreds of applicants and end up with only those candidates who are apt for your organizations vision and values, in the process helping you weed out the candidates who do not meet your requirements. Just imagine the number of hours you would have otherwise spent interviewing these candidates, setting up infrastructure for assessment tests and multiple rounds of interviews. Evaluating Common Sense, Emotional Intelligence, Communication, Fluency and many important KPI’s are key to “Quality of Hire” while screening for prospective team members, and this can be fully automated with industry standard baselines.  

  • Keep Candidates Informed via Automated Emails

Recruiters waste a lot of time responding to calls/emails from candidates they have interviewed. Use automated emails to let them know the status of their application.

  • Automate the Offer Process

The system can generate automatic offer letters, contracts and other documents along with rejection letters based on customizable workflows tailored to each organization’s recruiting standards.

  • Automate Employee Onboarding

Aspiring applicants have already gone through the process of application and filling in details and majority of the organizations have to go through the same basic information to be filled in again with the employees who join. By connecting the Recruiting Platform with Company Portal systems, a vast majority of the data can be copied over and will assist in speeding up the on boarding process from Day One. There are some MNC’s who have even adopted completing paperwork via digital transformations even before the employee show up on Day One. Automation can help with a number of activities such as setting up IT access, notifying Product/Project stakeholders, operations workflow for new joiners and so on.

  • Screening resumes: Automate score | rating

Industry experts consider screening resumes is still the most   time consuming part of recruiting. Upto, 88% of resumes received for a role are considered unqualified. On an average, a recruiter spends 23 hours screening resumes for a single hire. Through the hiring automation platform, the score/ rating is allocated to the candidates based on the inputs they provide. They are assessed on several levels such as aptitude, technical skills and other relevant skills. A filter incorporated in the system helps to select only relevant skill assessment categories for a particular role.

  •  Helps in having a pipeline of Talent

Using the hiring automation platform helps in creating a database of the qualified candidates you were not able to hire, but is suitable for another role, down the road.

Looking Ahead…

In 2019, finding top talent will depend on the recruiters’ ability to intelligently automate their work flow.

It is imperative to ensure that the recruitment process is conducted in a smooth and consistent manner so as to ensure that we hire the best talent in the market. Just as salespeople and marketers have benefited from software enabled automation in recent years, recruiters are increasingly turning to automated platforms for hiring the best talents

Armed with cutting edge tools and insights, recruiters can refine the process, eliminate inefficiencies, mitigate biases and get across to the top talent in minimum time. According to a survey conducted, 75% of recruiters say technology will play a big role in their company hiring process in 2019.

 Majority of recruiters worldwide are happy to consider a more data driven approach, most of them do not have time to turn the data to actionable insights. It is found that data driven recruiting teams are far outperforming their peers. Leveraging these insights, to optimise the recruiting strategy, increases the team productivity and gives the organisation a competitive advantage. Intelligent and smart way of recruiting through hiring automation helps to analyse candidates’ data quickly and make decisions faster. It helps to ensure that all the best fit candidates were identified and engaged, resulting in better quality hires and a higher performing organisation

Adopting automation platforms is helping recruiters screen candidates and shortlist quality applicants in record time.

Research also suggests that most companies depend on employee referrals for some important roles to avoid hiring misfits. This could negatively impact their ability to attract the best talent. Utilising automation, increases efficiency, offloads tedious mundane and repetitive tasks. As a result of this, it helps in reducing time-to-fill and cost-per-hire.

PQube has been in the forefront to address these pain points of sourcing and recruiting process. Get yourself a top notch, best in class, custom made hiring automation platform and some peace of mind. Through our end-to- end automation platform, you can speed up candidate discovery and qualification processes and float best-fit candidates to the top of your talent pipeline. Work Smarter, Not harder!

Technology is not a tool. It can give learners a voice that they might not have had before George Couros

Please follow and like us:

How to Write an Unbeatable Tic-Tac-Toe in JavaScript

Please follow and like us:

Writing small puzzle games is a nice way of improving your programming skills as those games tend to present you with challenge after challenge and force you to really put tremendous thought into writing your code. 

One such game is the classic Tic-Tac-Toe.

In this little walk-through (read long and descriptive) about writing an unbeatable tic-tac-toe, I will be using Vanilla JavaScript for logic and HTML/CSS for UI. I won’t be concentrating much on UI part of it, because, duh! 

Another little disclaimer – we will be concentrating on logic primarily and code will come second to that. Again, if you want to skip the “walk-through” and jump right to the code, I have a public repository on GitHub at https://github.com/FaisalST32/tic-tac-toe. I also have a live version of the game available at https://games.faisalrashid.online/tictactoe/

So, let’s dive in.

First of all you need to create the UI. Just use simple HTML to create 9 input boxes, or divs even to hold your X’s and O’s. The id’s of these input boxes are important as they will be our reference to the X’s and O’s. To keep it consistent with the positioning of our boxes, I have given the input boxes the id’s “0-0” to “2-2”. To visualize: 


This will give us an easy to use 3×3 matrix. You can design your UI whatever way you want. It should simply employ this form of queryable HTML elements. 

Here’s a screenshot of my UI. Simple boxes with a little gloss of CSS.

Now, the logic! First of all, whenever a user, or a participant in this case, clicks or taps an empty box, the value of that box should change to either an X or an O, depending upon whose turn it is.

Implementing that is simple. I use a global variable to hold the ‘currentPlayer‘. This variable has a value of either X or O. Then I simply write a method to toggle current player, whenever a box is tapped. I call the method changePlayer.

All this is started by tapping a box. So, we need a function to get us started. We write a function that marks the box with X or O and changes player. We call the function onCheckBox. So far, the function checks a box and and then changes player.

Now, while the boxes are being tapped, we need to keep track of the checked boxes. Using an array should help us get this job done. Simply holding the id’s of all the boxes is useful, but it’s not enough. We will definitely need to hold the id’s (co-ordinates in this case) as well as the player who checked the box. So, our checkedBoxes array will be an array of objects of this form:

[{box: ‘0-1’, player: ‘X’}, {box: ‘2-1’, player: ‘O’}, …]

We now have two global variables – one to hold currentPlayer and other to hold checkedBoxes.

Another thing that I like to keep track of is the Turn Count. I can get that from the chekedBoxes array, but this way it’s simpler and very useful if I’m manipulating the checkedBoxes array.

Since we will be writing a Player vs CPU mode only (github repo contains both 1p and 2p modes), these are all the global variables that we are going to need – checkedBoxescurrentPlayer and turnCount.

NOTE: It’s always good practice to keep your global variables at a minimum to avoid dependencies and unexpected behavior within functions.

I believe our onCheckBox method is now ready. This is what it looks like

function onCheckBox(element) {
   checkedBoxes.push({ box: element.id, player: currentPlayer });
   var   gameStatus =checkWinner();   //Will come to this method in a bit
}function checkElement(element){
     element.value = currentPlayer;     
     element.disabled ="disabled";
}function switchPlayer() {
    currentPlayer = currentPlayer =="X"?"O":"X";
    document.querySelector('.current-player').textContent = currentPlayer;

We are passing the clicked Html element as one of the parameters to the method to access it’s id for coordinates. Everytime we check a box we need to check whether there is a winner or whether the game is drawn.

This brings us to our the checkWinner method. This method simply checks whether the X’s or O’s are in a single line (rules of tic-tac-toe) to determine whether there is a winner. It’s not very difficult to build that logic. We query the checkedBoxes array and find all the coordinates with player X. If the coordinates follow the pattern (a-0, a-1, a-2) or (0-a, 1-a, 2-a) where a = 0 or 1 or 2, then we have a horizontal or vertical line checked. Well, diagonal lines are a little tricky. For right to left diagonal, we use (a-a, b-b, c-c) and for left to right diagonal we use (0-2, 1-1, 2-0). If we find any of these patterns in the checkedBox matrix then the ‘player’ having the pattern is the winner. If none of these patterns match, then we simply check whether one of the two players has checked 5 boxes to determine that it’s a draw. 

function checkWinner(isCheckOnly=false) {
if (currentPlayer =="X") {
//Get all the boxes marked by Player X
   var  xs = checkedBoxes.filter(item=> item.player =="X").map(value=> {
     return { x: Number(value.box.split("-")[0]), y: Number(value.box.split("-")[1]) }
else if (currentPlayer =="O") {
//Get all the boxes marked by Player O
   var  os = checkedBoxes.filter(item=> item.player =="O").map(value=> {
     return { x: Number(value.box.split("-")[0]), y: Number(value.box.split("-")[1]) }
}function calculateScore(positions) {
//Check right diagonalif (positions.filter(i=> { return i.x == i.y }).length ==3) {
              return'game over';
}//Check Left diagonal
if (positions.filter(i=> { return (i.x ==0&& i.y ==2) 
                                    || (i.x ==1&& i.y ==1)
                                    || (i.x ==2&& i.y ==0) }).length ==3) {
                return'game over';
//check horizontal match
for (var i =0; i <3; i++) {
  var  consecutiveHorizontal = positions.filter(p=> p.x == i);
  if (consecutiveHorizontal.length ==3) {
       return'game over';
//check vertical match
  var  consecutiveVertical = positions.filter(p=> p.y == i);
  if (consecutiveVertical.length ==3) {
        return'game over';
//check draw
if (positions.length ==5) {
  return'game drawn';
//if none of the conditions match 'game on'
return'game on';

Here I’m delegating the responsibility of finding result to calculateScore method. These two methods are essentially translating what we said above to JavaScript code. Nothing fancy here.

Let’s try something now. Shall we? I believe our game is now ready to handle all the tic-tac-toe logic. What remains is making it unbeatable. To make the game unbeatable, I want to set some ground rules to avoid making this post excruciatingly long (you’re kidding, right). The CPU will always play second and will be primarily focused on not letting the opponent win. So, our onCheckBoxmethod will see the addition of the method computerPlays for CPU’s turn. 

function onCheckBox(element) {
checkedBoxes.push({ box: element.id, player:
    currentPlayer });
     gameStatus = checkWinner();
  if (turnCount %2 == 1&&
    gameStatus == 'game on'){

As you can see the computerPlays method will only be called if the turnCount is odd, ie, it’s 2nd, 4th, 6th or 8th turn, and if gameStatus returned by the checkWinner method is ‘game on’ as there is no point in continuing the game, if the game is already over. To understand how to counter a human move, I came up with 5 cases. These five cases in the order of their priority are: 

  1. First Move
  2. Finishing Move that allows CPU to win the game.
  3. Saving Move that allows CPU to save the game.
  4. Predicting a move that will trap the CPU and avoiding it.
  5. And if none of these fit, a Random move.

Here’s a sneak preview of our computerPlays method.

function computerPlays() {
  var  nextBoxCoords;
  if(turnCount ==1){
nextBoxCoords =computeFirstMove();
  if (!nextBoxCoords){
nextBoxCoords =computeFinishingMove();
}  if (!nextBoxCoords) {
nextBoxCoords =computeSavingMove();
  if (!nextBoxCoords)
nextBoxCoords =predictTrappingMove();
  if (!nextBoxCoords) {
nextBoxCoords =computeRandomMove();
  var  nextBox = document.querySelector(`[id='${nextBoxCoords}']`);

1. First Move

Computing first move is out of experience, although, I could have written an algorithm for it. But to avoid complexity, I just went with past experience. If it’s CPU’s first move, we need to find where the opponent played. If it’s center box, we return a corner box. Similarly, if he played a corner box, we return an edge box adjacent to it and finally if he played an edge box, we return the center box. By the way, 1-1 is the center box, 0-1, 1-0, 1-2, 2-1 are the edge boxes and, you guessed it, 0-0, 0-2, 2-0, 2-2 are the corner boxes.

Here it is,

function computeFirstMove(){
  var  playedMove = checkedBoxes.map(b=> b.box)[0];
  var  edgeMoves = ['0-1', '1-0', '1-2', '2-1'];
  var  cornerMoves = ['0-0', '0-2', '2-0', '2-2'];
  var  centerMove = ['1-1'];
  if(edgeMoves.find(m=> m == playedMove))
  else if(cornerMoves.find(m=> m == playedMove))
  else if(centerMove.find(m=> m == playedMove))
    return cornerMoves[Math.floor(Math.random()*cornerMoves.length)];
}function edgeMoveResponse(playedMove){
  if(playedMove =='1-2') 
  else if (playedMove =="0-1") 
  else if (playedMove =="1-0") 
  else if(playedMove =='2-1') 

To avoid cramming up the computeFirstMove method, I moved out the edgeMoveResponse method. Now, that we got the first move sorted, let’s move to the next check – computeFinishingMove

2. Finishing Move that allows CPU to win the game.

If the opponent is there for the taking we would prioritize taking him. Let’s say we have the following situation: 

Since, it’s CPU’s turn (O) we would definitely want to check the lower-right box. That’s where our computeFinishingMove method comes in. It simply iterates over all the remaining boxes and checks them one by one. It then calls the checkWinner method on each iteration and if there’s a winner, just returns the box of that iteration as the ‘nextBoxCoords‘ to the computerPlays method. Here’s the code: 

function computeFinishingMove() {
  var  remainingMoves =getRemainingMoves();
  var  finishingMoveCoords;
  for (var move of remainingMoves) {
    checkedBoxes.push({ box: move, player: currentPlayer });
    var  nextBox = document.querySelector(`[id='${move}']`)
    if (checkWinner() =='game over') {
finishingMoveCoords = move;
      onUncheckBox(nextBox, true);
    onUncheckBox(nextBox, true);
    console.log('Playing Finishing Move')
    return finishingMoveCoords;
}function getRemainingMoves() {
  var  allMoves = ['0-0', '0-1', '0-2',
                  '1-0', '1-1', '1-2',
                  '2-0', '2-1', '2-2',]
  var  playedMoves = checkedBoxes.map(b=> b.box);
  return allMoves.filter(m=>!playedMoves.find(move=> move == m));
function onUncheckBox(elementisImplicit=false) {
checkedBoxes = checkedBoxes.filter(b=> b.box != element.id);
  if (!isImplicit) {
element.value ='';

While checking a box to check for winner, we have to make sure that we uncheck that box after the iteration completes to avoid bad data in checkedBoxes array. For that matter, we employ the onUncheckBox method above. If there is no ‘finishing move’ available, we check for the next condition – computeSavingMove. 

3. Saving Move that allows CPU to save the game.

Consider the following scenario: 

Here it’s CPU’s (O) turn to play. Clearly playing anywhere other than top middle box will cause the game to end in the next turn. So, we have to definitely check that box. To do this, we write a method similar to previous method where we this time iterate over all the remaining boxes and during each iteration fill them with opponent’s mark and then call the checkWinner method. If it returns ‘game over’ in any of the iterations then that is our desired box. Here’s what this translates to in JavaScript. 

function computeSavingMove() {  var  remainingMoves =getRemainingMoves();  switchPlayer();  var  savingMoveCoords;  for (var  move of remainingMoves) {          checkedBoxes.push({ box: move, player: currentPlayer });         var nextBox = document.querySelector(`[id='${move}']`)         if (checkWinner() =='game over') {                         savingMoveCoords = move;                         onUncheckBox(nextBox, true);                         break;}    onUncheckBox(nextBox, true);}    switchPlayer();   if(savingMoveCoords){      console.log('Playing Saving Move')      return savingMoveCoords;}}

You might argue that this is a clear violation of the DRY (Don’t Repeat Yourself) principle. But, sometimes, to keep the code readable and avoid complexities, you may want to take a rain check on the DRY. To make sure that I’m iterating with opponent’s move and note CPU’s, I’m calling the switchPlayer method before iterating over remainingMoves. If none of the remaining moves is a saving move we then turn our attention to the trickiest condition – predictTrappingMove

4. Predicting a move that will trap the CPU and avoiding it.

A ‘Trapping Move’, as I like to call it is when the opponent checks a box that leaves you with two Finishing boxes to fill, ultimately leading you to lose the game. Here’s a screenshot to show exactly that: 

In the image, it’s Player O’s turn and he is in a lose-lose situation. If he check tile 0-0, Player’s X will check 2-2 to win the game and vice versa. So, the only way out of this situation is to avoid it. That’s where our next method, predictTrappingMove comes in.

This method isn’t complicated in terms of execution but the planning needs to be spot on. So, what we do is, every time the opponent plays a move, we check for the possibility of a trapping move, the next time he plays. To achieve this, we will have to one by one check every box with our move. On each turn, we will then have to check each remaining box with the opponents move. Then, we check whether more than one winning move was created as a result of that. I know, I know, what the hell, right? Okay let’s break it down. Suppose we are in this situation: 

The opponent is playing for O’s. If I, for instance, play 1-0, the opponent can easily play 0-2 and trap me like this. 

Since, there was no finishing or saving move available, I wasn’t able to detect this. To detect this, I will have to check every single box till I find one that’s safe. I can accomplish that by first checking box. Then I will play opponent’s turn on each of the remaining boxes.

This way, I can determine whether any of his moves will result in a trapping move. Any of my turns that I don’t find a trapping move anywhere, will be my next move. For some turns, it won’t be possible for the opponent to play all the available boxes, eg, a turn where he has to play a saving move. In those cases, I won’t be iterating over all his possible moves, but just the saving ones. I’ll be making the assumption that the opponent will try to save himself if I play a move that forces him to do so. Okay, this is how it all translates to JavaScript. 

function predictTrappingMove() {
  var  checkedBoxesBackup = checkedBoxes.slice();
  var  remainingMoves =getRemainingMoves();
  var  nextMove;
  var  moveFound;
  for(var move of remainingMoves){
checkedBoxes.push({box: move, player: currentPlayer})
//Check if the opponent needs to play a saving move
    var savingMove =  computeSavingMove();
checkedBoxes.push({box: savingMove, player: currentPlayer});
      if(checkTrap() =='no trap'){
nextMove = move;
//If no saving move is required, check each position  
     for(var opponentMove ofgetRemainingMoves()){
       moveFound =true;
       checkedBoxes.push({box: opponentMove, player: currentPlayer});
       if(checkTrap() =='trapped'){
         moveFound =false;
nextMove = move;
}checkedBoxes = checkedBoxesBackup;
  return nextMove;
function checkTrap(){
  var  boxes =getRemainingMoves();
  var  winningMoveCount =0;
  for(var  freeMove of boxes){
checkedBoxes.push({box: freeMove, player: currentPlayer});
    var result = checkWinner(true);
    if(result =='game over')
  if(winningMoveCount >1){
    return 'trapped';
    return 'no trap';

Here, predictTrappingMove is first checking a box on my behalf. Then, it’s checking whether the opponent needs to play a saving move to counter that. If yes, it’s calling the checkTrap method to see whether more than one saving conditions were created on that opponent move.

If not, that is the move that will be returned and played. If that’s not the case, however, and the opponent’s saving move created a trap for us, we need to move forward and check the remaining boxes for ourselves, and then in each turn check the remaining boxes on the opponent’s behalf and call the checkTrap method each time. If any of the boxes creates a ‘trapping move’, we avoid that move and keep iterating over remaining moves, till we find a safe move to play.

It may be a little confusing still, but if you go over the code a few times, it should all be clear. 

5. Random move

I wrote the computeRandomMove in the first versions of the game to calculate a move if all checks don’t return a move. However, it’s not relevant now as checkTrappingMove will always return a move, irrespective of everything. Here’s the code still if you need it. 

function computeRandomMove() {  var  remainingMoves =getRemainingMoves();  return remainingMoves[Math.floor(Math.random()*remainingMoves.length)]}

It’s simply leveraging the Math.random() method of JavaScript and returning a box based on that from the remainingMoves. So, that’s it. You’re ready to create your unbeatable tic-tac-toe. You can go ahead and write your own with the same principles or even improve over these.

You can even try to write a method that forcesTrappingMove on the opponent making your player a little more aggressive. If you got this far, thanks for your patience. Till next time!

TL;DR Writing code to create an unbeatable tic-tac-toe is simple, but coming up with the logic is what matters.

Please follow and like us:

5 Ways Technology Can Help A Small Business

Please follow and like us:

Technology is changing our world in the most unexpected ways. Supreeth Bhat, MD, PQube believes that every small business needs to use technology to “future proof” themselves. According to him, “Constant Innovation is the Key to Survival”.

1.  Improving collaboration

Initially small companies started utilizing technology in the form of e mail and instant messenger. Technology has now significantly grown to collaborative project management platforms that allow the small business to operate from anywhere in the world.

2.  Minimize errors

Manual processes have a lot of room for errors. This significantly increases the cost. Automation completely eliminates factors that cause human errors thereby significantly reducing costs.

3.  Enhancing customer relations

Technology has opened a lot more avenues for small businesses from opening up online stores to offering 24/7 customer service. Business growth is great but with it comes the need to organize your information. This is where a CRM is useful.

4.  Cloud space

Small businesses can keep their important files on a massive server called the cloud and access them at any time. No technical knowledge is required. Cloud storage is also the perfect backup plan for businesses. These files are stored at a remote location and once data is stored in the cloud, it is safe.

5.  Tailor made apps

Mobile apps open opportunities to engage with customers in a unique way. They make it easier to convert audience into customers. Also enables businesses to have personalized interactions with customers. We are already in the era of driverless cars, robots performing surgeries and working in factories. Through technology disruptions, have come improved quality of life. Every business needs to incorporate technology or there are high chances they might miss the opportunities or fall behind the rest or worse become irrelevant.

Please follow and like us: