The Horrors of AI (Halloween Edition đ)
Kevin Moe Myint Myat đšâđ»
Posted on October 31, 2024
I was horrified by AI on the eve of Halloween đ
Just days before Halloween 2024, I had a virtual interview with a potential employer, where the lead engineer presented me with the "classic Mars Rover problem." To be honest, I didnât realize it was a well-known problem because I donât frequently visit coding practice websites. Instead, Iâve always relied on my original problem-solving skills and critical thinking. Typically, I ace take-home assignments and impress reviewers, which ultimately earns me my offers. Thatâs how itâs always been.
However, during some of my job-seeking phases, Iâve encountered a different method of assessing candidates: the pairing session. Iâm not opposed to it, as it gives the interviewer (the ânavigatorâ) a chance to see the candidate(the âdriverâ)âs ability to verbalize their thought process while solving problems together.
The problem is like this: imagine a 10x10 grid with a rover starting at coordinates (5, 5)âessentially in the middle of the gridâfacing east. The rover can receive commands represented by "L," "R," or "M," where:
- L means to rotate left (90° counterclockwise),
- R means to rotate right (90° clockwise), and
- M means to move forward by one grid cell in its current direction.
For example, if the command sequence is âMMMLMMM,â the rover would end up at coordinates (8, 2), facing north. The output format should look like â8:2:Nâ. Simple enough?
Since Iâve been working with React for a couple of years, my natural approach to solving this was to think in terms of State and Effect, where the state would represent the roverâs coordinates and direction. But as this wasnât a UI test, the interviewer encouraged me to stick to pure logical programming. I chose Node.js, my preferred backend language, to tackle the problem.
My initial setup probably looked something like this:
const intialStateOfRover = {
x: 5,
y: 5,
direction: "E",
};
function processCommands(commandString) {
//iterate commandString in a loop and do the movement logic
//the movement logic results in a new state for rover
//return the state in format x:y:direction
}
The command "M" is straightforward since it just requires moving one grid forward (+1). But which coordinateâx or yâshould we adjust? That depends on the direction. If the rover is facing "E" (East) or "W" (West), the x-axis changes. If itâs facing "N" (North) or "S" (South), the y-axis changes.
To manage direction, I thought in terms of degrees: "E" represents 0°, "N" 90°, "W" 180°, and "S" 270°. When the degrees loop back to 360°, we're facing "E" again. The "L" and "R" commands adjust the roverâs direction by subtracting or adding 90° to the current heading. This approach helped me map out the logic needed for the program.
const COMMANDS = {
L: 90,
R: -90,
M: 1,
};
const DIRECTIONS = {
E: {
axis: "x",
value: 1,
degree: 0,
},
W: {
axis: "x",
value: -1,
degree: 180,
},
N: {
axis: "y",
value: -1,
degree: 90,
},
S: {
axis: "y",
value: 1,
degree: 270,
},
};
function processCommands(commandString) {
const resultState = { ...intialStateOfRover };
const lengthOfCommand = commandString.length;
for (let i = 0; i < lengthOfCommand; i++) {
let directionObj = DIRECTIONS[resultState.direction];
const command = commandString[i];
if (command === "M") {
resultState[directionObj.axis] =
resultState[directionObj.axis] + directionObj.value;
} else {
let degree = directionObj.degree;
degree = degree + COMMANDS[command];
resultState.direction = Object.entries(DIRECTIONS).find(
(direction) => direction[1].degree === degree
)?.[0];
}
}
return `${resultState.x}:${resultState.y}:${resultState.direction}`;
}
As I explained my code to the interviewer, we took a test-driven approach to validate my logic. Thatâs when we hit a roadblock: running the command sequence "MMML" correctly placed the rover, but with "MMMR," the result came back as undefined.
While debugging together, we discovered that moving clockwise caused the degree to become "-90," which wasnât found in the DIRECTIONS map. The interviewer kindly offered a hint, introducing me to the concept of "Modulo." By adding the maximum degree to the current degree and then finding the remainder with respect to the maximum degree, we could wrap negative values around. This way, "-90" would become 270, which correctly maps to the "S" (South) direction. It worked like this...
let degree = directionObj.degree;
degree = degree + COMMANDS[command];
degree = (degree + 360) % 360;
VoilĂ ! The test for moving in the correct direction passed. It took us 30â45 minutes to complete, and I felt genuinely humbled by the experience. I thanked the interviewer for his time, and afterward, I kept reflecting on ways I could have improved my approach. Thinking in an object-oriented way, I realized that I could have created a *Rover * class, instantiated it as an object, and used methods to mutate its internal state.
It wasnât until Halloween night that it hit meâI should challenge an AI with this problem and see how well it performs! So, I prompted my best friend Meta AI like this...
I will give you example problem.. letâs say itâs 10x10 grid and a car is at 5, 5 and at east direction . The command can be L, R or M. L means rotate to left⊠R means rotate to right.. M means move one grid⊠if like this, if a command is âMMMLMMMâ , it will be at 5, 2 and at north direction. Write a JavaScript code
With just a brief prompt, even in imperfect English, my best buddy understood perfectly and gave me this surprising result...
class Rover {
constructor(x, y, direction) {
this.x = x;
this.y = y;
this.direction = direction;
this.directions = {
0: [0, 1], // North
90: [1, 0], // East
180: [0, -1], // South
270: [-1, 0], // West
};
}
turn(command) {
this.direction = command === 'L' ? (this.direction - 90 + 360) % 360 : (this.direction + 90) % 360;
}
move() {
[this.x, this.y] = [this.x + this.directions[this.direction][0], this.y + this.directions[this.direction][1]];
}
executeCommands(commands) {
for (const command of commands) {
if (command === 'M') {
this.move();
} else {
this.turn(command);
}
}
}
getPosition() {
return `${this.x}, ${this.y} and at direction ${['N', 'E', 'S', 'W'][Math.floor(this.direction / 90) % 4]}
(${this.direction}°)`;
}
}
// Usage
const rover = new Rover(5, 5, 90);
rover.executeCommands('MMMLMMM');
console.log(rover.getPosition());
I was stunned and I asked
I never said itâs a Rover.. how do you know itâs Rover?
The genius revealed to me that itâs the classic Mars Rover problem. Wowâjust from my short prompt, it knew exactly what I was asking...
A CLAIRVOYANT HERE!!!
It even knew right away to use an object-oriented approach for better readability and reusabilityâsomething that only dawned on me hours after the interview. Talk about the difference pressure and emotion make! The advantage of being an emotionless, massive dataset is that AI can process and solve problems instantly, while a mere mortal developer like me took 45 minutes to barely complete it, even with the interviewer's help.
Iâm truly in awe of how AI technology has advanced over just a few years, reaching a level of problem-solving that now surpasses human ability. Disheartened, I made another prompt to the AI.
Quick question, why do we still need developers if you can code like that?
With humility, the AI has answered
While I'm capable of generating high-quality code, there are several reasons why human developers are still essential:
- Context understanding: I can only understand the context of a problem within the scope of the input provided. Human developers bring real-world experience, domain knowledge, and nuanced understanding.
- Creativity and innovation: While I can generate code, I don't have the same level of creativity or innovative thinking as humans.
- Problem definition and identification: Humans are better at identifying and defining problems, whereas I rely on well-defined inputs.
- Critical thinking and decision-making: Developers must make architectural decisions, optimize performance, and weigh trade-offs â tasks requiring human judgment.
- Maintenance and evolution: Code requires ongoing maintenance, refactoring, and updates, which humans are better suited for.
- Collaboration and communication: Development involves teamwork, stakeholder discussions, and effective communication â skills unique to humans.
- Customization and adaptation: Real-world projects often require customized solutions, adapting to changing requirements, and integrating with existing systems.
- Emotional intelligence and empathy: Human developers can consider user experience, usability, and accessibility aspects.
- Originality and intellectual property: Human-created code is original and protectable by copyright.
- Learning and improvement: Humans learn from experiences, adapt to new technologies, and continuously improve. I'm designed to assist, augment, and accelerate development, not replace it.
That said, I felt reassured, realizing that even though AIs can now tackle coding challenges faster and more efficiently, there is still a strong demand for human developers in tech. Itâs not going to take our jobs anytime soon.
In my experience, software development involves far more than just acing coding quizzes. It requires numerous rounds of discussions with stakeholders, deep dives into technical feasibility, peer reviews, and continual improvements to both user and developer experience. Until software products are designed exclusively for AI rather than human customers, human developers will remain essential.
For Humans, By Humans
HAPPY HALLOWEEN 2024 đ» !!!
Posted on October 31, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.