Skip to content

Instantly share code, notes, and snippets.

@mikebaldry
Created May 24, 2012 14:14
Show Gist options
  • Select an option

  • Save mikebaldry/2781812 to your computer and use it in GitHub Desktop.

Select an option

Save mikebaldry/2781812 to your computer and use it in GitHub Desktop.
To run: ./image_editor
To run tests: #run with python -m unittest app_tests.TestImage
------original challenge------
Coding challenge
Graphical editors allow users to edit images in the same way text editors let us modify documents. Images are represented as an M x N array of pixels with each pixel given colour.
Produce a program that simulates a simple interactive graphical editor.
Input
The input consists of a line containing a sequence of commands. Each command is represented by a single capital letter at the start of the line. Arguments to the command are separated by spaces and follow the command character.
Pixel co-ordinates are represented by a pair of integers: 1) a column number between 1 and M, and 2) a row number between 1 and N. Where 1 <= M, N <= 250. The origin sits in the upper-left of the table. Colours are specified by capital letters.
Commands
The editor supports 7 commands:
1. I M N. Create a new M x N image with all pixels coloured white (O).
2. C. Clears the table, setting all pixels to white (O).
3. L X Y C. Colours the pixel (X,Y) with colour C.
4. V X Y1 Y2 C. Draw a vertical segment of colour C in column X between rows Y1 and Y2 (inclusive).
5. H X1 X2 Y C. Draw a horizontal segment of colour C in row Y between columns X1 and X2 (inclusive).
6. F X Y C. Fill the region R with the colour C. R is defined as: Pixel (X,Y) belongs to R. Any other pixel which is the same colour as (X,Y) and shares a common side with any pixel in R also belongs to this region.
7. S. Show the contents of the current image
8. 8. X. Terminate the session
Example
In the example below, > denotes input, => denotes program output.
>I 5 6
>L 2 3 A
>S
=>
OOOOO
OOOOO
OAOOO
OOOOO
OOOOO
OOOOO
>F 3 3 J
>V 2 3 4 W
>H 3 4 2 Z
>S
=>
JJJJJ
JJZZJ
JWJJJ
JWJJJ
JJJJJ
JJJJJ
Submission
We prefer submissions in Ruby although we will accept them in other languages.
Please provide an executable solution with any source files in a common archive format (ZIP, TAR etc.).
import numpy
import inspect
import sys
class Image:
def __init__(self, width, height):
self.width = width
self.height = height
self.clear()
def clear(self):
self.data = numpy.array([['O'] * self.width for x in xrange(self.height)])
def drawPixel(self, x, y, colour):
if (not self.__validPixel(x, y)):
return
self.data[y, x] = colour
def drawVerticalLine(self, x, y1, y2, colour):
for y in xrange(y1, y2 + 1):
self.drawPixel(x, y, colour)
def drawHorizontalLine(self, x1, x2, y, colour):
for x in xrange(x1, x2 + 1):
self.drawPixel(x, y, colour)
def drawFilledArea(self, x, y, replacementColour):
#not using recursion as this can cause a stack overflow with large image sizes
#and calling methods is slow, so its best not to do that anyway.
stack = [[x, y]]
targetColour = self.__getPixelColour(x, y)
while len(stack) > 0:
pixel = stack.pop()
if (not self.__validPixel(*pixel)):
continue
if (self.__getPixelColour(*pixel) != targetColour):
continue
self.drawPixel(*(pixel + [replacementColour]))
stack.append([pixel[0] - 1, pixel[1] ]) # western pixel
stack.append([pixel[0] + 1, pixel[1] ]) # eastern pixel
stack.append([pixel[0] , pixel[1] - 1]) # northern pixel
stack.append([pixel[0] , pixel[1] + 1]) # southern pixel
def __getPixelColour(self, x, y):
if (not self.__validPixel(x, y)):
return None
return self.data[y, x]
def __validPixel(self, x, y):
return x >= 0 and y >= 0 and x < self.width and y < self.height
def __str__(self):
result = ""
for y in xrange(len(self.data)):
for x in xrange(len(self.data[y])):
result += self.data[y][x]
result += "\n"
return result[:-1]
class ConsoleInput:
def __init__(self, commandHandler):
self.commandHandler = commandHandler
def capture(self):
finished = False
errorMessage = "I'm sorry, Dave. I'm afraid I can't do that. "
while (not finished):
command = self.__readCommand()
method = self.__lookupMethod(command)
if(method):
try:
finished = method(*command["arguments"]) == False
except Error as e:
print(errorMessage + e.__str__())
else:
print(errorMessage + "The command was invalid.")
def __readCommand(self):
parts = raw_input("> ").split(" ")
command = parts[0]
arguments = [self.__attemptCastAsInteger(a) for a in parts[1:]]
return {"name": command, "arguments": arguments}
def __lookupMethod(self, command):
result = None
try:
result = getattr(self.commandHandler, command["name"].lower())
except AttributeError:
return None
expectedArguments = len(command["arguments"])
actualArguments = len(inspect.getargspec(result).args) - 1 # self
if (expectedArguments != actualArguments):
return None
return result
def __attemptCastAsInteger(self, argument):
try:
return int(argument)
except ValueError:
return argument
class Error(Exception):
def __init__(self, message):
self.message = message
def __str__(self):
return self.message
import app
import unittest
class TestImage(unittest.TestCase):
def img(self):
return self.image.__str__()
def setUp(self):
self.image = app.Image(5, 5)
def test_initialState(self):
self.assertEqual("OOOOO\nOOOOO\nOOOOO\nOOOOO\nOOOOO", self.img())
def test_colouringAPixel(self):
self.image.drawPixel(0, 0, "R")
self.assertEqual("ROOOO\nOOOOO\nOOOOO\nOOOOO\nOOOOO", self.img())
def test_clearing(self):
self.image.drawPixel(0, 0, "R")
self.image.clear()
self.assertEqual("OOOOO\nOOOOO\nOOOOO\nOOOOO\nOOOOO", self.img())
def test_verticalLine(self):
self.image.drawVerticalLine(1, 1, 4, "R")
self.assertEqual("OOOOO\nOROOO\nOROOO\nOROOO\nOROOO", self.img())
def test_horizontalLine(self):
self.image.drawHorizontalLine(1, 4, 1, "R")
self.assertEqual("OOOOO\nORRRR\nOOOOO\nOOOOO\nOOOOO", self.img())
def test_fillArea(self):
self.image = app.Image(7, 7) #5,5 gives a 1 pixel area in a square, pointless to test fill
self.image.drawHorizontalLine(1, 5, 1, "R")
self.image.drawHorizontalLine(1, 5, 5, "R")
self.image.drawVerticalLine(1, 1, 5, "R")
self.image.drawVerticalLine(5, 1, 5, "R")
self.image.drawFilledArea(4, 4, "G")
self.assertEqual("OOOOOOO\nORRRRRO\nORGGGRO\nORGGGRO\nORGGGRO\nORRRRRO\nOOOOOOO""", self.img())
#!/usr/bin/env python
import app
class Application:
def __init__(self):
self.image = None
def x(self):
return False
def i(self, x, y):
self.image = app.Image(x, y)
def c(self):
self.__ensureImage()
self.image.clear()
def l(self, x, y, colour):
self.__ensureImage()
self.image.drawPixel(x - 1, y - 1, colour)
def v(self, x, y1, y2, colour):
self.__ensureImage()
self.image.drawVerticalLine(x - 1, y1 - 1, y2 - 1, colour)
def h(self, x1, x2, y, colour):
self.__ensureImage()
self.image.drawHorizontalLine(x1 - 1, x2 -1, y - 1, colour)
def f(self, x, y, colour):
self.__ensureImage()
self.image.drawFilledArea(x - 1, y - 1, colour)
def s(self):
self.__ensureImage()
print self.image
def __ensureImage(self):
if (not self.image):
raise app.Error("You must create an image first.")
print "Image Editor\n"
app.ConsoleInput(Application()).capture()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment