Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hw4 frank #15

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
73 changes: 73 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework2/hw2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import(
"fmt"
"io/ioutil"
"net/http"
"net/url"
"encoding/json"
)

const NOT_FOUND = "key not found"

type NameReader interface {
Read(source string, key string) string
}

type JSONFetcher map[string]string

func (fetcher JSONFetcher) Read(source string, key string) string {
if val, ok := fetcher.retreive(source, key); ok {
return val
}
data, err := readFromSource(source)
if err != nil {
panic(err)
}
var decoded map[string]interface{}
err = json.Unmarshal(data, &decoded)
if err != nil {
panic(err)
}
value := findByKey(decoded, key)
if (key != NOT_FOUND) {
fetcher.store(source, key, value)
}
return value
}

func (fetcher JSONFetcher) store(source string, key string, value string) {
fetcher[source+key] = value
}

func (fetcher JSONFetcher) retreive(source string, key string) (string, bool) {
val, ok := fetcher[source+key]
return val, ok
}

func readFromSource(source string) ([]byte, error) {
if _, err := url.ParseRequestURI(source); err == nil {
res, err := http.Get(source)
if err != nil {
return nil, err
}
defer res.Body.Close()
return ioutil.ReadAll(res.Body)
} else {
return ioutil.ReadFile(source)
}
}

func findByKey(decoded map[string]interface{}, key string) string {
val, ok := decoded[key]
if !ok {
return NOT_FOUND
}
return val.(string)
}

func main() {
fetcher := make(JSONFetcher)
fmt.Println(fetcher.Read("https://jsonplaceholder.typicode.com/posts/1", "body"))
fmt.Println(fetcher.Read("test.json", "key1"))
}
3 changes: 3 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework2/test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"key1": "value1"
}
76 changes: 76 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework3/machine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package main

import(
"errors"
"strings"
"strconv"
)

// used for identifying different machine objects that represent
// the "same" machine in different states
var nextMachineNum = 0

type Machine struct {
items []int
num int
}

func (m *Machine) push(x int) *Machine {
return MakeMachine(append(m.items, x), m.num)
}

func (m *Machine) peek() (int, error) {
if !m.isEmpty() {
return m.items[len(m.items)-1], nil
} else {
return 0, errors.New("Machine is empty")
}
}

func (m *Machine) pop() (int, *Machine, error) {
if !m.isEmpty() {
top := m.items[len(m.items)-1]
nextItems := m.items[:len(m.items)-1]
return top, MakeMachine(nextItems, m.num), nil
} else {
return 0, nil, errors.New("Machine is empty")
}
}

func (m *Machine) isEmpty() bool {
return len(m.items) == 0
}

func MakeMachine(items []int, num int) *Machine {
tmp := make([]int, len(items))
copy(tmp, items)
m := &Machine{tmp, num}
return m
}

func MakeMachineFromString(s string) *Machine {
itemsStr := strings.Split(s[1:len(s)-1], " ")
items := make([]int, 0)
for i := len(itemsStr)-1; i >= 0; i -= 1 {
item, err := strconv.Atoi(itemsStr[i])
if err != nil {
panic("Malformed machine specification: " + s)
}
items = append(items, item)
}
nextMachineNum += 1
return MakeMachine(items, nextMachineNum)
}

func (m *Machine) String() string {
var sb strings.Builder
sb.WriteString("[")
for i := len(m.items)-1; i >= 0; i -= 1 {
sb.WriteString(strconv.Itoa(m.items[i]))
if (i > 0) {
sb.WriteString(" ")
}
}
sb.WriteString("]")
return sb.String()
}
34 changes: 34 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework3/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package main

import(
"fmt"
"os"
)

func main() {
if len(os.Args) != 3 {
fmt.Println("Please provide machine state and order as arguments")
fmt.Println("For example: \"[1 2]\" \"{1 2}")
os.Exit(1)
}
run(os.Args[1], os.Args[2])
}

func run(state, order string) {
fmt.Printf("Ordering %s from %s\n", order, state)
final, ok := ProcessOrder(MakeOrder(order), MakeState(state))
if ok {
fmt.Printf("Order completed, resulting state: %s\n", final)
} else {
fmt.Println("This order cannot be processed")
}
}

func run_examples() {
run("[1]", "{}")
run("[1 2]", "{1 2}")
run("[1 2]", "{1 2 3}")

run("[1], [1 2], [1 2 3 4], [1 2 3]", "{1 2 3 4}")
run("[2 1 1 1 1 3], [3 1 1 1 1 4 2]", "{1 1 1 1 2 3 4}")
}
57 changes: 57 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework3/order.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package main

