6
\$\begingroup\$

Most of you have probably heard of the famous Turtle Graphics program, initially made popular by Logo. This challenge is to implement a Turtle Graphics program in your language of choice.

Rules:

  1. Rule one is that when the pen is in the down state, it must draw in both the square the turtle leaves and the square the turtle enters. This is what would happen in real life, so that is what your program should do.

  2. Rule two is the turtle must include these 10 commands, which can be represented in the input as you like:

RESET - resets board to blank - turtle position is default.

UP and DOWN - these two commands set the pen/eraser state.

RIGHT and LEFT - these two commands turn the turtle in the specified direction.

FORWARD - advances turtle to next square.

DRAW and ERASE - these commands set the turtle to drawing and erasing, respectively.

DISPLAY - displays board.

POSITION - prints turtle's x/y coordinate on the board.

STOP, which stops drawing, displays the board, and terminates the program after the user enters any input.

  1. The floor must be 20x20. You can use vectors, arrays, or anything you like to represent it.

  2. You must stop the turtle and display an error message if the turtle hits the wall.

  3. Default turtle position is 0,0 facing right.

Scoring:

This program will use standard scoring rules with a few modifications to try to allow industry programming languages, such as Java and C++, to compete.

  1. Imports, includes, usings and other similar statements do not score anything.

  2. Loop header statements each only score one point. All other statements add the full number of characters in the statement to the score.

Example:

These statements do not score:

#include <iostream>
import java.util.Scanner;

def inputCommand():
string inputCommand(){}

These statements score only one point:

for(int i = 0; i < 9; i++){}
for i in range(0,10):
while(true){}
while x in y:

These statements score the full number of their characters:

string n;
i = 9;

switch(d) {
  case i:
    break;
  default:
    break;
}

return x;

cout<<'example';
cin>>s;
System.out.println()
print('example')

If you have any questions or comments, please let me know in the comments.

\$\endgroup\$
  • \$\begingroup\$ Any particular starting position/direction after reset? Also, what should happen if you run out of bounds? Right/left 90 degrees or 45 degrees? \$\endgroup\$ – Joachim Isaksson Jan 10 '14 at 5:39
  • \$\begingroup\$ Given how complex this program will need to be, your odd scoring rules will make this overly difficult for people to calculate their score. \$\endgroup\$ – user8777 Jan 10 '14 at 5:52
  • 2
    \$\begingroup\$ how many bonus points would we get for writing a scoring program to score the programs we write for this problem? \$\endgroup\$ – serakfalcon Jan 10 '14 at 6:01
  • 1
    \$\begingroup\$ @JoachimIsaksson Added more rules. Diagonal is optional - not required. \$\endgroup\$ – Hosch250 Jan 10 '14 at 6:23
  • 1
    \$\begingroup\$ One-character hello world in C with these rules: #include <stdio.h> main(){for(printf("Hello world!\n");0;)6;} \$\endgroup\$ – Emil Vikström Jan 10 '14 at 8:54
4
\$\begingroup\$

JavaScript, one point

for (s='                    ',
    reset=function(){a=s.split(/./).map(function(){return s.split(/(?=.)/)}); x=0; y=0; dx=1; dy=0; pen='#'; down=1;},
    display=function(){console.log(a.map(function(x){return x.join('')}).join('\n'))},
    position=function(){console.log(x, y)},
    draw=function(){a[y][x]=down?pen:a[y][x]},
    forward=function(){draw(); x+=dx; y+=dy; (y<0||y>19||x<0||x>19) && (console.log('Hit wall')||(dx?(x-=dx):(y-=dy))); draw();},
    turn=function(d){nx=-1*(!dx)*d*dy; dy=(!dy)*d*dx; dx=nx;},
    reset();
    ((p=prompt()) != 'STOP') || display();
    (p == "RESET") && reset(),
    (p == "DISPLAY") && display(),
    (p == "POSITION") && position(),
    (p == "DRAW") && (pen='#'),
    (p == "ERASE") && (pen=' '),
    (p == "UP") && (down=0),
    (p == "DOWN") && (down=1),
    (p == "RIGHT") && turn(1),
    (p == "LEFT") && turn(-1),
    (p == "FORWARD") && forward()
);

