DanaFosmer.com
  • Test Engineering
  • Electrical Engineering
  • Projects and Code
  • Archives
  • About

Python Problem 5

12/29/2022

0 Comments

 

Problem Description

This is the Interpreter problem. The idea is it's a computer where a list of commands are read from RAM and processed with a set of instructions and registers.

The input file is a list of commands read into RAM that are then processed according to these rules
  • 100 halt
  • 2dn set register d to n
  • 3dn add register n to register d
  • 4dn multiply register d by n
  • 5ds set register d to the value of register s
  • 6ds add the value of register s to register d
  • 7ds multiply register d by the value of register s
  • 8da set register d to the value in RAM whose address is in register a
  • 9sa set the value in RAM whose address is in register a to that of register s
  • 0ds goto the location in register d unless register s contains 0

Solution

I have main do a little bit of the work in this problem. It basically iterates through the commands in RAM, the trouble is some of the commands change the instruction pointer to a new location in RAM. I feel like my logic is a little messy with those tasks. There is a class called RamProcessor that handles each command, but the instance also keeps track of the instruction pointer.

I just treated the commands as regular integers, and then every result was processed as modulo 1000 to keep it to three digits, or roll-over.
class RamProcessor:

    def __init__(self):
        self.register = [0 for i in range(10)]
        self.ram = [0 for i in range(1000)]
        self.instruction = 0
        self.instruction_digit1 = 0
        self.instruction_digit2 = 0
        self.instruction_digit3 = 0
        self.ram_counter = 0

    def read_ram(self):
        file_reader = fr.FileReader("inputFile.txt")
        self.ram = file_reader.file_as_int_list()
        return self.ram

    def instruction_router(self, instruction):
        self.instruction = instruction
        self.instruction_digit1 = int(self.instruction/100)
        self.instruction_digit2 = int((self.instruction % 100)/10)
        self.instruction_digit3 = int(((self.instruction % 100)% 10))

        match self.instruction_digit1:
            case 0:
                if self.register[self.instruction_digit3] == 0:
                    return 100
                else:
                    self.instruction = self.ram[self.register[self.instruction_digit2]]
                    self.ram_counter = self.register[self.instruction_digit2]
            
            case 1:
                print("halt")

            case 2:
                self.register[self.instruction_digit2] = self.instruction_digit3
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)
            case 3:
                self.register[self.instruction_digit2] += self.instruction_digit3
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)

            case 4:
                self.register[self.instruction_digit2] *= self.instruction_digit3
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)

            case 5:
                self.register[self.instruction_digit2] = self.register[self.instruction_digit3]
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)

            case 6:
                self.register[self.instruction_digit2] += self.register[self.instruction_digit3]
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)

            case 7:
                self.register[self.instruction_digit2] *= self.register[self.instruction_digit3]
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)
            
            case 8:
                self.register[self.instruction_digit2] = self.ram[self.register[self.instruction_digit3]]
                self.register[self.instruction_digit2] = (self.register[self.instruction_digit2] % 1000)

            case 9:
                self.ram[self.instruction_digit3] = self.register[self.instruction_digit2]
                self.ram[self.instruction_digit3] = (self.ram[self.instruction_digit3] % 1000)
        return 0

    def get_ram_contents(self):
        return self.ram

    def update_ram_counter(self):
        return self.ram_counter
See full code on my GitHub
0 Comments

Python Problem 4

12/29/2022

0 Comments

 

Problem Description

This is the graphical editor problem. It's sort of a text version of the Microsoft Paint program. This one doesn't read in a file, it takes user input of commands to change the "image."

The commands to implement are as follows:
  • create an image
  • clear the image
  • color a pixel
  • draw a vertical line
  • draw a horizontal line
  • draw a filled rectangle
  • fill a region
  • write the image to a file

Solution

This is another 2D array problem, but again in Python it's a list of lists.

I'm not sure how clean I got the object design aspects of this, I have a class called Interface and a class called Drawing that handle the user input processing and the drawing of the image. Trouble is I kind of have some interface aspects in the main function. It seems to work, but probably could be cleaner.

