In this assignment, you will create a program for graphing simple functions. You will make heavy use of interfaces, both your own interfaces and ones provided by the Go standard library. There are two main components:

An

`Expr`

(or**expression**) type, which represents a mathematical function of one variable, for example,`x + 2`

, or`3 * x * (x + 7)`

. An expression can`Eval`

itself on a particular value of`x`

, returning a number, and it can`String`

itself (producing a string like “x + 2”).A

`Graph`

struct that implements the`image.Image`

interface. A`Graph`

holds an`Expr`

and some settings, like how big the graph should be and how its axes are arranged.

Declare an interface for expressions, `Expr`

. An expression should be able to `String() string`

itself, and `Eval(x float64) float64`

its value at a certain float64 value of x.

Implement each of the following expression types as you please:

`Constant`

, an expression representing a constant number, like 2.3 or -50. This should`Eval`

to itself, no matter what`x`

is. The`String`

function should just return a String version of this number. (Use`fmt.Sprintf`

.)`Negative`

, an expression representing the negation of another expression. (You must, of course, store that other expression.) This should print out as`-BLAH`

, where`BLAH`

is whatever the subexpression prints out as. It should evaluate to the negative of whatever the other expression evaluates to.`BinaryOperation`

, an expression consisting of two sub-expressions and a binary operation, either`+`

,`-`

,`*`

, or`/`

. This should print as`(e1 op e2)`

, where`e1`

and`e2`

are the string versions of the two sub-expressions, and`op`

is the operation.`Variable`

, which represents a variable. (You might choose to implement this as`type Variable string`

, where the string is the name of the variable, like “x” or “y”. Just note that your program only supports one variable; you can call it`x`

or`y`

or whatever, but it’s all the same thing.) It evaluates to whatever`x`

is passed into the`Eval`

method; it prints out as`x`

(or whatever the variable name is).

Write a struct type, `Graph`

, that stores an expression, and some settings: a height and width in pixels, as well as a MinX, MaxX, MinY, and MaxY for the “axes” of the graph. Implement the three methods required for the Image interface:

`ColorModel() color.Model`

–you can just return`color.GrayModel`

.`Bounds() Rectangel`

–use`image.Rect(0, 0, w, h)`

to return the width and height of your image in pixels.`At(x, y int) color.Color`

–the hard one. Given an (x, y) coordinate, decide what color to paint that pixel of the image. To do this, you need to first figure out what “real value” x corresponds to. If x is the 5th pixel in a 100-pixel image, and the axis goes from MinX = 0 to MaxX = 20, then x = 5 really corresponds to x = 1, 1/20th of the way across the axis. Once you have this, you need to evaluate your Expr at this point. This will give you a y value. Calculate what pixel that y value would land on, based on the y axis’s scale. If that pixel number is the y value passed in to you, return black (`color.Gray{0}`

). Otherwise, return white (`color.Gray{255}`

).

In your main function, create a few expressions, and save them to files using code like the following:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | func main() { var e1 Expr = ... var e2 Expr = ... var graph1 = Graph{e1, 100, 100, ..., ..., ..., ...} var graph2 = Graph{e2, 100, 100, ..., ..., ..., ...} f1, err := os.Create("graph1.png") if err != nil { panic("Error opening graph1.png") } png.Encode(f1, graph1) f1.Close() f2, err := os.Create("graph2.png") if err != nil { panic("Error opening graph2.png") } png.Encode(f2, graph2) f2.Close() } |