Sorry, I couldn't resist.

\$\endgroup\$
2
\$\begingroup\$

Mathematica (1 point and 211 208 205 characters)

A:=Abort[]
q@1:=Check[a〚##〛=c,A]&@@p
DI:=Print@ArrayPlot@a
ST:=DI+A
PO:=Print@p
FO:=p+=v
LE:=v=Cross@v
RI:=v=-LE
DR:=c=1
ER:=c=0
UP:=d=0
DO:=d=1
v={UP,DR};
a=0Array[p=0v+1,20p];
Symbol@StringTake[#,2]q@d&/@StringSplit@s

It prints

enter image description here

for

s = "DOWN RIGHT FORWARD FORWARD FORWARD FORWARD LEFT UP FORWARD LEFT \
   FORWARD FORWARD DOWN RIGHT FORWARD UP FORWARD LEFT FORWARD DOWN \
   FORWARD LEFT FORWARD FORWARD UP LEFT LEFT FORWARD FORWARD DOWN ERASE STOP";

I assume that the initial state is up&drawing.

You can put the whole code inside the header of Do loop

`Do[,{code; 1}]`

It is only 1 point!

\$\endgroup\$
1
\$\begingroup\$

Java

Here is my program - un-golfed (too complicated), unscored (I am unsure what the enums and Scanner object creation score as), and over-done:

package javaapplication74;

import java.util.Scanner;
import static java.lang.Integer.parseInt;

public class JavaApplication74 {

// create Scanner for input
static Scanner in = new Scanner(System.in);

// enumerator of commands
private enum Commands {RESET, UP, DOWN, RIGHT, LEFT, FORWARD, DISPLAY, ERASE, REVERSE, POSITION, STOP, ERROR};

// enumerator of directions turtle can face
private enum Direction {UP, DOWN, RIGHT, LEFT};

// array of valid commands
static final char[] commands = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'r' };

// width and height of room;
static final int ROOM = 20;

// turtle's position
static int[] position = {0, 0};

// number of squares to move
static int move = 0;

// Write a "turtle graphics" program
public static void main(String[] args)
{
    // array of drawn lines
    boolean[][] floor = new boolean[ROOM][ROOM];

    // store command
    Commands command;

    // store current direction - default right
    Direction direction = Direction.RIGHT;

    // pen in drawing condition
    boolean draw = false;
    boolean erase = false;

    // provide directions
    directions();

    // get and execute commands until stop
    do {
        // get command
        command = inputCommand();

        // analyse and execute command
        switch(command) {
            case RESET:
                reset(floor);
            case UP:
                draw = false;
                erase = false;
                break;
            case DOWN:
                draw = true;
                erase = false;
                break;
            case RIGHT:
            case LEFT:
                direction = turn(command, direction);
                break;
            case FORWARD:
                floor = move(floor, direction, draw, erase);
                break;
            case DISPLAY:
                display(draw, floor);
                break;
            case ERASE:
                draw = false;
                erase = true;
                break;
            case REVERSE:
                reverse(floor);
                break;
            case POSITION:
                showPosition(direction);
                break;
            case STOP:
            case ERROR:
                break;

        }   // end switch

    } while(command != Commands.STOP);
    // end do-while
}   // end method main

// Provide directions
public static void directions()
{
    System.out.println("This is a turtle graphics program.");
    System.out.println("You have 11 commands available, use the number to the right to use that command:");
    System.out.printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "0: Clear floor.", "1: Pen up, eraser up (default position).", "2: Pen down.", "3: Turn right.", "4: Turn left.",
            "5: Go forward x spaces (enter 5,x)", "6: Display current layout", "7: Erase", "8: Show turtle's position", "9: Quit program", "r: Draw or erase current square.");
    System.out.println("Note: the turtle will draw one more symbol than the number of spaces entered\n\tbecause it will draw in the square it is initially in.");

}   // end method main

// Input command
public static Commands inputCommand()
{
    // store command as string
    String command;

    // input command
    do {
        System.out.print("Enter your command: ");
        command = in.next();

    } while(!valid(command.charAt(0)));
    // end do-while

    // return command as enum value
    switch(command.charAt(0)) {
        case '0':
            return Commands.RESET;
        case '1':
            return Commands.UP;
        case '2':
            return Commands.DOWN;
        case '3':
            return Commands.RIGHT;
        case '4':
            return Commands.LEFT;
        case '5':

            // recover from bad input
            if(command.substring(1).isEmpty() || command.charAt(1) != ',' || command.substring(2).isEmpty())
                return Commands.ERROR;

            move = parseInt(command.substring(2));
            return Commands.FORWARD;
        case '6':
            return Commands.DISPLAY;
        case '7':
            return Commands.ERASE;
        case '8':
            return Commands.POSITION;
        case '9':
            return Commands.STOP;
        case 'r':
            return Commands.REVERSE;
        default:
            return Commands.ERROR;
    }   // end switch
}   // end method inputCommand

// Validate command
public static boolean valid(char c)
{
    for(int ch : commands) {
        if(c == ch)
            return true;

    }   // end for

    // if reach this point, not valid
    return false;

}   // end method valid

// Turn turtle
public static Direction turn(Commands c, Direction d)
{
    // turn turtle
    switch(d) {
        case UP:
            if(c == Commands.RIGHT)
                d = Direction.RIGHT;
            else
                d = Direction.LEFT;

            break;

        case RIGHT:
            if(c == Commands.RIGHT)
                d = Direction.DOWN;
            else
                d = Direction.UP;

            break;

        case DOWN:
            if(c == Commands.RIGHT)
                d = Direction.LEFT;
            else
                d = Direction.RIGHT;

            break;

        case LEFT:
            if(c == Commands.RIGHT)
                d = Direction.UP;
            else
                d = Direction.DOWN;

            break;

    }   // end switch

    return d;

}   // end method turn

// move turtle
public static boolean[][] move(boolean[][] floor, Direction d, boolean draw, boolean erase)
{
    // get direction to move turtle
    switch(d) {
        // move turtle up
        case UP:
            for(; move > 0; move--) {

                // draw, erase, or leave square
                draw(draw, erase, floor);

                // change position
                position[0]--;

                // return to caller if turtle hits wall
                if(position[0] <= 0) {

                    // reset value
                    position[0] = 0;

                    // print warning
                    System.out.println("Your turtle hit the wall and had to stop.");

                    // stop moving turtle
                    break;

                }   // end if
            }   // end for

            break;

        // move turtle down
        case DOWN:
            for(; move > 0; move--) {

                // draw, erase, or leave square
                draw(draw, erase, floor);

                // change position
                position[0]++;

                // make sure turtle does not walk through wall
                if(position[0] >= ROOM) {

                    // reset value
                    position[0] = ROOM-1;

                    // print warning
                    System.out.println("Your turtle hit the wall and had to stop.");

                    // stop moving turtle
                    break;

                }   // end if
            }   // end for

            break;

        // move turtle right
        case RIGHT:
            for(; move > 0; move--) {

                // draw, erase, or leave square
                draw(draw, erase, floor);

                // change position
                position[1]++;

                // make sure turtle does not walk through wall
                if(position[1] >= ROOM) {

                    // reset value
                    position[1] = ROOM-1;

                    // print warning
                    System.out.println("Your turtle hit the wall and had to stop.");

                    // stop moving turtle
                    break;

                }   // end if
            }   // end for

            break;

        // move turtle left
        case LEFT:
            for(; move > 0; move--) {

                // draw, erase, or leave square
                draw(draw, erase, floor);

                // change position
                position[1]--;

                // make sure turtle does not walk through wall
                if(position[1] <= 0) {

                    // reset value
                    position[1] = 0;

                    // print warning
                    System.out.println("Your turtle hit the wall and had to stop.");

                    // stop moving turtle
                    break;

                }   // end if
            }   // end for

            break;

    }   // end switch

    // draw, erase, or leave square
    draw(draw, erase, floor);

    return floor;

}   // end method move

// Draw, erase, or leave square
public static boolean[][] draw(boolean draw, boolean erase, boolean[][] floor)
{
    // if draw, turtle cannot leave square without drawing
    if(draw)
        floor[position[0]][position[1]] = true;

    // if erase, turtle cannot leave square without erasing
    if(erase)
        floor[position[0]][position[1]] = false;

    return floor;

}   // end method draw

// Display array
public static void display(boolean draw, boolean[][] array)
{
    // loop through array
    for(boolean b[] : array) {
        for(boolean bb : b) {

            // draw picture
            if(bb)
                System.out.print("*");
            else
                System.out.print(" ");

        }   // end inner for

        // return at end of row
        System.out.println();

    }   // end outer for
}   // end method display

// Reverse value (draw or erase square) of current position
public static void reverse(boolean floor[][])
{
    floor[position[0]][position[1]] = !floor[position[0]][position[1]];

}   // end method reverse

// Show turtle's position
public static void showPosition(Direction d)
{
    // x-y coordinate
    System.out.printf("(%d, %d)\n", position[1], position[0]);

    // direction
    System.out.print("You are facing ");
    switch(d) {
        case UP:
            System.out.println("up.");
            break;
        case DOWN:
            System.out.println("down.");
            break;
        case RIGHT:
            System.out.println("right.");
            break;
        case LEFT:
            System.out.println("left.");
            break;

    }   // end switch

}   // end method showPosition
// Reset floor to blank
public static boolean[][] reset(boolean[][] floor)
{
    for(boolean b[] : floor)
        for(int i = 0; i < b.length; i++)
            b[i] = false;

    return floor;

}   // end method reset
}   // end class JavaApplication74