The Interface class is a while loop that will allow you to continue to read commands until the exit command is given. I also implemented a commend to output a text menu of choices, although that wasn't really in the problem. Here is the menu.
Picture
Here is the Interface class, interface method. It's a loop that checks if you made a valid selection and returns your selection. (Here's the bad job by me, the X command is actually handled in the main function. So, that's where the design could be better. Maybe I'll still fix it)
def interface(self):
        
        valid_entry = {"C":"valid","I":"valid", "L":"valid", "V":"valid", "H":"valid", "K":"valid", "F":"valid", "S":"valid", "X":"valid", "M":"valid"}
        while True:
            self.selection = ""
            self.selection = input("Select a command or enter M to see the menu:")
            try:
                valid_entry[self.selection[0]] == "valid"
            except KeyError:
                print("Please make a valid selection, enter M to see menu")
                continue
            if self.selection == "M":
                print(self.command_menu)
            elif self.selection == "X":
                print("Exiting")
                return self.selection
                break
            elif valid_entry[self.selection[0]] == "valid":
                print("valid selction")
                return self.selection
            else:
                print("Please make a valid selection, enter M to see menu")
The main function runs a loop that calls the interface and returns the command to be processed
def execute_main():
    return_command = ""
    image = None
    problem4_interface = Inter.Interface()
    process_drawing = Drawing()
    while return_command != "X":
        return_command = problem4_interface.interface()
        if return_command != "X":
            image = process_drawing.command_router(return_command, image)
        else:
            continue
It took a long time to write all the methods to process all the lists (maybe that's why I've posted this with some problems - haha) Here is the method to fill a region in the Drawing class. It determines what color you select as input and changes all of that color to a the new color.
def fill_region(self, image):
        self.image = image
        if self.image == None:
            print("No image has been created, run command I M N")
        else:
            self.target_color = self.image[int(self.command[2])-1][int(self.command[4])-1]
            print(f"target {self.target_color}")
            for index, num_row in enumerate(self.image):
                for index2, color_val in enumerate(num_row):
                    if color_val == self.target_color:
                        self.image[index][index2] = self.command[6]
                    else:
                        None
            print(self.image)
            return self.image
See the full code on my Github
0 Comments

Python Problem 3

12/29/2022

0 Comments

 

Problem Description

This problem called the LCD Display. The idea is to take a number as an input and output the same number written with vertical and horizontal dashes. So, input looks like this, where the first number is the segment size and the second number is the number to convert:
Picture
The output looks like this, in dashes with each segment being made of two dashes (the first number of the input)
Picture

Solution

This seemed kind of silly but still a couple tricky things to solve.
I couldn't think of a way to just create each digit and stitch the strings together (I don't think there is a way to do that). So, I broke it apart into five parts that could be written as normal strings and added together.
Picture
Then, there's a method for each portion that will decide what blanks or dashes are needed for the current number. For example, here is the build_top() method. If you need a 1 or 4, it's blank, otherwise it's a line.
def build_top(self):
        for i in self.number_to_convert:
            if i == "1" or i == "4":
                self.top_string += " "*(self.segment_size+2)+ " "
            else:
                self.top_string += " " + "-"*self.segment_size + "  "
        return self.top_string
The main function does the following:
  1. Read in the number
  2. Call build_top(), build_upper(), build_middle(), build_lower(), build_bottom()
  3. Concatenate all the strings
  4. Write to a file
Note there is a loop for the upper and lower part as it is made of multiple strings. Here's the code:
def execute_main():
    input_file = fr.FileReader("inputFile.txt")
    raw_input = input_file.file_read_all_str_list()

    #calculate position strings
    exe_problem2 = Problem3(raw_input[0], raw_input[2:])
    top = exe_problem2.build_top()
    
    for i in range(int(raw_input[0])):
        upper = exe_problem2.build_upper()
        upper += "\n"+ upper
                
    middle = exe_problem2.build_middle()

    for i in range(int(raw_input[0])):
        lower = exe_problem2.build_lower()
        lower += "\n" + lower

    bottom = exe_problem2.build_bottom()

    #combine position strings
    output_string = top + "\n" + upper + "\n" + middle + "\n" + lower +"\n" + bottom

    output_file = fw.FileWriter("PyProblem3-Output.txt")
    output_file.file_write_all_str(output_string)
See the full code on my Github
0 Comments

Python Problem 2

12/29/2022

0 Comments

 

Problem Description

This problem is taken from the game Minesweeper on Windows. The input is a static board of mines and blank locations (* and .)

Like this:
Picture
The objective is to create an output file with the same game board only with the blanks replaced with a count of the adjacent count.

Like this:
Picture

Solution