import(
"strings"
"strconv"
)

type Order []int

// create an order except one instance of the given item
// if the order has multiple instances, only one will be removed
func (o Order) except(item int) Order {
found := false
result := make([]int, 0)
for _, orderItem := range o {
if !found && item == orderItem {
found = true
continue
}
result = append(result, orderItem)
}
return result
}

func MakeOrder(s string) Order {
items := make([]int, 0)
numbers := strings.TrimSpace(s[1:len(s)-1])
itemsStr := strings.Split(numbers, " ")
if len(numbers) == 0 {
return items
}
for _, itemStr := range itemsStr {
item, err := strconv.Atoi(itemStr)
if err != nil {
panic("Malformed order specification: " + s)
}
items = append(items, item)
}
return items
}

func (o Order) String() string {
var sb strings.Builder
sb.WriteString("{")
for idx, item := range o {
sb.WriteString(strconv.Itoa(item))
if (idx < len(o)-1) {
sb.WriteString(" ")
}
}
sb.WriteString("}")
return sb.String()
}

func (o Order) Equals(other Order) bool {
return strings.Compare(o.String(), other.String()) == 0
}
36 changes: 36 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework3/order_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package main

import(
"testing"
"fmt"
)

func TestExceptRemoves(t *testing.T) {
order := MakeOrder("{1 2 3}")
except := order.except(1)
expected := MakeOrder("{2 3}")
if !expected.Equals(except) {
complain(t, "Did not remove correctly", except, expected)
}
}

func TestExceptNonExistent(t *testing.T) {
order := MakeOrder("{1 2 3}")
except := order.except(5)
if !except.Equals(order) {
complain(t, "Failed when removing non-existent item", except, order)
}
}

func TestExceptEmpty(t *testing.T) {
order := MakeOrder("{}")
except := order.except(1)
if !except.Equals(order) {
complain(t, "Failed to remove from empty order", except, order)
t.Errorf("Failed to remove from empty order")
}
}

func complain(t *testing.T, msg string, expected, result Order) {
t.Errorf(fmt.Sprintf("Error: %s, expected: %s, result: %s", msg, expected, result))
}
90 changes: 90 additions & 0 deletions homeworks/Frank.Teardrop-i-hate-nicknames/homework3/vending.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package main

import(
"strings"
)

type State []*Machine

// Process given order in a given state of vending machines
// if order can be satisfied by this state, return state of the machines
// after processing order and true
// If the order cannot be satisfied return nil and false
// An empty order can be satisfied trivially: by doing nothing and
// keeping current state
func ProcessOrder(order Order, state State) (State, bool) {
if len(order) == 0 {
return state, true
}
// take only first element if items in order should be taken
// sequentially
for _, item := range order {
nextStates := processItem(item, state)
for _, nextState := range nextStates {
result, isSolution := ProcessOrder(order.except(item), nextState)
if isSolution {
return result, true
}
}
}

return nil, false
}

// Process a single order item in given state of vending machines
// Since there can be multiple machines that have this item, return
// states for all possible item retrievals
func processItem(item int, state State) []State {
results := make([]State, 0)
updatedMachines := takeItem(item, state)
for _, updated := range updatedMachines {
results = append(results, replaceMachine(updated, state))
}
return results
}

// Try taking an item from every machine in the state.
// Return every machine that got removed item from the top
// type []*Machine signifies that this is not a state but a collection
// of machines, even though it's the same type
func takeItem(item int, state State) []*Machine {
result := make([]*Machine, 0)
for _, machine := range state {
if top, err := machine.peek(); err == nil && top == item {
_, updated, _ := machine.pop()
result = append(result, updated)
}
}
return result
}

// Find machine in the state with the same number as m
// Return new state with machine in the state replaced
func replaceMachine(replacement *Machine, state State) State {
result := make(State, 0)
for _, machine := range state {
if replacement.num == machine.num {
result = append(result, replacement)
} else {
result = append(result, machine)
}
}
return result
}

func MakeState(s string) State {
machines := make(State, 0)
strs := strings.Split(s, ", ")
for _, machineStr := range strs {
machines = append(machines, MakeMachineFromString(machineStr))
}
return machines
}

func (state State) String() string {
machineStrs := make([]string, 0)
for _, machine := range state {
machineStrs = append(machineStrs, machine.String())
}
return strings.Join(machineStrs, ", ")
}
Loading