I wrote this for my programming class about a month ago, so it isn't optimized for golf. I thought you might like to see my solution though.

\$\endgroup\$
  • 1
    \$\begingroup\$ You submitted an answer to your own Gulf challenge, but didn't golf it andcouldn't score it. What does that day about your rules? \$\endgroup\$ – user8777 Jan 10 '14 at 20:08
  • \$\begingroup\$ @LegoStormtroopr I didn't score it because I wasn't sure about the atomic-golf rules. My rules were modified to only not score imports and score loop statements at only 1 point - that isn't that hard, is it? I made a comment on what I was unsure about in the answer. I will score it if you will explain what the rules for these are. Also, golfing the names won't really help because user-defined variables only score 1 point each time thy are used. \$\endgroup\$ – Hosch250 Jan 10 '14 at 20:16
  • \$\begingroup\$ What's the course maximum? \$\endgroup\$ – Embattled Swag Jan 10 '14 at 21:49
  • \$\begingroup\$ If you mean for program score, nothing. It will be interesting to see what people come up with. \$\endgroup\$ – Hosch250 Jan 10 '14 at 23:10
1
\$\begingroup\$

Python 2.7 (443? Points, 531 chars)


Not really that well golfed and the display looks kind of horrid. Takes input from a file 'i' and runs printing out the output. I defined two new 'commands': 'CW' and 'CCW' which rotate the turtle 90 degrees clockwise and counter-clockwise respectivly.

