Is my AI solution to Untrusted Game considered logical or “ethical”?

Posted on

Problem

I am applying to a university to study Computational Linguistics, and as I read, it would be recommended to have a background in Artificial Intelligence.

The Admission board asked me to prepare a portfolio of my works, and I am considering to add this solution to the portfolio.

I have been lazy to develop an AI to bypass the default obstacles, so I added mine to ease the movement of the robot.

 /*
 * robotNav.js
 *
 * The green key is located in a slightly more
 * complicated room. You'll need to get the robot
 * past these obstacles.
 */

function getRandomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

function startLevel(map) {
    map.placePlayer(0, map.getHeight() - 1);
    var player = map.getPlayer();

    map.defineObject('robot', {
        'type': 'dynamic',
        'symbol': 'R',
        'color': 'gray',
        'onCollision': function (player, me) {
            me.giveItemTo(player, 'greenKey');
        },
        'behavior': function (me) {
            for(i = 2; i<9; i++){
                map.placeObject(map.getWidth() - 20, i, 'block');
            }
            for(i = 2; i<9; i++){
                map.placeObject(map.getWidth() - 3, i, 'block');
            }
            if(me.canMove('down') && !me.canMove('left')){
                me.move('down');
            }else{
                if(me.canMove('right') && !me.canMove('down')){
                    me.move('right');
                }
                if(me.canMove('up') && !me.canMove('right')){
                    if(me.canMove('left')){
                        me.move('up');
                    }else{
                        me.move('down');
                    }

                }
                if(!me.canMove('up') && me.canMove('right')){
                    me.move('right');
                }
                if(!me.canMove('up') && !me.canMove('right')){
                    me.move('down');
                }
            }
        }
    });

    map.defineObject('barrier', {
        'symbol': '░',
        'color': 'purple',
        'impassable': true,
        'passableFor': ['robot']
    });

    map.placeObject(map.getWidth() - 1, map.getHeight() - 1, 'exit');
    map.placeObject(1, 1, 'robot');
    map.placeObject(map.getWidth() - 2, 8, 'greenKey');
    map.placeObject(map.getWidth() - 2, 9, 'barrier');

    for (var x = 0; x < map.getWidth(); x++) {
        map.placeObject(x, 0, 'block');
        if (x != map.getWidth() - 2) {
            map.placeObject(x, 9, 'block');
        }
    }

    for (var y = 1; y < 9; y++) {
        map.placeObject(0, y, 'block');
        map.placeObject(map.getWidth() - 1, y, 'block');
    }

    for (var i = 0; i < 4; i++) {
        map.placeObject(20 - i, i + 1, 'block');
        map.placeObject(35 - i, 8 - i, 'block');
    }
}

function validateLevel(map) {
    map.validateExactlyXManyObjects(1, 'exit');
    map.validateExactlyXManyObjects(1, 'robot');
    map.validateAtMostXObjects(1, 'greenKey');
}

function onExit(map) {
    if (!map.getPlayer().hasItem('greenKey')) {
        map.writeStatus("We need to get that key!");
        return false;
    } else {
        return true;
    }
}

This Solution is to the quiz #12 in Chapter 2 of Untrusted Game.

What I mean by ethical is that am I allowed to cheat my way out in the AI world, or am I required to solve the problem as it is without additions (the additions here are the two added walls).

EDIT:

Here is the default setup of the scene:

default scene

And here are my changes:

my solution

The ‘@’ is the player, the small blue rectangle in the bottom-right corner is the goal, ‘R’ is the robot that must be programmed (it moves once the player moves), ‘K’ is the goal for the robot it also is the key that allows the player to open his goal, the robot must reach the key and move through the portal under it (no human is allowed to pass it) and provide the key to the player so he can win the quiz.

Another thing is that I am only allowed to edit the behaviour of the ‘robot’ object (at line 24).

'behavior': function (me) {....}

Solution

I’m one of the developers of Untrusted (neunenak). Your solution is completely ethical/fair/okay. The whole idea behind the game was that the player could write whatever code they needed to be able to progress to the next level. We do have a lot of code in the game’s framework designed to make really easy and uncreative solutions impossible, but that’s just to try to force the player to think creatively – if the code you wrote lets you get Dr. Eval to the next level, it’s all good. After all, in the real world you don’t get more points for writing a complicated AI when a shell script solves your actual problem just as well!

Thanks for playing the game by the way! We’re glad you’re enjoying it 🙂

From a quick review:

  • As @Amon said, I would not use this for your portfolio, especially if you are cheating
  • You have 0 comments in your code, even for a fake AI that is not good enough
  • Instead of all the ifs and else I would build a rules table, the logic would go through each entry, see if a condition evaluates to true, and then perform the action.
  • I don’t see any style problems, so that’s good

I got out with this:

    this.direction = this.direction || 'down';

    var moves = {
      'down' : [ 'left' , 'down' , 'right' , 'up' ],
      'right': [ 'down' , 'right' , 'up'   , 'left' ],
      'left' : [ 'up' , 'left' , 'down' , 'right' ],
      'up'   : [ 'right' , 'up' , 'left' , 'down' ]

    }, 
    move = moves[this.direction];

    if( me.canMove( move[0] ) )
      this.direction = move[0];
    else if ( me.canMove( move[1] ) )
      this.direction = move[1];  
    else if ( me.canMove( move[2] ) )
      this.direction = move[2];            
    else  
      this.direction = move[3];


    me.move( this.direction )

Obviously the access to each movement option could have been handled with a loop, but you get the gist.

Right hand wall walk is not that hard to code (kept it simple so my son could understand it):

    if(me.vars === undefined)
    {
        me.vars = 1;
        me.facing = 0;    
        me.direction = Array ('up','right','down','left','up');            
    }

    if(me.canMove(me.direction[me.facing+1]))
    {
        me.facing++;
    }
    else if(me.canMove(me.direction[me.facing]))
    {

    }
    else
    {
        me.facing--;
    }


    if(me.facing < 0)
    {
        me.facing = 0;
    }
    if(me.facing > 3)
    {
        me.facing = 0;
    }

    me.move(me.direction[me.facing]);

There is better ‘unethical’ solution – works for 12th and 13th level

        map.defineObject('xxx', 
        {
            'type': 'static',
            'symbol': 'X',
            'color': '#0f0',
            'onCollision': function (player, game) {
                game.addToInventory('greenKey');
            }
        });
        if(!me.xx){
            map.placeObject(20, map.getHeight() - 1, 'xxx');
            me.xx=true;
        } 

I knew my solution was not the expected one, but it worked for several stages before this one, so the code was written and just had to change the directions. The solution was to trigger set directions with the phone, using player color swaps.

var player = map.getPlayer();
player.setPhoneCallback( function(){
    if(player.getColor()=='#0f0'){
        player.setColor('#f0f');
    }else if(player.getColor()=='#f0f'){
        player.setColor('#00f');
    }else if(player.getColor()=='#00f'){
        player.setColor('#0ff');
    }else{
        player.setColor('#f00');
    }
});
if(player.getColor()=='#0f0'){ me.move('down'); }
if(player.getColor()=='#f0f'){ me.move('right'); }
if(player.getColor()=='#00f'){ me.move('up'); }
if(player.getColor()=='#0ff'){ me.move('right'); }
if(player.getColor()=='#f00'){ me.move('down'); }

Leave a Reply

Your email address will not be published. Required fields are marked *