I think the intention of this problem was to solve a 2D array problem. Well, there's not really arrays in Python, so I used a list of lists. (Lists are pretty much arrays)
The tricky thing about this problem was thinking of a way to iterate the list and perform the calculation without writing out of bounds. Here's how I did it:
  1. Read in a string list of lists
  2. Convert the strings to integers to enable the math. So, if there was a period I convert to 0, if there was a * I convert to an 88 as a sentinel value for *. (You can actually mix types in a list in Python, so maybe that was a waste of time)
  3. Then I added a buffer on all sides of the 2D list, such that a 4x4 game board is now 6x6. That way I could iterate through the 2D list and every time I found an 88 call a method to add 1 to every adjacent cell of the table.
  4. Convert the 88s to * and everything to strings in order to write to a file

Couple things, I used list comprehensions to initialize the list of empty lists like this:
self.game_space = [[] for i in range(self.rows)]
Then I could just append to the lists like this and didn't need to know the number of columns of the game board to do it.

This is the more Pythonic way to do this (I think). Adding the index variable and enumerate keyword allows using the lists as iterators in the for loops. You could use nested for loops with counters like i and j along with the range() function. That would look more like C++ but is not the thing. (I guess I could have skipped the elif part, but I like how this reads)
def process_gameboard(self, input_game):
        #convert strings to ints, use 88 as the sentinal for *
        for index, row in enumerate(input_game):
            for char in row:
                if char == "*":
                    self.game_space[index].append(88)
                elif char == ".":
                    self.game_space[index].append(0)
                else:
                    None
See the full code on my Github
0 Comments

Python Problem 1

12/27/2022

0 Comments

 

Problem Description

Python Problem 1 is called the 3n+1 problem. This is an actual famous math/CS problem (search for Collatz conjecture). The objective here is to read in an input that consists of a pair of numbers. The first number is the starting point in a consecutive sequence of integers extending to the ending number. Each number is processed through the 3n+1 algorithm keeping track of the cycle time for each input to cycle to n=1.

Here is the calculation, if the number n is even, divide by 2. If the number is odd, multiply by 3 and add 1.
The result of that is the new n, continue until you get to n=1. Keep track of how many cycles it takes to get to n=1

For example, an input might be 1 10
n=1 and done right away. Cycle time is 1
n=2, 2/2=1. Cycle time is 2
n=3
…
n=10

The desired output is the input plus the longest cycle time.
Input:
1 10
Output:
1 10 20

Solution

This problem is pretty straight forward. I created a class for the problem solution, file input and file output. There is a method that solves the actual 3n+1 calculation from input to n=1 and returns the number of cycles.
The main loop just keeps track of the longest cycle count and formats the output string.

I'm still learning the best way to structure things, but I run with a main function like this:
if __name__ == "__main__":
    execute_main()
They call this "dunder name, dunder main" and it's a way to either run your code from a terminal or import it like a script. (dunder is a way to say double underscore out loud - I guess I'm typing - oh well)

Here is an image of running the code like a script. Note that I added a print statement for this to work, the output is supposed to just go to a file
Picture
Look at that!

Other notes, I'm using VS Code on Linux for development. I also have been setting up a virtual environment for loading packages and keeping my install clean. I only used native Python for this, but it a good practice.

See the full code on my Github
0 Comments

TestStand - Instrument Handle Code

3/25/2016

0 Comments

 
teststand_insthandle.zip
File Size: 47 kb
File Type: zip
Download File

0 Comments

TestStand - Basics 3 Code

3/25/2016

1 Comment

 
teststand_basics3.zip
File Size: 45 kb
File Type: zip
Download File

1 Comment

TestStand - Basics 2 Code

3/25/2016

2 Comments

 
teststand_basics2.zip
File Size: 35 kb
File Type: zip
Download File

2 Comments

Code to create a trace graph display in LabVIEW using an Agilent U2001A power sensor

3/21/2014

1 Comment

 
This is the LabVIEW code to create a trace graph display for an Agilent U2001A power sensor. Here is the write up
agilent_u2000_example_create_trace_graph_display.vi
File Size: 47 kb
File Type: vi
Download File

1 Comment

Labview Project #1: The DOT Test Executive

7/22/2011

0 Comments

 
This is the DOT-TE code as written up
dot-te_v.0.1_lv8.5.zip
File Size: 590 kb
File Type: zip
Download File

0 Comments

    Archives

    December 2022
    March 2016
    March 2014
    July 2011

    Categories

    All
    Python

  • Test Engineering
  • Electrical Engineering
  • Projects and Code
  • Archives
  • About