b=[];u=1;s=r=0;p=[];d=[(1,0),(0,1),(-1,0),(0,-1)];l='0';
def q():
 for i in b:print ''.join(i)
def z():
 r=0;p=[0]*2
 for i in [0]*20:
  b.append([l]*20)
def k():
 b[p[1]][p[0]]=(('1',l)[s],b[p[1]][p[0]])[u]
z()
for c in open('i','r').read().split():
 if c=="RESET":z()
 elif c=="UP":u=1
 elif c=="DOWN":u=0
 elif c=="FORWARD":
  k();p[0]+=d[r][0];p[1]+=d[r][1];k()
 elif c=="DRAW":s=0
 elif c=="ERASE":s=1
 elif c=="DISPLAY":q()
 elif c=="POSITION":print p
 elif c=="STOP":q();break
 elif c=="CW":r=(r+1)%4
 elif c=="CCW":r=(r-1)%4

Test Input:

DOWN FORWARD FORWARD CW FORWARD FORWARD CW FORWARD FORWARD CW FORWARD FORWARD CW UP FORWARD FORWARD FORWARD FORWARD DOWN FORWARD FORWARD CW FORWARD FORWARD CW FORWARD FORWARD CW FORWARD FORWARD CW ERASE FORWARD FORWARD STOP

