mirror of
https://github.com/Xevion/contest.git
synced 2025-12-06 09:14:39 -06:00
A+ January 2017: Memory
This commit is contained in:
292
uil/aplus-january-2017/src/Memory.java
Normal file
292
uil/aplus-january-2017/src/Memory.java
Normal file
@@ -0,0 +1,292 @@
|
|||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple tuple class for storing pairs of Cards.
|
||||||
|
*/
|
||||||
|
class CardPair
|
||||||
|
{
|
||||||
|
Card a;
|
||||||
|
Card b;
|
||||||
|
boolean marked = false;
|
||||||
|
|
||||||
|
CardPair(Card a, Card b)
|
||||||
|
{
|
||||||
|
this.a = a;
|
||||||
|
this.b = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean bothVisible()
|
||||||
|
{
|
||||||
|
return a.visible && b.visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Card
|
||||||
|
{
|
||||||
|
public Card other; // Two-way reference to the other card.
|
||||||
|
|
||||||
|
int x; // Column
|
||||||
|
int y; // Row
|
||||||
|
int z; // Depth/Level
|
||||||
|
char value; // The actual a-Z letter of the card.
|
||||||
|
CardPair pair; // Reference to the CardPair containing both
|
||||||
|
boolean visible = false; // Whether or not the Card is considered visible
|
||||||
|
|
||||||
|
Card(char value, int x, int y, int z)
|
||||||
|
{
|
||||||
|
this.value = value;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("Card{%s, x=%d, y=%d, z=%d, %s}", value, x, y, z, visible ? "Visible" : "Not Visible");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Card card = (Card) o;
|
||||||
|
return x == card.x &&
|
||||||
|
y == card.y &&
|
||||||
|
z == card.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return Objects.hash(x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MemoryStructure
|
||||||
|
{
|
||||||
|
private final char[][][] charStructure;
|
||||||
|
private final Card[][][] cardStack;
|
||||||
|
public int width;
|
||||||
|
public int height;
|
||||||
|
public int depth;
|
||||||
|
|
||||||
|
private final HashMap<Character, CardPair> pairs;
|
||||||
|
public final Queue<Card> revealed; // A queue containing all newly
|
||||||
|
|
||||||
|
MemoryStructure(int width, int height, int depth)
|
||||||
|
{
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.depth = depth;
|
||||||
|
|
||||||
|
charStructure = new char[width][height][depth];
|
||||||
|
cardStack = new Card[width][height][depth];
|
||||||
|
|
||||||
|
pairs = new HashMap<>();
|
||||||
|
revealed = new LinkedList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CardPair getPair(char value)
|
||||||
|
{
|
||||||
|
return pairs.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public char getValue(int row, int column, int level)
|
||||||
|
{
|
||||||
|
return this.charStructure[column][row][level];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Card getCard(int row, int column, int level)
|
||||||
|
{
|
||||||
|
return this.cardStack[column][row][level];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param card The card you want to place into the structure.
|
||||||
|
*/
|
||||||
|
public void putCard(Card card)
|
||||||
|
{
|
||||||
|
if (card == null) return;
|
||||||
|
|
||||||
|
this.charStructure[card.x][card.y][card.z] = card.value;
|
||||||
|
this.cardStack[card.x][card.y][card.z] = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param row The row (Y-coordinate)
|
||||||
|
* @param column The column (X-coordinate)
|
||||||
|
* @return The full vertical column of characters from top to bottom of the structure at a specific coordinate.
|
||||||
|
*/
|
||||||
|
public Card[] getVertical(int row, int column)
|
||||||
|
{
|
||||||
|
Card[] vertical = new Card[depth];
|
||||||
|
for (int z = 0; z < depth; z++)
|
||||||
|
vertical[z] = getCard(row, column, z);
|
||||||
|
return vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param row The row (Y-coordinate)
|
||||||
|
* @param column The column (X-coordinate)
|
||||||
|
* @param level The level/depth (Z-coordinate)
|
||||||
|
* @return A list of characters that are above the specific 3d coordinate
|
||||||
|
*/
|
||||||
|
public Card[] getAbove(int row, int column, int level)
|
||||||
|
{
|
||||||
|
Card[] above = new Card[level];
|
||||||
|
for (int z = 0; z < level; z++)
|
||||||
|
above[z] = getCard(row, column, z);
|
||||||
|
return above;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepare the Character/Pair map for use after values are set.
|
||||||
|
*/
|
||||||
|
public void prepareMap()
|
||||||
|
{
|
||||||
|
// Iterate through every position in structure
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
for (int z = 0; z < depth; z++) {
|
||||||
|
Card card = getCard(y, x, z);
|
||||||
|
|
||||||
|
if (pairs.containsKey(card.value)) {
|
||||||
|
// First part of pair has been found, add the other part
|
||||||
|
CardPair pair = pairs.get(card.value);
|
||||||
|
pair.b = card;
|
||||||
|
|
||||||
|
// Setup card references
|
||||||
|
pair.a.other = pair.b;
|
||||||
|
pair.b.other = pair.a;
|
||||||
|
pair.a.pair = pair;
|
||||||
|
pair.b.pair = pair;
|
||||||
|
} else {
|
||||||
|
// Never found before. Create new Pair instance and place first part in.
|
||||||
|
CardPair pair = new CardPair(card, null);
|
||||||
|
pairs.put(card.value, pair);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds all known visible cards by searching top down. Should only be ran once at the beginning (thus only
|
||||||
|
* searching to one depth, but could be used later on to go down to any depth necessary).
|
||||||
|
*/
|
||||||
|
public void setupVisible()
|
||||||
|
{
|
||||||
|
// Iterate only each XY coordinate in the grid
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
// Start moving down in depth until a non-marked card is found.
|
||||||
|
for (int z = 0; z < depth; z++) {
|
||||||
|
Card card = getCard(y, x, z);
|
||||||
|
CardPair cp = getPair(card);
|
||||||
|
|
||||||
|
// If on top of this column's stack
|
||||||
|
if (!cp.marked) {
|
||||||
|
card.visible = true;
|
||||||
|
revealed.add(card);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CardPair getPair(Card card)
|
||||||
|
{
|
||||||
|
return getPair(card.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return String.format("MemoryStructure{width=%d, height=%d, depth=%d}", width, height, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifts a card off the stack by marking the one under a card as visible, and adding that one to the stack.
|
||||||
|
*
|
||||||
|
* @param card The card to 'lift' off the card stack, revealing the card beneath it.
|
||||||
|
*/
|
||||||
|
public void lift(Card card)
|
||||||
|
{
|
||||||
|
// Get the card beneath it
|
||||||
|
int newZ = card.z + 1;
|
||||||
|
|
||||||
|
// If there is going to be a card beneath
|
||||||
|
if (!(newZ > depth - 1)) {
|
||||||
|
Card under = getCard(card.y, card.x, newZ);
|
||||||
|
under.visible = true;
|
||||||
|
revealed.add(under);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Character> values()
|
||||||
|
{
|
||||||
|
return pairs.keySet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Memory
|
||||||
|
{
|
||||||
|
public static void main(String[] args) throws FileNotFoundException
|
||||||
|
{
|
||||||
|
|
||||||
|
Scanner in = new Scanner(new File("memory.dat"));
|
||||||
|
int inputs = in.nextInt();
|
||||||
|
in.nextLine();
|
||||||
|
|
||||||
|
for (int i = 0; i < inputs; i++) {
|
||||||
|
MemoryStructure ms = new MemoryStructure(in.nextInt(), in.nextInt(), in.nextInt());
|
||||||
|
in.nextLine();
|
||||||
|
|
||||||
|
// Read in character inputs
|
||||||
|
for (int z = 0; z < ms.depth; z++) {
|
||||||
|
for (int y = 0; y < ms.height; y++) {
|
||||||
|
String line = in.nextLine();
|
||||||
|
|
||||||
|
for (int x = 0; x < ms.width; x++) {
|
||||||
|
Card card = new Card(line.charAt(x), y, x, z);
|
||||||
|
ms.putCard(card);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ms.prepareMap(); // Form all pairs in map
|
||||||
|
ms.setupVisible(); // Find initially visible cards
|
||||||
|
|
||||||
|
Set<Character> unseen = ms.values();
|
||||||
|
|
||||||
|
// Keep searching and unlocking card pairs
|
||||||
|
while (ms.revealed.size() > 0) {
|
||||||
|
Card next = ms.revealed.poll();
|
||||||
|
|
||||||
|
// Skip Cards that may have been marked by it's sibling while inside the queue
|
||||||
|
if (next.pair.marked)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If both cards in the pair are visible
|
||||||
|
if (next.pair.bothVisible()) {
|
||||||
|
// Mark the pair
|
||||||
|
next.pair.marked = true;
|
||||||
|
|
||||||
|
// Remember that we've seen this character
|
||||||
|
unseen.remove(next.value);
|
||||||
|
|
||||||
|
// Mark cards beneath as visible and add them to the Queue
|
||||||
|
ms.lift(next);
|
||||||
|
ms.lift(next.other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println(unseen.size() == 0 ? "solvable" : "impossible");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user