std::queue<node*> Map::add_all_possible_paths(node *N, Map ©){ std::queue<node*> neighbohrs; std::vector<pos_t> J = N->diamonds; node *par = N; pos_t new_man = N->man; //Don't get children if there is a deadlock bool dead_end = false; for(size_t n=0; n < J.size(); ++n){ if(dead_lock(J.at(n))){ dead_end = true; for(auto g : goals){ if(g == J.at(n)){ dead_end = false; //if a diamond is locked in a goal then it is not a deadlock. } } if(dead_end){ return neighbohrs; //deadlock, no need to see what children might come of this. } } } wave(copy,new_man,J); Map wave_map; /******** If we want to optimize for robot moves ********/ std::vector<std::vector<float>> cost_map; if(optimize_for_robot_moves){ cost_map = find_robot_moves(wave_map, N); } char ans; for(size_t n=0; n < J.size(); ++n){ ans = copy.valid_push(J.at(n)); //gets all the directions a diamond can be pushed if(ans){ new_man = J.at(n); //New position where the man is where the diamond was if(ans & east){ J.at(n) = N->diamonds.at(n) + right; //move diamond node *next = new node(new_man,J,par); //create node if(optimize_for_robot_moves){ next->path_length = N->path_length + wave_map.get(new_man) -3;//based on robot moves in seconds } else { next->path_length = N->path_length + copy.get(new_man-right) - 2; //wavefront approach } J.at(n) = N->diamonds.at(n); //reset diamond neighbohrs.push(next); } if(ans & west){ J.at(n) = N->diamonds.at(n) + left; node *next = new node(new_man,J,par); if(optimize_for_robot_moves){ next->path_length = N->path_length + wave_map.get(new_man) -3; } else { next->path_length = N->path_length + copy.get(new_man-left) - 2; //wavefront approach } J.at(n) = N->diamonds.at(n); neighbohrs.push(next); } if(ans & north){ J.at(n) = N->diamonds.at(n) + above; node *next = new node(new_man,J,par); if(optimize_for_robot_moves){ next->path_length = N->path_length + wave_map.get(new_man) -3; } else { next->path_length = N->path_length + copy.get(new_man-above) - 2; //wavefront approach } J.at(n) = N->diamonds.at(n); neighbohrs.push(next); } if(ans & south){ J.at(n) = N->diamonds.at(n) + below; node *next = new node(new_man,J,par); if(optimize_for_robot_moves){ next->path_length = N->path_length + wave_map.get(new_man) -3; } else { next->path_length = N->path_length + copy.get(new_man-below) - 2; //wavefront approach } J.at(n) = N->diamonds.at(n); neighbohrs.push(next); } } } return neighbohrs; }
/* * osprd_ioctl(inode, filp, cmd, arg) * Called to perform an ioctl on the named file. */ int osprd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { osprd_info_t *d = file2osprd(filp); // device info int r = 0; // return value: initially 0 // is file open for writing? int filp_writable = (filp->f_mode & FMODE_WRITE) != 0; // This line avoids compiler warnings; you may remove it. (void) filp_writable, (void) d; // Set 'r' to the ioctl's return value: 0 on success, negative on error unsigned local_ticket; if (cmd == OSPRDIOCACQUIRE) { // EXERCISE: Lock the ramdisk. // // If *filp is open for writing (filp_writable), then attempt // to write-lock the ramdisk; otherwise attempt to read-lock // the ramdisk. // // This lock request must block using 'd->blockq' until: // 1) no other process holds a write lock; // 2) either the request is for a read lock, or no other process // holds a read lock; and // 3) lock requests should be serviced in order, so no process // that blocked earlier is still blocked waiting for the // lock. // // If a process acquires a lock, mark this fact by setting // 'filp->f_flags |= F_OSPRD_LOCKED'. You also need to // keep track of how many read and write locks are held: // change the 'osprd_info_t' structure to do this. // // Also wake up processes waiting on 'd->blockq' as needed. // // If the lock request would cause a deadlock, return -EDEADLK. // If the lock request blocks and is awoken by a signal, then // return -ERESTARTSYS. // Otherwise, if we can grant the lock request, return 0. // 'd->ticket_head' and 'd->ticket_tail' should help you // service lock requests in order. These implement a ticket // order: 'ticket_tail' is the next ticket, and 'ticket_head' // is the ticket currently being served. You should set a local // variable to 'd->ticket_head' and increment 'd->ticket_head'. // Then, block at least until 'd->ticket_tail == local_ticket'. // (Some of these operations are in a critical section and must // be protected by a spinlock; which ones?) // Your code here (instead of the next two lines). osp_spin_lock(&(d->mutex)); // lock while updating device local_ticket = d->ticket_head; d->ticket_head = d->ticket_head + 1; osp_spin_unlock(&(d->mutex)); for_each_open_file(current, dead_lock(filp, d), d); // lock requests block and is awoken by signal if (wait_event_interruptible( (d->blockq, d->writeLocks == 0) && (local_ticket == d->ticketTail) && (!filp_writable || d->readLocks == 0) ) ) { // sleep until any of the conditions are true if (local_ticket != d->ticket_tail) d->numInterrupt++; else d->ticket_tail++; return -ERESTARTSYS; } // deadlock exists bool deadlock_exists = d->deadlock > 1; bool locked = filp->f_flags & F_OSPRD_LOCKED; if (deadlock_exists && locked) return -EDEADLK; // lock device osp_spin_lock(&(d->mutex)); d->deadlock = 0; filp->f_flags = filp->f_flags | F_OSPRD_LOCKED; if (d->mutex.lock >= 1) r = 0; if (!filp_writable) d->readLocks++; else { d->ticket_tail++; d->writeLocks++; } osp_spin_unlock(&(d->mutex)); // finish using device r = 0; // if (!filp_writable) d->ticket_tail++; } else if (cmd == OSPRDIOCTRYACQUIRE) { // EXERCISE: ATTEMPT to lock the ramdisk. // // This is just like OSPRDIOCACQUIRE, except it should never // block. If OSPRDIOCACQUIRE would block or return deadlock, // OSPRDIOCTRYACQUIRE should return -EBUSY. // Otherwise, if we can grant the lock request, return 0. // Your code here (instead of the next two lines). local_ticket = d->ticket_head; bool lockCheck1 = local_ticket != d->ticket_tail; bool lockCheck2 = (filp_writable && d->readLocks != 0); bool lockCheck3 = d->writeLocks != 0; if (filp->f_flags & F_OSPRD_LOCKED || lockCheck1 || lockCheck2 || lockCheck3) r = -EBUSY; // device is busy, is not open for writing else { osp_spin_lock(&(d->mutex)); // lock device to try reading device filp->f_flags = filp->f_flags | F_OSPRD_LOCKED; d->ticket_head++; if (!filp_writable) d->readLocks++; // if not readable, then try to write to device else d->writeLocks++; if (d->ticket_head > d->ticket_tail) d->ticket_tail++; // get next ticket osp_spin_unlock(&(d->mutex)); wake_up_all(&d->blockq); // wake up all blocked tasks r = 0; } } else if (cmd == OSPRDIOCRELEASE) { // EXERCISE: Unlock the ramdisk. // // If the file hasn't locked the ramdisk, return -EINVAL. // Otherwise, clear the lock from filp->f_flags, wake up // the wait queue, perform any additional accounting steps // you need, and return 0. // Your code here (instead of the next line). if (!(filp->f_flags & F_OSPRD_LOCKED)) r = -EINVAL; // file hasn't locked ramdisk else { osp_spin_lock(&(d->mutex)); d->readLocks = 0; d->writeLocks = 0; r = 0; filp->f_flags = filp->f_flags & ~F_OSPRD_LOCKED; osp_spin_unlock(&(d->mutex)); wake_up_all(&d->blockq); // wake up all blocked tasks } } else r = -ENOTTY; /* unknown command */ return r; }