Java tutorial
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package ai_coursework; import cm3038.search.ActionStatePair; import cm3038.search.State; import java.util.*; import org.apache.commons.math3.util.Combinations; /** * * @author Liam */ public class HWState implements State { // Instance Variables public ArrayList<Person> northBank; public ArrayList<Person> southBank; public RiverBank raftLocation; /** * Creates a new HWState object that includes the North Bank, South Bank * and Raft Location of the state. * @param nb An Array List of Person Objects on the North Bank * @param sb An Array List of Person Objects on the South Bank * @param rl A RiverBank Type specifying the Raft Location (NORTH or SOUTH) */ public HWState(ArrayList nb, ArrayList sb, RiverBank rl) { northBank = nb; southBank = sb; raftLocation = rl; } @Override public String toString() { String northString = ""; String southString = ""; for (int i = 0; i < northBank.size(); i++) northString += northBank.get(i).name; for (int i = 0; i < southBank.size(); i++) southString += southBank.get(i).name; String result = "North: " + northString; if (raftLocation == RiverBank.NORTH) result += " Raft"; result += "\nSouth: " + southString; if (raftLocation == RiverBank.SOUTH) result += " Raft"; return result; } /** * Compares two HWState Objects checking to see if they are equal to each * other based on the Name of the Person Objects on the north and south * banks and location of the raft. Returns true or false. * @param state An HWState object to be compared * @return A boolean value based on whether a state is equal to another state */ @Override public boolean equals(Object state) { if (!(state instanceof HWState)) return false; HWState hwstate = (HWState) state; return areEqualIgnoringOrder(this.northBank, hwstate.northBank, new NameComparator()) && areEqualIgnoringOrder(this.southBank, hwstate.southBank, new NameComparator()) && this.raftLocation == hwstate.raftLocation; } /** * Compares two Array Lists by sorting both Lists and comparing each object * in the list to the object with the same index in the other List * @param list1 A list of Person Objects to be compared with list2 * @param list2 A list of Person Objects to be compared with list1 * @param comparator A Comparator Object used to compare the lists * @return A boolean value based on whether the Lists are equal or not */ public static <T> boolean areEqualIgnoringOrder(List<Person> list1, List<Person> list2, NameComparator comparator) { // if lists aren't the same size return false. (should never occur) if (list1.size() != list2.size()) return false; // Create a copy of both lists List<Person> copy1 = new ArrayList<>(list1); List<Person> copy2 = new ArrayList<>(list2); // Sort both of the lists Collections.sort(copy1, comparator); Collections.sort(copy2, comparator); // Iterate through both lists comparing each element one by one using // the comparator provided Iterator<Person> it1 = copy1.iterator(); Iterator<Person> it2 = copy2.iterator(); while (it1.hasNext()) { Person t1 = it1.next(); Person t2 = it2.next(); if (comparator.compare(t1, t2) != 0) return false; } return true; } /** * Creates an integer key value based on the size of the north and south * banks and the raft location * @return An integer value used to identify a State */ @Override public int hashCode() { int bank = this.raftLocation == RiverBank.NORTH ? 5 : 10; return northBank.size() * 1000 + southBank.size() * 100 * bank; } /** * Finds all possible and valid successor states from this.state * @return A list of all valid successor states */ @Override public List<ActionStatePair> successor() { List<ActionStatePair> result = new ArrayList<>(); ArrayList<Person> bank = raftLocation == RiverBank.NORTH ? northBank : southBank; if (this.isInvalid()) // If the current state is invalid return result; // Return an emtpy set for (int i = 0; i <= HusbandWives.RAFTSIZE && i <= bank.size(); i++) { Combinations combo = new Combinations(bank.size(), i); Iterator<int[]> iterator = combo.iterator(); while (iterator.hasNext()) { int[] selected = iterator.next(); ArrayList<Person> raft = new ArrayList<>(); for (int index : selected) { raft.add(bank.get(index)); } if (raft.isEmpty()) break; HWAction action = new HWAction(raft, oppositeBank(raftLocation)); HWState nextState = this.applyAction(action); if (!nextState.isInvalid()) result.add(new ActionStatePair(action, nextState)); } } return result; } /** * Checks to see if a state is invalid or not. * State's are invalid if a Wife is on a bank with a Husband that is not * her own. * @return A boolean value based on whether a state is invalid or not */ public boolean isInvalid() { // North Bank Check - // Wife in the presence of another man without her own spouse int husbandCount = 0; for (Person p : northBank) if (p.title == Title.HUSBAND) husbandCount++; for (Person p : northBank) if (p.title == Title.WIFE && !northBank.contains(p.spouse) && husbandCount > 0) return true; // South Bank Check - // Wife in the presence of another man without her own spouse husbandCount = 0; for (Person p : southBank) if (p.title == Title.HUSBAND) husbandCount++; for (Person p : southBank) if (p.title == Title.WIFE && !southBank.contains(p.spouse) && husbandCount > 0) return true; return false; } /** * Takes the Person Objects that are on the raft away from one bank and puts * them on the other bank. Deciding which banks to take from and place to * comes from the toBank variable from the Action Class * @param action The action to be applied to the state * @return A new HWState with the action applied */ public HWState applyAction(HWAction action) { ArrayList<Person> newNorth = new ArrayList<>(this.northBank); ArrayList<Person> newSouth = new ArrayList<>(this.southBank); if (action.toBank == RiverBank.NORTH) { for (int i = 0; i < action.raft.size(); i++) { newSouth.remove(action.raft.get(i)); newNorth.add(action.raft.get(i)); } return new HWState(newNorth, newSouth, RiverBank.NORTH); } for (int i = 0; i < action.raft.size(); i++) { newNorth.remove(action.raft.get(i)); newSouth.add(action.raft.get(i)); } return new HWState(newNorth, newSouth, RiverBank.SOUTH); } private RiverBank oppositeBank(RiverBank current) { if (current == RiverBank.NORTH) return RiverBank.SOUTH; return RiverBank.NORTH; } }