Output:

11100000000000000000
10101010000000000000
11101110000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
00000000000000000000
\$\endgroup\$
  • \$\begingroup\$ I found 431 characters - you have three for-loops in there, did you forget to remove one? \$\endgroup\$ – Hosch250 Jan 10 '14 at 16:14
  • \$\begingroup\$ Quite Possibly, let me recalculate. \$\endgroup\$ – Sinkingpoint Jan 10 '14 at 19:43
1
\$\begingroup\$

Java, 10 Points

import java.util.Scanner;
import static java.lang.System.*;

class Turtle{
    public static void main(String...args){
        Scanner s=new Scanner(in).useDelimiter("\\W+");
        for(
            String board = "Lol I'm coding stuff".replaceAll(".","00000000000000000000\n"),
                input,
                x = "0",
                y = "0",
                rotation = "0",
                up = "true",
                mode = "1",
                nop
        ;
            null==(s.hasNext()?null:out.printf(board))
        ;
            nop = 
            ((input=s.next()).equals("RESET")
                ?(x = y = rotation = "0") + (up = "true") + (mode = "1")
            :input.equals("STOP")
                ?(s=new Scanner("")).toString()
            :input.equals("DISPLAY")
                ?out.printf(board).toString()
            :input.equals("POSITION")
                ?out.printf("(%s,%s)",x,y).toString()
                :"")+
            (up = input.equals("UP")
                ?"true"
            :input.equals("DOWN")
                ?"false"
                :up)+
            (rotation = input.equals("LEFT")
                ?""+((1+Integer.parseInt(rotation))%4)
            :input.equals("RIGHT")
                ?""+((3+Integer.parseInt(rotation))%4)
                :rotation)+
            (mode = input.equals("DRAW")
                ?"1"
            :input.equals("ERASE")
                ?"0"
                :mode)+
            (input.equals("FORWARD")
                ?
                    ((x = Integer.parseInt(rotation)%2!=0
                        ?x
                    :rotation.equals("0")
                        ?Integer.parseInt(x)+1+""
                        :Integer.parseInt(x)-1+"")+
                    (y = Integer.parseInt(rotation)%2==0
                        ?y
                    :rotation.equals("3")
                        ?Integer.parseInt(y)+1+""
                        :Integer.parseInt(y)-1+""))
                :"")+
            (out.printf("\nx:%s y:%s rot:%s up:%s mode:%s input:%s\n",x,y,rotation,up,mode,input))+
            (board = up.equals("false")
                ?board.replaceFirst("(?<=(?:[01]{20}\n){"+y+"}.{"+x+"}).",mode)
                :board)+
            (Integer.parseInt(x)<0||Integer.parseInt(x)>20||Integer.parseInt(y)<0||Integer.parseInt(y)>20
                ?(board = String.format("Error at position (%s,%s)",x,y)) + (s=new Scanner("")).toString()
                :"")
        );
    }
}

Scanner s=new Scanner(in).useDelimiter("\\W+"); counts as 9 points, and the rest of the main method is just a for-loop's header and so it counts as 1 point.

Loop header statements each only score one point

\$\endgroup\$
  • \$\begingroup\$ Great job twisting the rules to your advantage! This is probably the first time Java will win a golf program! \$\endgroup\$ – Hosch250 Jan 11 '14 at 4:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.